:root {
  --bg: #0f1115;
  --panel: #171a21;
  --panel-2: #1d212a;
  --border: #272c38;
  --text: #e6e9ef;
  --muted: #8d97a8;
  /* The Server Color: identity only, the brand dot and the band across the top. Nothing interactive or stateful uses it. */
  --accent: #d97757;
  /*
   * Role tokens, each checked against the three backgrounds. A primary button
   * and a selected row are neutral; green is healthy; amber is a warning, which
   * includes a limit reached, since that is a hold rather than a failure; red
   * is failure and error alone. Every state colour comes with a glyph and a word.
   */
  --primary-bg: #cee8e9;
  --primary-ink: #132027;
  --primary-hover: #e3f1f1;
  --selected-bg: #1b2730;
  --selected-edge: var(--text);
  --text-2: #c9ced8;
  --meter: #9bc3cb;
  --meter-soft: rgba(155, 195, 203, 0.16);
  /* The run's recommended option: the meter's calm teal, never a pass or a warning colour. */
  --recommend: var(--meter);
  --recommend-edge: rgba(155, 195, 203, 0.45);
  /* The edge of a choice a person can pick, a step up from a panel's border. */
  --option-edge: #343a47;
  /* A computer's two bars: the session lighter, the week deeper, so they differ in lightness and not hue alone. */
  --meter-session: #d6ecee;
  --meter-week: #7fa9b5;
  --track: #252a34;
  /* The hover over a computer's row. */
  --tip-bg: #20242d;
  --tip-border: #343a47;
  --focus: #aad7ed;
  --focus-soft: rgba(170, 215, 237, 0.18);
  --ok: #57ad82;
  --ok-edge: rgba(87, 173, 130, 0.4);
  --live: #74a5ec;
  --live-edge: rgba(116, 165, 236, 0.4);
  --warn: #ffcc66;
  --warn-edge: rgba(255, 204, 102, 0.4);
  --fail: #ff6161;
  --fail-soft: rgba(255, 97, 97, 0.12);
  --fail-edge: rgba(255, 97, 97, 0.4);
  /* The disk banner past 95%: a dark red ground, and light red words that read 4.5:1 on it. */
  --fail-bg: #2a1a1d;
  --fail-ink: #ffd9d9;
  --fail-ink-2: #e9c3c3;
  /* A usage limit that is used up: its bar and its share, softer than a failure, the one state a meter colours. */
  --used-up: #e06666;
  /* Decoration that is not a state: project folders, a run's retrospective, a tool call. */
  --quiet: #9283a8;
  /* The tint and the edge of a row with news. */
  --unread-tint: rgba(231, 227, 222, 0.05);
  /* Borders a control is recognised by, at least 3:1 against the header bar. */
  --control-border: #646d80;
  --radius: 10px;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

a {
  color: inherit;
  text-decoration: none;
}

/*
 * The app shell: the header across the top, the sidebar down the left and the
 * page beside it. The sidebar is a column 264px wide until dragged wider or
 * narrower on its right edge, and a drawer off the left edge below 1024px.
 */
:root {
  --topbar-h: 52px;
  /* app.js and the head of index.html set --sidebar-pick from the width this browser keeps. */
  --sidebar-w: clamp(220px, var(--sidebar-pick, 264px), 480px);
}

.shell {
  display: grid;
  grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
  grid-template-rows: auto auto minmax(0, 1fr);
  min-height: 100vh;
}

/* Keyboard users land on it first; it is off screen until focused. */
.skip-link {
  position: absolute;
  top: -100px;
  left: 12px;
  z-index: 60;
  padding: 8px 14px;
  border-radius: 8px;
  background: var(--primary-bg);
  color: var(--primary-ink);
  font-weight: 600;
}

.skip-link:focus {
  top: 8px;
  outline: 2px solid var(--text);
  outline-offset: 2px;
}

/* The header: the menu button on a phone, the brand, and the bell. */
.topbar {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 12px;
  min-height: var(--topbar-h);
  padding: 8px 16px;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
  position: sticky;
  top: 0;
  z-index: 5;
  /* The server's color across the top, so which server this is shows before anything is read. */
  box-shadow: inset 0 3px 0 var(--accent);
}

/* The sidebar button's two icons: the rail's beside the page, the drawer's below 1024px. */
.topbar .btn.menu .ico-drawer {
  display: none;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  font-weight: 600;
  letter-spacing: 0.2px;
  overflow-wrap: anywhere;
}

.brand .dot {
  flex: none;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--accent);
}

.topbar-right {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-left: auto;
}

/* An update on offer: a dot on the Settings button's corner, as the bell's marks sit on its. */
.btn.settings {
  position: relative;
  overflow: visible;
}

/* Left of the clock while a Codex full reset is about to be lost: what and how soon, on one line. */
.reset-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  padding: 0 10px;
  border: 1px solid var(--tip-border);
  border-radius: 999px;
  background: var(--panel-2);
  color: var(--text);
  font-size: 12px;
  text-decoration: none;
  white-space: nowrap;
}

.reset-badge:hover {
  border-color: var(--control-border);
}

.reset-badge:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.reset-badge[hidden] {
  display: none;
}

.reset-badge .glyph {
  display: inline-flex;
  margin: 0;
  color: var(--primary-bg);
}

/* Under 36 hours: solid amber, dark words on it. */
.reset-badge.urgent {
  border-color: var(--warn);
  background: var(--warn);
  color: var(--primary-ink);
  font-weight: 600;
}

.reset-badge.urgent:hover {
  border-color: var(--warn);
}

.reset-badge.urgent .glyph {
  color: var(--primary-ink);
}

.update-dot {
  position: absolute;
  top: -4px;
  right: -4px;
  width: 9px;
  height: 9px;
  border: 2px solid var(--panel);
  border-radius: 50%;
  background: var(--primary-bg);
}

.update-dot[hidden] {
  display: none;
}

/*
 * Usage beside the name, when Settings puts the meters in the header: one
 * small meter per limit of each account, its short name and the share used
 * over a thin bar, as the header drew them before the sidebar. A limit near or
 * reached is amber with a glyph and, for a screen reader, the word, so the
 * colour never says it alone; a reading that could not be refreshed is dimmed.
 * Accounts are told apart by a rule and a name only when there are two. Gone
 * below 1024px, where the drawer's bars and the phone's strip carry the same.
 */
.header-meters {
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: 0;
  margin-left: 8px;
  overflow: hidden;
}

.header-meters[hidden] {
  display: none;
}

.hm-account {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: none;
}

.hm-meter {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 64px;
  cursor: help;
}

.hm-meter.stale {
  opacity: 0.6;
}

.hm-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 6px;
  color: var(--muted);
  font-size: 10.5px;
  line-height: 1;
  white-space: nowrap;
}

.hm-pct {
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.hm-pct .glyph {
  margin-right: 3px;
  font-size: 9px;
}

/* The shared meter, thinner and on the header's own track. */
.hm-meter .lim-meter {
  height: 4px;
  background: var(--track);
}

.hm-meter.near .hm-pct,
.hm-meter.reached .hm-pct {
  color: var(--warn);
}

.hm-meter.near .lim-fill,
.hm-meter.reached .lim-fill {
  background: var(--warn);
}

/*
 * The one-line availability strip, on a phone only: the best account's
 * tightest limit and the alert word, so the display stays in view with the
 * sidebar closed. Border and glyph carry the severity along with the colour.
 */
.status-strip {
  display: none;
  flex: 1 1 100%;
  align-items: center;
  gap: 8px;
  min-height: 36px;
  padding: 4px 10px;
  border: 1px solid var(--control-border);
  border-radius: 8px;
  color: var(--text);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
}

.status-strip.warning {
  border-color: var(--control-border);
}

.status-strip.critical {
  border-color: var(--control-border);
}

.status-strip .glyph {
  margin: 0;
  font-size: 11px;
}

.status-strip.ok .glyph {
  color: var(--ok);
}

.status-strip.warning .glyph,
.status-strip.warning .strip-text {
  color: var(--warn);
}

.status-strip.critical .glyph,
.status-strip.critical .strip-text {
  color: var(--fail);
}

.status-strip .strip-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
}

.status-strip .side-more {
  color: var(--muted);
  font-weight: 400;
}

/*
 * The sidebar: a column that stays put while the page scrolls. The navigation
 * at the top scrolls on its own when the column is short; the status block
 * stays pinned at the bottom.
 */
.sidebar {
  grid-column: 1;
  grid-row: 3;
  position: sticky;
  top: calc(var(--header-h, var(--topbar-h)) + var(--banner-h, 0px));
  display: flex;
  flex-direction: column;
  height: calc(100vh - var(--header-h, var(--topbar-h)) - var(--banner-h, 0px));
  overflow: hidden;
  padding: 12px 10px 12px;
  border-right: 1px solid var(--border);
  background: var(--panel);
}

/*
 * The sidebar's right edge: dragged, or its arrow keys pressed, to make the
 * sidebar wider or narrower, and double-clicked for the usual 264px. A line
 * shows on it while hovered, focused or dragged. Neither the rail nor the
 * drawer below 1024px has one.
 */
.side-resize {
  display: none;
}

@media (min-width: 1024px) {
  .side-resize {
    display: block;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 1;
    width: 8px;
    cursor: col-resize;
    touch-action: none;
  }
  .side-resize::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 2px;
    transition: background-color 120ms ease;
  }
  .side-resize:hover::after,
  html.resizing .side-resize::after {
    background: var(--control-border);
  }
  /* The line is its focus ring: an outline round an 8px strip the height of the window reads as a box. */
  .side-resize:focus-visible {
    outline: none;
  }
  .side-resize:focus-visible::after {
    width: 3px;
    background: var(--focus);
  }
  html.rail .side-resize {
    display: none;
  }
}

/* While dragging, the resize arrows wherever the pointer goes, and no text selected on the way. */
html.resizing,
html.resizing * {
  cursor: col-resize !important;
  user-select: none;
}

/* Only the drawer has a close button, so the head is empty on a desktop. */
.sidebar-head {
  display: none;
  justify-content: flex-end;
}

.side-nav {
  display: flex;
  flex-direction: column;
  gap: 14px;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
}

.side-group {
  min-width: 0;
}

.side-title {
  margin: 0 0 4px;
  padding: 0 8px;
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.side-list {
  display: grid;
  /* As wide as the sidebar and no wider, so a long name shortens in its row rather than pushing what follows it out of view. */
  grid-template-columns: minmax(0, 1fr);
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* `display: grid` above outranks the hidden attribute, which is how "No projects yet" once showed with the list folded. */
.side-list[hidden] {
  display: none;
}

/* A section heading with a control or a count at its end: Projects and its +, Status and how many computers are open. */
.side-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 4px;
  padding-right: 2px;
}

.side-title-row .side-title {
  margin: 0;
}

.side-head-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: 7px;
  background: none;
  color: var(--muted);
  cursor: pointer;
}

.side-head-btn:hover,
.side-head-btn[aria-expanded='true'] {
  background: var(--selected-bg);
  color: var(--text);
}

.side-head-btn:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
}

/*
 * One item: an icon, a label and whatever marks it carries, as a link or a
 * button. The current page is a soft fill and a heavier label, never a colour
 * on its own.
 */
.side-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 34px;
  padding: 5px 8px;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: 13px;
  line-height: 1.35;
  text-align: left;
  cursor: pointer;
}

.side-item:hover {
  background: var(--panel-2);
}

.side-item[aria-current='page'] {
  background: var(--selected-bg);
  font-weight: 600;
}

.side-item:focus-visible,
.side-rail-status:focus-visible,
.topbar .menu:focus-visible,
.status-page a:focus-visible,
.status-page .btn:focus-visible,
.status-page [tabindex='-1']:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.side-item:focus-visible {
  outline-offset: -2px;
}

.side-icon {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  color: var(--muted);
  font-size: 14px;
}

.side-icon svg {
  display: block;
}

.side-item[aria-current='page'] .side-icon {
  color: var(--text);
}

/* A project's folder is decoration, not a state. */
[data-route^='project:'] .side-icon {
  color: var(--quiet);
}

/* A node's online glyph is a filled dot, offline a hollow one, each with its word beside it. */
.side-icon.online {
  color: var(--ok);
}

.side-icon.offline {
  color: var(--fail);
}

/* A run waiting for values: amber, with "waiting" beside it. */
.side-icon.values {
  color: var(--warn);
}

.side-text {
  flex: 1 1 auto;
  min-width: 0;
  display: grid;
  gap: 1px;
}

.side-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The second line of an item: which node, how long, how busy. */
.side-sub {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--muted);
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.side-sub .lim-meter {
  flex: 1 1 36px;
  max-width: 64px;
  height: 4px;
}

/* "any": a job that runs on any computer with room, before the computer it will start on. */
.side-any {
  flex: none;
  padding: 0 4px;
  border: 1px solid var(--control-border);
  border-radius: 4px;
  color: var(--text-2);
  font-size: 10px;
  letter-spacing: 0.06em;
  line-height: 14px;
  text-transform: uppercase;
}

.side-where {
  color: var(--text-2);
}

/* A section's own link at the end of its heading, such as Waiting's Queue. */
.side-head-link {
  padding: 3px 6px;
  border-radius: 6px;
  color: var(--text-2);
  font-size: 12px;
}

/* The rest of a list past what the sidebar has room for, under the icons' column. */
.side-more-link {
  display: block;
  padding: 2px 8px 4px 38px;
  border-radius: 6px;
  color: var(--text-2);
  font-size: 12px;
}

.side-head-link:hover,
.side-more-link:hover {
  color: var(--text);
  text-decoration: underline;
}

.side-head-link:focus-visible,
.side-more-link:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
}

/* How many of a kind are updated, as the tabs count them. */
.side-count {
  flex: none;
  min-width: 18px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--primary-bg);
  color: var(--primary-ink);
  font-size: 11px;
  font-weight: 600;
  line-height: 18px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.side-count.quiet {
  background: var(--panel-2);
  color: var(--muted);
}

/* A plugin's count on its Hub link, in the project color it asked for. */
.side-count.plugin-badge[data-color] {
  background: var(--project);
  color: #16181d;
}

.side-count.side-dot {
  min-width: 0;
  width: 7px;
  height: 7px;
  margin-left: auto;
  padding: 0;
  border-radius: 50%;
  background: var(--primary-bg);
}

.side-count[hidden] {
  display: none;
}

/* The marks beside a job: a run under way, and on Settings an update on offer. */
.side-mark {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 10px;
  font-size: 11px;
  line-height: 1;
}

.side-mark.running {
  color: var(--live);
}

.side-mark.update::before {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--primary-bg);
}

.side-mark[hidden] {
  display: none;
}

/* Projects: its heading and +, the New project form, then the projects once there are any. */
.side-projects {
  margin-top: 2px;
}

/* A project's row: the chevron that folds its jobs, then the project, with its + over the end; its jobs sit under it, started in from under the chevron. */
.side-project-row {
  position: relative;
  display: flex;
  align-items: center;
}

/* Shrinks to the row beside the chevron, so a long name shortens rather than pushing the job count past the sidebar's edge. */
.side-project-row > .side-item {
  min-width: 0;
}

.side-fold {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  min-height: 34px;
  padding: 0;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--muted);
}

button.side-fold {
  cursor: pointer;
}

button.side-fold:hover {
  background: var(--panel-2);
  color: var(--text);
}

button.side-fold:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: -2px;
}

.side-fold svg {
  display: block;
}

.side-fold[aria-expanded='true'] svg {
  transform: rotate(90deg);
}

.side-jobs {
  padding-left: 40px;
}

/* A subproject's chevron sits under its parent's icon, a step in from the parent's own. */
.side-subprojects {
  padding-left: 18px;
}

.side-jobs .side-icon {
  color: var(--quiet);
}

.side-jobs .side-item[aria-current='page'] .side-icon {
  color: var(--text);
}

/*
 * A project's +, which opens the menu that adds a job to it. It sits over
 * the job count and takes its place while the row is hovered, holds focus
 * or has its menu open, so a row at rest reads as a count; where nothing
 * hovers it is always there, in the row beside the count.
 */
.side-new-job {
  position: absolute;
  top: 50%;
  right: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 0;
  border-radius: 7px;
  background: none;
  color: var(--muted);
  cursor: pointer;
  transform: translateY(-50%);
  opacity: 0;
  pointer-events: none;
}

.side-new-job svg {
  display: block;
}

.side-project-row:hover .side-new-job,
.side-project-row:focus-within .side-new-job,
.side-new-job[aria-expanded='true'] {
  opacity: 1;
  pointer-events: auto;
}

.side-project-row:hover .side-count,
.side-project-row:focus-within .side-count,
.side-project-row:has(> .side-new-job[aria-expanded='true']) .side-count {
  visibility: hidden;
}

.side-new-job:hover,
.side-new-job[aria-expanded='true'] {
  background: var(--selected-bg);
  color: var(--text);
}

.side-new-job:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
}

@media (hover: none) {
  .side-new-job {
    position: static;
    flex: none;
    transform: none;
    opacity: 1;
    pointer-events: auto;
  }
  .side-project-row:hover .side-count,
  .side-project-row:focus-within .side-count,
  .side-project-row:has(> .side-new-job[aria-expanded='true']) .side-count {
    visibility: visible;
  }
}

/* The Jobs heading folds its pages away: the heading is the button, with the chevron a project's fold uses. */
.side-title-fold {
  padding: 0;
}

.side-title-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 28px;
  padding: 0 8px;
  border: 0;
  border-radius: 7px;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
}

.side-title-btn:hover {
  background: var(--panel-2);
  color: var(--text);
}

.side-title-btn:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
}

.side-title-btn svg {
  display: block;
}

.side-title-btn[aria-expanded='true'] svg {
  transform: rotate(90deg);
}

.side-title-btn .side-dot {
  margin-left: 2px;
}

.side-jobs-group.folded > .side-list {
  display: none;
}



.side-projects .side-list,
.side-add {
  margin-top: 2px;
}

.side-add[hidden] {
  display: none;
}

/* The form that adds a project, under the list, with its label shown and its error beside the field. */
.side-new {
  display: grid;
  gap: 6px;
  margin: 4px 0 2px;
  padding: 8px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel-2);
}

.side-new label {
  font-size: 12px;
  color: var(--muted);
}

.side-new input {
  width: 100%;
  min-height: 32px;
  padding: 5px 8px;
  border: 1px solid var(--control-border);
  border-radius: 6px;
  background: var(--bg);
  color: var(--text);
  font: inherit;
  font-size: 13px;
}

.side-new input:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
}

.side-new .row-actions {
  display: flex;
  gap: 6px;
}

.side-new .error {
  padding: 6px 8px;
  font-size: 12px;
}

.side-new .error[hidden] {
  display: none;
}

/*
 * The status block, pinned to the bottom: the heading onto the System status
 * page, one line for the worst current issue, and one row per computer with
 * its account's meters. Glyph, word and colour say each state together.
 */
.side-status {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 60%;
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
  overflow-y: auto;
  overflow-x: hidden;
}

.side-status .side-title {
  margin: 0;
}

.side-provider {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--muted);
  font-size: 12px;
}

.side-provider .select {
  flex: none;
  width: 96px;
  min-width: 0;
  margin-left: auto;
  min-height: 36px;
  padding: 5px 8px;
  border-color: var(--control-border);
  background: transparent;
  font-size: 12px;
}

.side-status-link {
  display: inline-block;
  padding: 2px 0;
  border-radius: 4px;
  color: inherit;
}

.side-status-link:hover,
.side-status-link[aria-current='page'] {
  color: var(--text);
}

.side-status-link[aria-current='page'] {
  text-decoration: underline;
  text-decoration-color: var(--selected-edge);
  text-underline-offset: 3px;
}

/* The one line: the glyph, the severity word for a screen reader, the issue, then "+2 more". */
.side-alert {
  display: flex;
  align-items: flex-start;
  gap: 7px;
  margin: 0 0 2px;
  padding: 7px 8px;
  border: 1px solid var(--control-border);
  border-radius: 8px;
  color: var(--ok);
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.4;
  overflow-wrap: anywhere;
}

.side-alert[hidden] {
  display: none;
}

.side-alert:hover,
.side-rail-status:hover {
  background: var(--panel-2);
}

.side-alert.warning,
.side-rail-status.warning {
  border-color: var(--control-border);
  color: var(--warn);
}

.side-alert.critical,
.side-rail-status.critical {
  border-color: var(--control-border);
  color: var(--fail);
}

.side-alert .glyph {
  flex: none;
  margin: 0;
  font-size: 11px;
  line-height: 1.6;
}

.side-alert .side-more {
  color: var(--muted);
  font-weight: 400;
  white-space: nowrap;
}

/*
 * The computers, the hub's own first and the rest A to Z. As bars, each row is
 * the name, how busy it is and its state, over two thin bars: the session,
 * then the week. A used-up limit keeps its colour and fills its bar; the row's
 * "back Sat 7 PM" says the rest. Offline is the one state in the failure colour.
 */
.side-nodes {
  display: grid;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.side-nodes.rings {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px 2px;
}

.sn-link {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 6px 8px;
  border-radius: 8px;
  color: var(--text);
}

.sn-link:hover {
  background: var(--panel-2);
}

.sn-link:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: -2px;
}

/* A narrow sidebar drops the reset times under the name rather than cutting the name short. */
.sn-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 8px;
  min-width: 0;
}

.sn-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
  font-weight: 600;
}

/* The account to use first: an hourglass after the name, in the button colour. The hover says why. */
.sn-use {
  display: inline-flex;
  flex: none;
  align-self: center;
  color: var(--primary-bg);
}

.sn-cell .sn-use {
  margin-left: 4px;
  vertical-align: -1px;
}

.sn-state {
  flex: none;
  margin-left: auto;
  color: var(--text);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.sn-row.held .sn-state {
  color: var(--text-2);
}

.sn-row.offline .sn-name,
.sn-cell.offline .sn-name {
  color: var(--muted);
}

.sn-row.offline .sn-state,
.sn-cell.offline .sn-ring.empty {
  color: var(--fail);
}

.sn-bars {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.sn-bar {
  display: block;
  height: 4px;
  border-radius: 2px;
  background: var(--track);
  overflow: hidden;
}

.sn-bar i {
  display: block;
  height: 100%;
  border-radius: 2px;
}

.sn-bar .session,
.sn-keys .session {
  background: var(--meter-session);
}

.sn-bar .week,
.sn-keys .week {
  background: var(--meter-week);
}

/* Amber from 80% used, as the node and account meters are, and soft red once used up. */
.sn-bar .high {
  background: var(--warn);
}

.sn-bar .used-up {
  background: var(--used-up);
}

/* Every limit's share under the bars, so a computer held by a limit with no bar of its own says which. */
.sn-pcts {
  display: flex;
  flex-wrap: wrap;
  gap: 0 4px;
  color: var(--muted);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.sn-pcts .high {
  color: var(--warn);
}

.sn-pcts .used-up {
  color: var(--used-up);
}

.sn-meta {
  color: var(--muted);
  font-size: 11.5px;
  overflow-wrap: anywhere;
}

/* The key on the left, the hub's build on the right, then a waiting build on a line of its own. */
.side-foot {
  display: flex;
  align-items: center;
  gap: 8px;
}

.side-build {
  margin-left: auto;
  padding: 2px 8px 0;
  color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  text-decoration: none;
  white-space: nowrap;
}

.side-update {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 2px 8px 0;
  color: var(--text-2);
  font-size: 11px;
  text-decoration: none;
  white-space: nowrap;
}

.side-update .mono {
  font-size: 11px;
}

.side-build:hover,
.side-update:hover {
  color: var(--text);
  text-decoration: underline;
}

.side-build:focus-visible,
.side-update:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
  border-radius: 4px;
}

.side-build[hidden],
.side-update[hidden] {
  display: none;
}

.side-update-dot {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--primary-bg);
}

/* Which bar is which, said once under the computers. */
.sn-keys {
  display: flex;
  gap: 12px;
  padding: 2px 8px 0;
  color: var(--muted);
  font-size: 11px;
}

.sn-keys[hidden] {
  display: none;
}

.sn-keys .key {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

.sn-keys i {
  display: inline-block;
  width: 12px;
  height: 4px;
  border-radius: 2px;
}

/* As rings, three to a row: the week outside, the session inside, the share used or when it is back in the middle. */
.sn-cell .sn-link {
  align-items: center;
  gap: 2px;
  padding: 6px 2px;
  text-align: center;
}

.sn-ring {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
}

.sn-ring svg {
  display: block;
}

.sn-ring .ring-num {
  fill: var(--text);
  font-size: 13px;
  font-weight: 600;
}

.sn-ring .ring-word {
  fill: var(--text-2);
  font-size: 11px;
}

.sn-ring.empty {
  color: var(--muted);
  font-size: 12px;
}

.sn-cell .sn-name {
  max-width: 100%;
  margin-top: 2px;
  font-size: 12.5px;
}

.sn-cell .sn-state {
  margin: 0;
  color: var(--muted);
  font-size: 11px;
  white-space: normal;
}

/* Under a ring, the session reset over the week's, each on its own line. */
.sn-cell .sn-time {
  display: block;
}

/* The hover: each limit as a computer's row is drawn, its name and the share used over a bar, when it resets beneath. */
.sn-tip {
  position: fixed;
  z-index: 70;
  display: grid;
  gap: 10px;
  width: 264px;
  padding: 12px 14px;
  border: 1px solid var(--tip-border);
  border-radius: 10px;
  background: var(--tip-bg);
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.5);
  color: var(--text);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  max-height: calc(100vh - 16px);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.sn-tip[hidden] {
  display: none;
}

.tip-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}

.tip-head b {
  font-size: 13px;
}

.tip-why {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  line-height: 1.35;
}

.tip-why .glyph {
  flex: none;
  margin-top: 2px;
  color: var(--primary-bg);
}

.tip-head span {
  color: var(--text-2);
}

.tip-head-end {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.tip-gear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  margin: -4px -6px -4px 0;
  border-radius: 6px;
  color: var(--text-2);
}

.tip-gear:hover {
  background: var(--tip-border);
  color: var(--text);
}

.tip-lim {
  display: grid;
  gap: 5px;
}

.tip-lim-head {
  display: flex;
  justify-content: space-between;
  gap: 8px;
}

.tip-lim .sn-bar {
  height: 5px;
}

.tip-reset {
  color: var(--muted);
  font-size: 11px;
}

.tip-notes {
  display: grid;
  gap: 3px;
  padding-top: 8px;
  border-top: 1px solid var(--tip-border);
  color: var(--muted);
  font-size: 11px;
}

/*
 * The banner under the header for a disk past 90% full: a warning glyph and
 * plain words, which turn red on a red ground past 95%. It stays under the
 * header while the page scrolls; the sidebar sits below both.
 */
.disk-banner {
  grid-column: 1 / -1;
  grid-row: 2;
  position: sticky;
  top: var(--header-h, var(--topbar-h));
  z-index: 4;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 12px;
  min-height: 40px;
  padding: 4px 12px 4px 18px;
  border-bottom: 1px solid var(--border);
  background: var(--panel-2);
  font-size: 13px;
}

.disk-banner[hidden] {
  display: none;
}

.banner-glyph {
  display: inline-flex;
  flex: none;
  color: var(--warn);
}

.banner-text b {
  font-weight: 600;
}

.banner-why,
.banner-more {
  color: var(--muted);
}

.banner-link {
  color: var(--focus);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.banner-close {
  margin-left: auto;
}

.banner-link:focus-visible,
.banner-more:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: 3px;
}

.disk-banner.critical {
  border-bottom-color: var(--fail-edge);
  background: var(--fail-bg);
}

.disk-banner.critical .banner-glyph {
  color: var(--fail);
}

.disk-banner.critical .banner-text b,
.disk-banner.critical .banner-link {
  color: var(--fail-ink);
}

.disk-banner.critical .banner-why,
.disk-banner.critical .banner-more {
  color: var(--fail-ink-2);
}

/* One limit on its own line: the name, the percentage used, a meter, and when it resets. Also the job form's Node field. */
.avail-limits {
  display: grid;
  gap: 7px;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
}

.avail-lim {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 3px 8px;
  align-items: baseline;
  font-size: 12px;
}

.avail-lim .lim-meter {
  grid-column: 1 / -1;
  height: 5px;
}

.avail-lim .lim-reset {
  grid-column: 1 / -1;
  font-size: 11.5px;
}



.hdr-icon {
  display: inline-flex;
  flex: none;
}

.hdr-icon svg {
  display: block;
}

.num {
  font-variant-numeric: tabular-nums;
}

.glyph {
  margin-right: 4px;
  font-size: 0.8em;
}

/* Read by a screen reader, not drawn. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/*
 * The System status page: jobs, Codex accounts, Claude accounts, computers
 * and the page's own updates, in that order. Each section is reachable by its own address,
 * so the sidebar's alert line can land on the one that explains it.
 */
.status-page {
  container: status / inline-size;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0 18px 6px;
}

.status-page a.link {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--control-border);
  text-underline-offset: 3px;
}

.status-page a.link:hover {
  text-decoration-color: currentColor;
}

.status-word.attention {
  color: var(--warn);
}

.status-word.clear {
  color: var(--ok);
}

/* A section scrolled to from the sidebar clears the sticky header. */
.sp-section h3 {
  scroll-margin-top: calc(var(--topbar-h) + 16px);
}

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

.sp-section:first-child {
  border-top: none;
}

.sp-section h3 {
  margin: 0 0 8px;
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.sp-section h4 {
  margin: 12px 0 6px;
  font-size: 13px;
}

.sp-lead {
  margin: 0;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}

.sp-list {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
  font-size: 13px;
}

/* A job may be named with 120 characters and no space; it wraps rather than pushing the panel wide. */
.sp-item,
.acct-meta,
.sp-lead {
  overflow-wrap: anywhere;
}

.sp-item.warning {
  color: var(--warn);
}

.sp-item.offline {
  color: var(--fail);
}

.sp-item.critical {
  color: var(--fail);
}

.sp-item.muted {
  color: var(--muted);
}

/* A waiting job on System status: its icon, where it starts and why, and its two actions at the end. */
.sp-wait {
  display: grid;
  grid-template-columns: 16px minmax(0, 1fr) auto;
  gap: 4px 10px;
  align-items: start;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}

.sp-wait-icon {
  display: inline-flex;
  margin-top: 2px;
  color: var(--muted);
}

.sp-wait-text {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.sp-wait-where {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 6px;
  color: var(--text-2);
}

.sp-wait-actions {
  display: flex;
  gap: 6px;
}

@media (max-width: 640px) {
  .sp-wait {
    grid-template-columns: 16px minmax(0, 1fr);
  }

  .sp-wait-actions {
    grid-column: 2;
  }
}

.sp-item .hdr-icon {
  display: inline-flex;
  margin-right: 6px;
  vertical-align: -2px;
}

.sp-why,
.sp-meta,
.acct-meta {
  color: var(--muted);
  font-size: 12.5px;
}

.sp-meta {
  margin: 8px 0 0;
}

.sp-links {
  margin: 10px 0 0;
  font-size: 13px;
}

.sp-note {
  margin: 12px 0 0;
  color: var(--muted);
  font-size: 12px;
}

/* Both agents' unused resets, first on System status: the close ones listed, the rest folded. */
.reset-lead .glyph {
  display: inline-flex;
  margin-right: 6px;
  vertical-align: -1px;
  color: var(--warn);
}

.reset-list {
  margin: 12px 0 0;
  padding: 0;
  list-style: none;
}

.reset-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(110px, auto) minmax(180px, 1fr);
  align-items: center;
  gap: 8px 20px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}

.reset-account,
.reset-time {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  overflow-wrap: anywhere;
}

.reset-window,
.reset-time time {
  color: var(--muted);
  font-size: 12.5px;
}

/* The agent's tag, ahead of the reset's name. */
.reset-window .side-any {
  margin-right: 6px;
}

.reset-left,
.reset-time {
  font-variant-numeric: tabular-nums;
}

.reset-left {
  text-align: right;
}

/* A reset within 4 days of being lost: tinted, in full-strength words, with an amber chip. Never a failure colour. */
.reset-row.soon {
  margin: 0 -10px;
  padding: 12px 10px;
  border-bottom-color: transparent;
  border-radius: 8px;
  background: var(--meter-soft);
}

.reset-row.soon + .reset-row.soon {
  margin-top: 4px;
}

.reset-row.soon .reset-time > span {
  font-size: 15px;
  font-weight: 600;
}

.reset-row.soon .reset-time time {
  color: var(--text-2);
}

.reset-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 10px;
  border: 1px solid var(--warn-edge);
  border-radius: 999px;
  color: var(--warn);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

.reset-chip .glyph {
  display: inline-flex;
}

/* Under 36 hours the chip is solid amber, dark words on it, as the header badge turns. */
.reset-row.urgent .reset-chip {
  border-color: var(--warn);
  background: var(--warn);
  color: var(--primary-ink);
}

.reset-later {
  margin-top: 10px;
  font-size: 13px;
}

.reset-later summary {
  padding: 6px 0;
  color: var(--text-2);
  cursor: pointer;
}

.reset-later .reset-list {
  margin-top: 4px;
}

/* One account: who it is and how it stands on the left, each limit on its own line on the right. */
.acct {
  display: grid;
  grid-template-columns: minmax(170px, 210px) minmax(0, 1fr);
  gap: 6px 20px;
  padding: 12px 0;
  border-top: 1px dashed var(--border);
}

.acct:first-of-type {
  border-top: none;
  padding-top: 2px;
}

.acct-who {
  min-width: 0;
}

/* Breaks after the @ when it has to, so the address keeps its two halves. */
.acct-email {
  margin: 0;
  font-size: 13.5px;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.acct-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  font-size: 12.5px;
  font-weight: 600;
}

.acct-status.reached {
  color: var(--text);
}

.acct-status.near {
  color: var(--text);
}

.acct-status.ok {
  color: var(--ok);
}

.acct-status.unknown {
  color: var(--muted);
}

.acct-detail {
  min-width: 0;
}

.acct-limits {
  display: grid;
  /* Fixed columns, so each account's limits line up with the next one's. */
  grid-template-columns: 10em 4.8em 5.4em 56px minmax(0, 1fr);
  align-items: center;
  gap: 6px 12px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 13px;
}

.lim {
  display: contents;
}

.lim-name {
  overflow-wrap: anywhere;
}

.lim-flag {
  padding: 0 5px;
  border: 1px solid currentColor;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 600;
}

.lim-pct {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.lim-meter {
  display: block;
  height: 6px;
  border-radius: 999px;
  background: var(--border);
  overflow: hidden;
}

.lim-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--meter);
}

/* Amber from 80% used, and once used up the red the sidebar's bars turn. */
.lim-fill.high {
  background: var(--warn);
}

.lim-fill.used-up {
  background: var(--used-up);
}



.lim-reset {
  color: var(--muted);
  font-size: 12.5px;
}

.acct-meta {
  margin: 8px 0 0;
}

.acct-meta.stale {
  color: var(--muted);
}

/* The Settings page's Nodes card, scrolled to from the status page, clears the sticky header. */
[data-card] {
  scroll-margin-top: calc(var(--topbar-h) + 16px);
}

/* A touch screen gets full-size targets wherever the shell is drawn. */
@media (pointer: coarse) {
  .side-head-btn,
  .side-new-job {
    width: 44px;
    height: 44px;
  }
  .side-title-btn {
    min-height: 44px;
  }

  .side-item,
  .side-new input,
  .side-new .btn,
  .side-provider .select {
    min-height: 44px;
  }
  .topbar-right .btn.icon,
  .topbar .menu,
  .side-close {
    width: 44px;
    height: 44px;
  }
  .side-alert {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }
  /* A computer's row is a column of name and bars; it only needs the height. */
  .sn-link {
    min-height: 44px;
  }
  .banner-close {
    width: 44px;
    height: 44px;
  }
}

/* Narrower than the page's two columns: each account stacks, and so does each limit. By the page's own width, since the sidebar takes some of the window's. */
@container status (max-width: 720px) {
  .reset-row {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 6px 12px;
  }
  .reset-time {
    grid-column: 1 / -1;
  }
  .acct {
    grid-template-columns: minmax(0, 1fr);
  }
  .acct-limits {
    grid-template-columns: minmax(0, 1fr) max-content max-content;
  }
  .lim-meter,
  .lim-reset {
    grid-column: 1 / -1;
  }
  .lim-reset {
    margin: -2px 0 4px;
  }
}

/*
 * The status block as the rail shows it: one glyph for the worst current
 * issue, its hover the issue and each computer's standing. Drawn only in the
 * rail; its hover, its severity colours and its focus ring are the alert
 * line's and the items', declared with them above.
 */
.side-rail-status {
  display: none;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: 1px solid var(--control-border);
  border-radius: 8px;
  color: var(--ok);
  font-size: 12px;
  font-weight: 600;
}

.side-rail-status[aria-current='page'] {
  background: var(--selected-bg);
}

/*
 * The sidebar collapsed to a rail, from the header's sidebar button: each
 * item its icon alone, its label as its tooltip, and the status block one
 * glyph. A section with nothing to list is left out, and the updated dot
 * keeps its place on the icon's corner. Only beside the page: the drawer
 * below 1024px is never a rail.
 */
@media (min-width: 1024px) {
  html.rail {
    --sidebar-w: 56px;
  }
  html.rail .sidebar {
    padding: 12px 6px;
  }
  html.rail .side-title-row,
  html.rail .side-title,
  html.rail .side-add,
  html.rail .side-count,
  html.rail .side-mark,
  html.rail .side-provider,
  html.rail .side-alert,
  html.rail .side-nodes,
  html.rail .sn-keys,
  html.rail .side-fold,
  html.rail .side-jobs,
  html.rail .side-new-job {
    display: none;
  }
  /* The rail has no heading to open the fold from, so it shows the pages' icons whatever the fold says. */
  html.rail .side-subprojects {
    padding-left: 0;
  }
  html.rail .side-inside[hidden] {
    display: block;
  }
  html.rail .side-jobs-group.folded > .side-list {
    display: grid;
  }
  /* Hidden the `.sr-only` way, so the label stays the item's name for a screen reader; the tooltip shows it to the eye. */
  html.rail .side-label,
  html.rail .side-text {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }
  html.rail .side-group:has(> .side-list[hidden]) {
    display: none;
  }
  html.rail .side-group + .side-group {
    padding-top: 12px;
    border-top: 1px solid var(--border);
  }
  html.rail .side-item {
    justify-content: center;
    gap: 0;
    padding: 7px 0;
  }
  /* In the rail a plugin's count becomes a dot on its icon, as the job pages' do. */
  html.rail .side-count.plugin-badge {
    display: block;
    position: absolute;
    top: 6px;
    right: 9px;
    width: 7px;
    min-width: 0;
    height: 7px;
    margin: 0;
    padding: 0;
    font-size: 0;
  }
  html.rail .side-count.side-dot:not([hidden]) {
    display: block;
    position: absolute;
    top: 6px;
    right: 9px;
    margin: 0;
  }
  html.rail .side-status {
    align-items: center;
  }
  html.rail .side-rail-status {
    display: inline-flex;
  }
}

/*
 * Below 1024px the sidebar becomes a drawer off the left edge, opened from
 * the menu button. The two drawers share the backdrop and the inert page.
 */
@media (max-width: 1023px) {
  .shell {
    grid-template-columns: minmax(0, 1fr);
  }
  .topbar .btn.menu .ico-drawer {
    display: block;
  }
  .topbar .btn.menu .ico-rail {
    display: none;
  }
  .header-meters {
    display: none;
  }
  .sidebar {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 40;
    width: min(304px, 88vw);
    height: 100vh;
    height: 100dvh;
    padding: 8px 10px 12px;
    border-right: 1px solid var(--border);
    box-shadow: 18px 0 40px rgba(0, 0, 0, 0.45);
    transform: translateX(-100%);
    visibility: hidden;
    transition: transform 200ms ease, visibility 0s linear 200ms;
  }
  .sidebar.open {
    transform: none;
    visibility: visible;
    transition: transform 200ms ease;
  }
  .sidebar-head {
    display: flex;
  }
  /* Outranks the page's own placement in column 2, declared further down. */
  .shell > .view {
    grid-column: 1;
  }
  .topbar .menu,
  .side-close {
    width: 44px;
    height: 44px;
  }
  .side-item {
    min-height: 44px;
  }
}

/*
 * A phone: the status line takes a line of its own under the brand so the
 * worst current issue stays in view with the drawer closed.
 */
@media (max-width: 640px) {
  .topbar {
    padding: 8px 12px;
  }
  /* A phone has the status line under the brand, which opens System status too, so the clock gives the other icons their room. */
  #quota-resets-open {
    display: none;
  }
  .status-strip {
    display: flex;
  }
  .status-strip[hidden] {
    display: none;
  }
  .topbar-right .btn.icon {
    width: 44px;
    height: 44px;
  }
  /* Tap targets as tall as the header's buttons. */
  .reset-badge {
    height: 44px;
  }
  .side-build,
  .side-update {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .sidebar,
  .sidebar.open {
    transition: visibility 0s;
  }
}

/*
 * The bell, then a slot per level it counts, most severe first: needs action in
 * the drawer's `!` colour, worth knowing in its `~` colour. A slot reads `-`
 * until something in it is unread. Wider than the other icon buttons to hold them.
 */
.topbar-right .btn.icon.bell,
.btn.icon.bell {
  width: auto;
  gap: 7px;
  padding: 0 9px;
}

.bell-counts {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.bell-count {
  min-width: 1ch;
  text-align: center;
}

.bell-count.action {
  color: var(--warn);
}

.bell-count.worth {
  color: var(--primary-bg);
}

.bell-count.none {
  font-weight: 400;
  opacity: 0.45;
}

/* Heard, not seen: the one place a new count is announced. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/*
 * The notification drawer. It slides rather than appearing so it is obvious
 * where it came from, and it is never removed from the page — `visibility`
 * waits out the slide instead, which keeps it off the tab order while closed.
 */
.drawer {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  width: 400px;
  max-width: 100vw;
  height: 100vh;
  background: var(--panel);
  border-left: 1px solid var(--border);
  box-shadow: -18px 0 40px rgba(0, 0, 0, 0.45);
  transform: translateX(100%);
  visibility: hidden;
  transition: transform 200ms ease, visibility 0s linear 200ms;
}

.drawer.open {
  transform: none;
  visibility: visible;
  transition: transform 200ms ease;
}

.drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 18px 0;
}

.drawer-head h2 {
  margin: 0;
}

/* The filter and the mark-all button, under the title and above the list. */
.drawer-tools {
  display: flex;
  gap: 8px;
  padding: 10px 18px 0;
}

/* One chip per machine, when there is more than one. They wrap rather than scroll. */
.drawer-nodes {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 10px 18px 0;
}

.drawer-nodes[hidden] {
  display: none;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 26px;
  padding: 3px 11px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--panel-2);
  color: var(--text);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}

.chip:hover {
  border-color: #3a4152;
}

.chip[aria-pressed='true'] {
  border-color: var(--selected-edge);
  background: var(--selected-bg);
}

.chip-count {
  color: var(--warn);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.chip-count[hidden] {
  display: none;
}

.drawer-sub {
  margin: 6px 18px 12px;
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--muted);
}

.drawer-list {
  flex: 1;
  overflow-y: auto;
  border-top: 1px solid var(--border);
  outline: none;
}

/*
 * A heading per level. Each stays at the top while its rows scroll under it,
 * and folds its list away; routine starts folded.
 */
.note-section-head {
  position: sticky;
  top: 0;
  z-index: 1;
  margin: 0;
  font-size: inherit;
}

.note-section-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: 34px;
  padding: 7px 18px;
  border: 0;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
  color: var(--muted);
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}

.note-section-toggle:hover {
  color: var(--text);
}

.note-section-chevron {
  display: inline-flex;
  transition: transform 150ms ease;
}

.note-section-toggle[aria-expanded='true'] .note-section-chevron {
  transform: rotate(90deg);
}

.note-section-count {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
}

.note-section-list[hidden] {
  display: none;
}

.drawer-empty {
  padding: 24px 18px;
  color: var(--muted);
  font-size: 13px;
}

/* Watched by the observer that pulls the next twenty in. */
.drawer-sentinel {
  height: 1px;
}

.drawer-backdrop {
  position: fixed;
  inset: 0;
  z-index: 30;
  background: rgba(0, 0, 0, 0.45);
  opacity: 0;
  visibility: hidden;
  transition: opacity 200ms ease, visibility 0s linear 200ms;
}

.drawer-backdrop.open {
  opacity: 1;
  visibility: visible;
  transition: opacity 200ms ease;
}

.note {
  display: flex;
  gap: 10px;
  padding: 11px 18px;
  border-bottom: 1px solid var(--border);
}

/*
 * A notification that lands while the drawer is open slides in from the edge
 * it came from, so a list that changes under the reader says that it changed.
 */
.note.arriving {
  animation: note-in 220ms ease-out;
}

@keyframes note-in {
  from {
    opacity: 0;
    transform: translateX(28px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .drawer,
  .drawer.open {
    transition: visibility 0s;
  }
  .note.arriving {
    animation: none;
  }
  .note-section-chevron {
    transition: none;
  }
}

.note.linked {
  cursor: pointer;
}

.note.linked:hover {
  background: var(--panel-2);
}

/* Unread carries the accent edge; read is the same row without the emphasis. */
.note.unread {
  background: var(--unread-tint);
  box-shadow: inset 2px 0 0 var(--primary-bg);
}

/* `!` needs action, `~` worth knowing, `·` routine: a shape as well as a colour. */
.note-glyph {
  flex: none;
  width: 10px;
  font-size: 13px;
  font-weight: 700;
  line-height: 1.45;
  text-align: center;
  color: var(--muted);
}

.note-glyph.action {
  color: var(--warn);
}

.note-glyph.worth {
  color: var(--primary-bg);
}

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

.note-message {
  font-size: 13px;
  line-height: 1.45;
  word-break: break-word;
}

.note.unread .note-message {
  font-weight: 600;
}

/* Which machine, when there is more than one: read first, but quieter than the news. */
.note-node {
  color: var(--muted);
}

.note-meta {
  margin-top: 3px;
  font-size: 11px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/*
 * A node's machine, on its own page: one tile per reading, each a 15-minute
 * chart with the numbers behind it written underneath.
 */
.metric-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 12px;
}

.metric-tile {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px 11px;
}

.pop-title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  font-size: 12.5px;
  font-weight: 600;
}

.tile-value {
  font-variant-numeric: tabular-nums;
}

.metric-tile.warning .tile-value {
  color: var(--warn);
}

.metric-tile.critical .tile-value {
  color: var(--fail);
}

/* What the top of the chart is worth, which a rate needs and a percentage says anyway. */
.spark-top {
  font-variant-numeric: tabular-nums;
}

.pop-sub {
  margin-top: 2px;
  font-size: 11px;
  line-height: 1.4;
  color: var(--muted);
}

.spark {
  display: block;
  width: 100%;
  height: 52px;
  margin: 8px 0 2px;
  overflow: visible;
}

.spark-line {
  fill: none;
  stroke: var(--meter);
  stroke-width: 1.5;
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

.spark-area {
  fill: var(--meter-soft);
  stroke: none;
}

.pop-axis {
  display: flex;
  justify-content: space-between;
  font-size: 10px;
  color: var(--muted);
  border-top: 1px solid var(--border);
  padding-top: 4px;
}

.pop-stats {
  display: flex;
  gap: 14px;
  margin: 8px 0 0;
}

.pop-stats div {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.pop-stats dt {
  font-size: 10px;
  color: var(--muted);
}

.pop-stats dd {
  margin: 0;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}

.pop-detail {
  margin-top: 8px;
  font-size: 11px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.pop-note {
  margin-top: 6px;
  font-size: 11px;
  color: var(--warn);
}

.pop-detail[hidden],
.pop-note[hidden] {
  display: none;
}

/*
 * Wide enough that the date columns keep a time on one line. A run's "Sep 23,
 * 3:00:00 AM" breaking after the comma, or worse before the AM, was the whole
 * reason this is not 1080px.
 */
.view {
  grid-column: 2;
  grid-row: 3;
  width: 100%;
  max-width: 1320px;
  margin: 0 auto;
  padding: 24px 22px 64px;
  outline: none;
}

/* Focus lands on the title after a move between pages; the ring shows for the keyboard only. */
h1[tabindex='-1']:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 4px;
  border-radius: 4px;
}

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

/* Pause control and New cron sit together, and wrap as a pair on a phone. */
.head-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* Left of the pause control; filters whichever home tab is open. */
.head-actions input.home-search {
  flex: 0 1 240px;
  width: 240px;
  min-width: 0;
  padding: 8px 10px;
  font-size: 13px;
}

/* Sized to its own content rather than filling the row like a form select. */
.select.pause-select {
  flex: 0 0 auto;
  width: auto;
  padding: 8px 10px;
}

h1 {
  font-size: 20px;
  margin: 0 0 4px;
}

h2 {
  font-size: 16px;
  margin: 0 0 10px;
}

/* The logs page heading, with the job's status beside it. */
.logs-title {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 4px;
}

.logs-title h1 {
  margin: 0;
}

.logs-delay {
  margin-bottom: 4px;
}

.sub {
  color: var(--muted);
  font-size: 13px;
  margin: 0;
}

.btn {
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  border-radius: 8px;
  padding: 7px 13px;
  font-size: 13px;
  cursor: pointer;
  white-space: nowrap;
}

.btn:hover {
  border-color: #3a4152;
  background: #232834;
}

.btn.primary {
  background: var(--primary-bg);
  border-color: var(--primary-bg);
  color: var(--primary-ink);
  font-weight: 600;
}

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

.btn.danger {
  color: var(--fail);
  border-color: var(--fail-edge);
}

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

.btn:disabled {
  opacity: 0.5;
  cursor: default;
}

.btn.small {
  padding: 5px 10px;
  font-size: 12px;
}

/*
 * Icon only. The glyph carries the meaning on its own, so it takes the room the
 * label used to, and the name it answers to lives in title and aria-label.
 */
.btn.icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  font-size: 15px;
  line-height: 1;
}

/* The two home tabs. A row of links rather than buttons, so each is a real URL
   that can be opened, bookmarked and reloaded. */
.tabs {
  display: flex;
  gap: 4px;
  margin-bottom: 14px;
  border-bottom: 1px solid var(--border);
}

.tab {
  padding: 9px 14px;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  text-decoration: none;
  border: 1px solid transparent;
  border-bottom: none;
  border-radius: var(--radius) var(--radius) 0 0;
  /* Sits on the container's border so the selected tab can cover it. */
  margin-bottom: -1px;
  white-space: nowrap;
}

.tab:hover {
  color: var(--text);
  background: rgba(255, 255, 255, 0.03);
}

.tab.selected {
  color: var(--text);
  background: var(--panel);
  border-color: var(--border);
  border-bottom: 1px solid var(--panel);
  box-shadow: inset 0 2px 0 var(--selected-edge);
}

/* How many jobs on a tab are updated since they were last opened. */
.tab-count {
  display: inline-block;
  min-width: 18px;
  margin-left: 6px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--primary-bg);
  color: var(--primary-ink);
  font-size: 11px;
  line-height: 18px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.tab-count[hidden] {
  display: none;
}

/* Sort and Mark all read, between the tabs and the list. */
.list-tools {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px 12px;
  margin-bottom: 10px;
}

.list-actions {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

/* Sort, with Filters under it. */
.list-controls {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.sort-group {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px;
}

.sort-label {
  min-width: 3.5em;
  margin-right: 4px;
  font-size: 12px;
  color: var(--muted);
}

.sort-group .btn[aria-pressed='true'] {
  border-color: var(--selected-edge);
  background: var(--selected-bg);
  font-weight: 600;
}

.btn[aria-disabled='true'] {
  opacity: 0.5;
  cursor: default;
}

/* A job's name and, when it has news, the word that says so. */
.job-title {
  position: relative;
}

/* Indented past a group row's dot, so names line up with the group's name and the unread dot with its dot. */
.job-name-cell {
  padding-left: 30px;
}

/* In the cell's padding, so the name stays put whether or not it is there. */
.unread-dot {
  position: absolute;
  top: 7px;
  left: -15px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
}

html:not(.hide-updated) tr.unread .unread-dot {
  background: var(--primary-bg);
}

/* Text in the text colour on the accent, so it reads whatever the server colour is. */
.updated-tag {
  display: inline-block;
  margin-left: 8px;
  vertical-align: 1px;
  padding: 0 7px;
  border: 1px solid var(--control-border);
  border-radius: 999px;
  background: var(--panel-2);
  color: var(--text);
  font-size: 11px;
  font-weight: 600;
  line-height: 17px;
  white-space: nowrap;
}

.panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}

/* Beside the sidebar a job table can be wider than its panel, around 1100px; it scrolls sideways rather than losing its last buttons. */
.panel:has(> table) {
  overflow-x: auto;
}

/* The foot of the one-time list: one more page, and how far down you are. */
.load-more {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-top: 1px solid var(--border);
  background: var(--panel-2);
}

table {
  width: 100%;
  border-collapse: collapse;
}

th,
td {
  text-align: left;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}

th {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--muted);
  font-weight: 600;
  background: var(--panel-2);
}

tbody tr:last-child td {
  border-bottom: none;
}

tbody tr:hover {
  background: rgba(255, 255, 255, 0.02);
}

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

.cron-desc {
  color: var(--muted);
  font-size: 12px;
  margin-top: 2px;
}

/*
 * A description is two lines on the page and the whole thing in the tooltip.
 * Some of them are a paragraph, and a paragraph in a table cell makes one row
 * three times the height of its neighbours.
 */
.cron-desc.clamp {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  max-width: 560px;
  cursor: help;
}

/* Dates and countdowns read as one thing; a wrap splits "3:00:00 AM" in two. */
.time-cell {
  white-space: nowrap;
}

/* A next run time that could start late: the warning in front, the reason on hover. */
.delay-risk {
  display: flex;
  align-items: center;
  gap: 5px;
  cursor: help;
}

.delay-risk svg {
  display: block;
  color: var(--warn);
}

.mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px;
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  padding: 2px 9px;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--muted);
  white-space: nowrap;
}

.pill[hidden] {
  display: none;
}

.pill a:hover {
  color: var(--text);
  text-decoration: underline;
}

.pill .led {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
}

.pill.active {
  color: var(--ok);
  border-color: rgba(78, 201, 138, 0.35);
}

.pill.paused {
  color: var(--muted);
}

.pill.running {
  color: var(--live);
  border-color: var(--live-edge);
}

.pill.running .led {
  animation: pulse 1.1s ease-in-out infinite;
}

/* Held by a pause: distinct from deactivated, which is the cron's own setting. */
.pill.held {
  color: var(--warn);
  border-color: var(--warn-edge);
}

/* Waiting on a usage limit. Amber like a live run because something is pending,
   dashed because nothing is actually executing yet. */
.pill.delayed {
  color: var(--warn);
  border-style: dashed;
  border-color: var(--warn-edge);
}

.pill.delayed .led {
  animation: pulse 2.4s ease-in-out infinite;
}

/* A finished-but-interrupted outcome: amber, and not pulsing like a live run. */
.pill.warn {
  color: var(--warn);
  border-color: var(--warn-edge);
}

/* Live run length: blue like a running run, but steady — the ticking digits
   are the movement. Tabular figures keep the column from twitching each second. */
.pill.runtime {
  color: var(--live);
  border-color: var(--live-edge);
  font-variant-numeric: tabular-nums;
}

.pill.failed {
  color: var(--fail);
  border-color: var(--fail-edge);
}

@keyframes pulse {
  0%,
  100% {
    opacity: 0.25;
  }
  50% {
    opacity: 1;
  }
}

.row-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
}

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

.empty {
  padding: 46px 20px;
  text-align: center;
  color: var(--muted);
}

form.card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px;
  display: grid;
  gap: 16px;
}

.field {
  display: grid;
  gap: 6px;
}

.field[hidden] {
  display: none;
}

.preset-row[hidden] {
  display: none;
}

label {
  font-size: 12.5px;
  color: var(--muted);
}

input[type="text"],
input[type="number"],
input[type="search"],
input[type="password"],
textarea {
  background: #12151b;
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  padding: 9px 11px;
  font: inherit;
  width: 100%;
}

textarea {
  min-height: 190px;
  resize: vertical;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px;
  line-height: 1.55;
}

/* A short list of patterns rather than a prompt. */
textarea.compact {
  min-height: 110px;
}

/* One command per line: a long one scrolls rather than wrapping into what
   would read as two. */
textarea.commands-input {
  white-space: pre;
  overflow-wrap: normal;
  overflow-x: auto;
}

input:focus,
textarea:focus {
  outline: none;
  border-color: var(--focus);
  box-shadow: 0 0 0 3px var(--focus-soft);
}

.hint {
  font-size: 11.5px;
  color: var(--muted);
}

ul.hint {
  margin: 4px 0 0;
  padding-left: 18px;
}

.hint a {
  text-decoration: underline;
  text-underline-offset: 2px;
}

.hint.ok {
  color: var(--ok);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

.hint.warn {
  color: var(--warn);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* Settings page */
.card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px;
  display: grid;
  gap: 16px;
  margin-bottom: 16px;
}

/* Two readings in one card: a rule across it, rather than a second card. */
.card-divider {
  height: 1px;
  background: var(--border);
  margin: 0 -20px;
}

.card h3 {
  font-size: 11.5px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0;
}

.path-value {
  color: var(--text);
  font-size: 12.5px;
  word-break: break-all;
}

input.narrow {
  width: 72px;
  text-align: center;
  padding: 5px 8px;
  font-size: 12.5px;
}

/* Model dropdown */
.select-row {
  display: flex;
  gap: 8px;
  align-items: center;
}

.select {
  flex: 1;
  min-width: 0;
  background: #12151b;
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  padding: 9px 11px;
  font: inherit;
  font-size: 13px;
  color-scheme: dark;
}

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

/* Holds a disabled button so the pause explanation can be hovered: pointer
   events are suppressed on the button itself, so the wrapper gets the hover. */
.btn-hold {
  display: inline-flex;
  cursor: not-allowed;
}

.btn-hold > .btn:disabled {
  pointer-events: none;
  cursor: not-allowed;
}

.select:disabled,
.btn:disabled {
  opacity: 0.5;
  cursor: progress;
}

/* Cron field legend, each name explaining itself on hover */
.legend {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  white-space: nowrap;
}

.cron-field {
  position: relative;
  color: var(--text);
  border-bottom: 1px dotted var(--muted);
  text-decoration: none;
  cursor: help;
}

.cron-field::after,
.field-tip::after {
  content: attr(data-tip);
  position: absolute;
  bottom: calc(100% + 7px);
  left: 50%;
  transform: translateX(-50%);
  width: max-content;
  max-width: 230px;
  white-space: normal;
  text-align: center;
  background: #0b0d12;
  color: var(--text);
  border: 1px solid #3a4152;
  border-radius: 7px;
  padding: 6px 9px;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 11.5px;
  line-height: 1.45;
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.5);
  opacity: 0;
  pointer-events: none;
  transition: opacity 90ms ease;
  z-index: 20;
}

.cron-field:hover::after,
.field-tip:hover::after,
.field-tip:focus-visible::after {
  opacity: 1;
}

/* A plugin setting's tooltip mark: a small ? beside its label. Its bubble opens to the right, so a label at the card's edge keeps it on the page. */
.field-tip {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 15px;
  margin-left: 6px;
  border: 1px solid var(--muted);
  border-radius: 50%;
  color: var(--muted);
  font-size: 10px;
  font-weight: 600;
  line-height: 1;
  vertical-align: middle;
  cursor: help;
}

.field-tip:hover,
.field-tip:focus-visible {
  color: var(--text);
  border-color: var(--text);
  outline: none;
}

.field-tip::after {
  left: -8px;
  transform: none;
  max-width: 280px;
  text-align: left;
  font-weight: 400;
}

/* Cron field shortcuts */
.preset-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.join-command {
  flex: 1;
  min-width: 0;
}

/* What to run to trust a folder, under the line that names it, in the page's own text colour. */
.trust-fix {
  margin-top: 6px;
  color: var(--text);
}

.trust-fix .sp-meta {
  margin: 0 0 6px;
}

.trust-folder + .trust-folder {
  margin-top: 12px;
}

/* A long common command is cut short on its button; the title carries all of it. */
.command-button {
  max-width: 280px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.preset-sep {
  width: 1px;
  height: 20px;
  background: var(--border);
  margin: 0 2px;
}

.preset-label {
  font-size: 12.5px;
  color: var(--muted);
}

/* The Server Color picks: a row of dots, the chosen one ringed. */
.swatch,
.swatch-custom {
  width: 26px;
  height: 26px;
  padding: 0;
  border: none;
  border-radius: 50%;
  cursor: pointer;
  box-shadow: 0 0 0 1px var(--border);
}

.swatch[aria-pressed="true"],
.swatch-custom.selected {
  box-shadow: 0 0 0 2px var(--panel), 0 0 0 4px var(--text);
}

.swatch-custom {
  background: none;
}

.swatch-custom::-webkit-color-swatch-wrapper {
  padding: 0;
}

.swatch-custom::-webkit-color-swatch {
  border: none;
  border-radius: 50%;
}

.swatch-custom::-moz-color-swatch {
  border: none;
  border-radius: 50%;
}

.time-entry {
  background: #12151b;
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  padding: 5px 9px;
  font: inherit;
  font-size: 12.5px;
  /* Renders the native clock picker in dark. */
  color-scheme: dark;
}

.time-entry:focus {
  outline: none;
  border-color: var(--focus);
  box-shadow: 0 0 0 3px var(--focus-soft);
}

/* Working Directory picker */
.combo {
  position: relative;
}

.combo-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 10;
  background: var(--panel-2);
  border: 1px solid #3a4152;
  border-radius: 8px;
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.5);
  max-height: 244px;
  overflow-y: auto;
  padding: 4px;
}

.combo-item {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  border-radius: 6px;
  color: var(--text);
  padding: 7px 9px;
  cursor: pointer;
  font-size: 12.5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.combo-item:hover,
.combo-item.active {
  background: var(--selected-bg);
  color: var(--text);
}

.combo-item.active {
  box-shadow: inset 0 0 0 1px var(--control-border);
}

/* A delayed job's Stop, joined to the caret that opens Run anyway. */
.split-btn {
  display: inline-flex;
}

.split-btn > .btn:first-child {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

.split-btn > .split-caret {
  border-left: none;
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  padding-left: 7px;
  padding-right: 7px;
}

/* Fixed, not absolute: the job table's panel clips what overflows it. */
.split-menu {
  position: fixed;
  z-index: 50;
  min-width: 140px;
  background: var(--panel-2);
  border: 1px solid #3a4152;
  border-radius: 8px;
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.5);
  padding: 4px;
}

.split-item {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  border-radius: 6px;
  color: var(--text);
  padding: 7px 9px;
  cursor: pointer;
  font-size: 12.5px;
  white-space: nowrap;
}

.split-item:hover:not(:disabled),
.split-item:focus-visible {
  background: var(--selected-bg);
}

.split-item:disabled {
  opacity: 0.5;
  cursor: default;
}

/* Lifetime totals under the cron name on the logs page. Wraps rather than
   squeezing, so a narrow window stacks them instead of clipping the digits. */
.stat-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 12px;
}

.stat {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 9px;
  padding: 9px 14px;
  min-width: 132px;
}

.stat-value {
  font-size: 19px;
  font-weight: 600;
  line-height: 1.25;
  /* Tabular figures so a total that ticks up does not shift the label under it. */
  font-variant-numeric: tabular-nums;
}

.stat-label {
  font-size: 11.5px;
  color: var(--muted);
  margin-top: 1px;
}

.stat-sub {
  font-size: 11.5px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  margin-top: 3px;
}

/* A row of choices that wraps on a narrow window rather than forcing the page wider. */
.delay-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 22px;
  padding: 2px 0;
}

.check {
  display: flex;
  align-items: center;
  gap: 9px;
  color: var(--text);
  font-size: 13.5px;
  cursor: pointer;
}

.check input {
  width: 16px;
  height: 16px;
  accent-color: var(--primary-bg);
}

/* A setting that can follow a default: the input, then either the word that
   says it is following or the way back to it. */
.setting-row {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px 10px;
}

.setting-tag {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
}

.setting-default {
  font-size: 11px;
  line-height: 18px;
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0 8px;
  white-space: nowrap;
}

.setting-reset {
  background: none;
  border: 0;
  padding: 0 2px;
  min-height: 24px;
  font: inherit;
  font-size: 12px;
  color: var(--text);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
  white-space: nowrap;
}

.setting-reset:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: 4px;
}

.setting-tag[hidden],
.setting-row[hidden],
.setting-default[hidden],
.setting-reset[hidden] {
  display: none;
}

.settings-section {
  display: grid;
  gap: 16px;
}

/* Read by a screen reader, not drawn. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.form-actions {
  display: flex;
  gap: 10px;
  align-items: center;
  border-top: 1px solid var(--border);
  padding-top: 16px;
}

.form-actions .spacer {
  flex: 1;
}

/* A job form's heading: the Running switch, with a copy of the form's buttons under it. */
.head-side {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
}

.form-actions.top {
  border-top: 0;
  padding-top: 0;
  flex-wrap: wrap;
  justify-content: flex-end;
}

/* Delete sits right beside the others here, not pushed away from them. */
.form-actions.top .spacer {
  display: none;
}

/* Job forms: the prompt first and largest. */
textarea.prompt-input {
  min-height: 240px;
}

fieldset.when {
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}

fieldset.when legend {
  font-size: 12.5px;
  color: var(--muted);
  padding: 0;
  margin-bottom: 6px;
}

/* Sits under its choice, lined up with the words rather than the dot. */
.when-hint {
  margin: -2px 0 4px 25px;
}

.when-time {
  margin: 2px 0 0 25px;
}

/* Node and Working Directory side by side, stacked on a narrow window. */
.where-row {
  display: grid;
  grid-template-columns: minmax(200px, 1fr) minmax(0, 2fr);
  gap: 16px;
  align-items: start;
  container-type: inline-size;
}

/* Under about 700px of row the Node cards would be narrower than the sidebar
   tile they borrow from, so the two stack. By the row's own width, since the
   sidebar takes some of the window's. */
@container (max-width: 700px) {
  .where-row > * {
    grid-column: 1 / -1;
  }
}

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

  .when-hint,
  .when-time {
    margin-left: 0;
  }
}

/*
 * The Node field: one card per computer, a radio with the computer's standing
 * beside it in the sidebar's words and meters. The whole card is the label,
 * so anywhere on it picks the node.
 */
fieldset.node-field {
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}

.node-field legend {
  padding: 0;
  margin-bottom: 6px;
  font-size: 12.5px;
  color: var(--muted);
}

.node-opts {
  display: grid;
  gap: 8px;
}

.node-opt {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 10px;
  align-items: start;
  padding: 10px 12px;
  background: #12151b;
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  font-size: 13px;
  cursor: pointer;
}

.node-opt:hover {
  border-color: var(--control-border);
}

.node-opt input {
  width: 16px;
  height: 16px;
  margin: 2px 0 0;
  accent-color: var(--primary-bg);
}

.node-opt-body,
.node-reading {
  display: grid;
  gap: 4px;
  min-width: 0;
}

.node-opt-name {
  font-weight: 600;
  overflow-wrap: anywhere;
}

/* Why the field picked this computer for a new one-time job; empty, and so gone, otherwise. */
.node-why {
  display: flex;
  align-items: flex-start;
  gap: 5px;
  color: var(--primary-bg);
  font-size: 12px;
}

.node-why .glyph {
  display: inline-flex;
  flex: none;
  margin-top: 2px;
}

.node-why:empty {
  display: none;
}

.node-state,
.node-meta,
.node-folder {
  color: var(--muted);
  font-size: 12px;
  overflow-wrap: anywhere;
}

/* Online is a filled dot, offline a hollow one, each with its word, as the sidebar draws them. */
.node-state.online .glyph {
  color: var(--ok);
}

.node-state.offline .glyph {
  color: var(--muted);
}

.node-opt .avail-limits {
  margin-top: 2px;
}

.node-meta.stale {
  color: var(--muted);
}

.node-folder.ok {
  color: var(--ok);
}

.node-folder.warn {
  color: var(--warn);
}

/* The last answer, while a new one is on its way. */
.node-folder.pending {
  opacity: 0.55;
}

/* The chosen card carries the accent, and the focus ring sits on the card rather than the dot, where the browser can put it there. */
@supports selector(:has(a)) {
  .node-opt:has(input:checked) {
    border-color: var(--selected-edge);
  }

  .node-opt:has(input:focus-visible) {
    border-color: var(--focus);
    box-shadow: 0 0 0 3px var(--focus-soft);
  }

  .node-opt input:focus-visible {
    outline: none;
  }
}

@media (pointer: coarse) {
  .node-opt {
    min-height: 44px;
  }
}

details.more-options {
  border: 1px solid var(--border);
  border-radius: 8px;
}

details.more-options > summary {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 12px;
  padding: 12px 14px;
  min-height: 44px;
  cursor: pointer;
  list-style: none;
}

details.more-options > summary::-webkit-details-marker {
  display: none;
}

details.more-options > summary::before {
  content: '▸';
  color: var(--muted);
  transition: transform 120ms ease-out;
}

details.more-options[open] > summary::before {
  transform: rotate(90deg);
}

@media (prefers-reduced-motion: reduce) {
  details.more-options > summary::before {
    transition: none;
  }
}

details.more-options > summary:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: 8px;
}

.more-title {
  color: var(--text);
  font-size: 13.5px;
  font-weight: 500;
}

.more-summary {
  color: var(--muted);
  font-size: 12.5px;
}

.more-body {
  display: grid;
  gap: 16px;
  padding: 16px 14px;
  border-top: 1px solid var(--border);
}

/* A grid item is as wide as its widest word by default, and a long path or
   model name would push the card past the edge of a phone. */
.card > *,
.more-body > *,
.where-row > *,
.field > * {
  min-width: 0;
}

.hint {
  overflow-wrap: anywhere;
}

.error {
  background: var(--fail-soft);
  border: 1px solid var(--fail-edge);
  color: var(--fail);
  border-radius: 8px;
  padding: 10px 12px;
  font-size: 13px;
}

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

.run-sidebar {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}

/* The run on show: what it needs from you, when anything, above its log. */
.run-main {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
}

/* What a run that ended needing you asks: its steps, its decisions, and the way to answer. */
.answer-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 16px 18px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.answer-summary {
  margin: 0;
  color: var(--text-2);
  font-size: 14px;
  line-height: 1.55;
}

.answer-decision {
  display: flex;
  flex-direction: column;
  gap: 9px;
  margin: 0;
  padding: 12px 15px 15px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--panel-2);
}

.answer-decision legend,
.answer-steps-title {
  padding: 0 6px;
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.answer-steps-title {
  margin: 0 0 6px;
  padding: 0;
}

/* The run's own short label for the question, beside Your decision. */
.answer-header {
  margin-left: 8px;
  padding: 0 5px;
  border: 1px solid var(--control-border);
  border-radius: 4px;
  color: var(--text-2);
  letter-spacing: 0.02em;
  text-transform: none;
}

.answer-question {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.4;
}

/* Why the run asks: the background it gave, read before the choices. */
.answer-context {
  margin: 0;
  padding-left: 18px;
  color: var(--text-2);
  font-size: 13px;
  line-height: 1.55;
}

/* Each choice is a card, all of it the label, so a click anywhere picks it. */
.answer-option {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 10px 14px;
  border: 1px solid var(--option-edge);
  border-radius: 8px;
  background: var(--panel);
  /* A label is muted and small app-wide; a choice reads as text. */
  color: var(--text);
  font-size: 14px;
  cursor: pointer;
}

.answer-option:hover {
  border-color: var(--control-border);
}

.answer-option:has(input:checked) {
  border-color: var(--selected-edge);
  background: var(--selected-bg);
}

.answer-option input {
  flex: none;
  width: 16px;
  height: 16px;
  margin: 2px 0 0;
  accent-color: var(--primary-bg);
  cursor: pointer;
}

/* Your own answer: the last choice, its button beside a box rather than a label. */
.answer-own {
  cursor: default;
}

.answer-own input {
  margin-top: 13px;
}

.answer-card textarea.answer-own-box {
  flex: 1;
  min-width: 0;
  min-height: 44px;
  border-color: var(--control-border);
  font: inherit;
  font-size: 14px;
  line-height: 1.5;
}

/* The app's input focus is a soft glow, too faint on a radio or a checkbox. */
.answer-card input:not([type="text"]):focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.answer-option-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.answer-label {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 8px;
  font-size: 14px;
  font-weight: 600;
}

.answer-recommended {
  padding: 0 5px;
  border: 1px solid var(--recommend-edge);
  border-radius: 4px;
  color: var(--recommend);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.answer-desc {
  color: var(--muted);
  font-size: 13px;
  line-height: 1.45;
}

/* Back to no choice, so a note alone can be the answer. */
.answer-clear {
  align-self: flex-start;
  padding: 2px 4px;
  border: none;
  border-radius: 4px;
  background: none;
  color: var(--text-2);
  font: inherit;
  font-size: 12.5px;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}

.answer-clear:hover {
  color: var(--text);
}

.answer-clear:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
}

/* A reply to a run: its label, what it is for, and the box, in the page's type rather than the code font other boxes use. */
.reply-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.reply-label {
  color: var(--text);
  font-size: 14px;
  font-weight: 600;
}

.reply-help {
  color: var(--muted);
  font-size: 12.5px;
}

.reply-field textarea.reply-box {
  min-height: 64px;
  border-color: var(--control-border);
  font: inherit;
  font-size: 14px;
  line-height: 1.5;
}

/* The variables a reply sends for its run alone: shut, a line naming what is carried; open, a row each and a paste box. */
.vars {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel);
  container: vars-box / inline-size;
}

.vars summary {
  display: grid;
  grid-template-columns: 14px minmax(0, 1fr) auto;
  align-items: center;
  column-gap: 8px;
  row-gap: 2px;
  min-height: 40px;
  box-sizing: border-box;
  padding: 8px 12px;
  border-radius: 8px;
  color: var(--text);
  font-size: 13.5px;
  font-weight: 600;
  list-style: none;
  cursor: pointer;
}

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

.vars summary:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
}

.vars-chevron {
  display: inline-flex;
  color: var(--muted);
  transition: transform 0.15s ease;
}

.vars[open] .vars-chevron {
  transform: rotate(90deg);
}

.vars-note {
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 400;
  text-align: right;
}

.vars-names {
  grid-column: 2 / -1;
  color: var(--text-2);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  font-weight: 400;
  line-height: 1.55;
  overflow-wrap: anywhere;
}

.vars-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 2px 12px 12px;
}

.vars-said,
.vars-codex {
  margin: 0;
  color: var(--text-2);
  font-size: 12.5px;
  line-height: 1.55;
}

.vars-codex {
  color: var(--muted);
}

.vars-list {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--option-edge);
  border-radius: 8px;
  background: #12151b;
  overflow: hidden;
  container: vars / inline-size;
}

/* Name, value, the Sensitive tick and remove; a line under it when it stands in for one of the job's own. */
.vars-row {
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr) auto 32px;
  align-items: center;
  gap: 4px 12px;
  padding: 4px 6px 4px 12px;
  border-top: 1px solid var(--border);
}

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

.vars-name,
.vars-value {
  overflow: hidden;
  font-size: 12.5px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.vars-value {
  color: var(--muted);
}

.vars-dots {
  letter-spacing: 0.08em;
}

.vars-sensitive {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 32px;
  color: var(--text-2);
  font-size: 12.5px;
  white-space: nowrap;
  cursor: pointer;
}

.vars-sensitive input {
  width: 15px;
  height: 15px;
  margin: 0;
  accent-color: var(--primary-bg);
}

.vars-sensitive:has(input:disabled) {
  cursor: default;
  opacity: 0.7;
}

.vars-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--muted);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
}

.vars-remove:hover:not(:disabled) {
  background: var(--panel-2);
  color: var(--text);
}

.vars-remove:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: -2px;
}

.vars-over {
  grid-column: 1 / -1;
  margin: -2px 0 4px;
  color: var(--muted);
  font-size: 12px;
}

/* Too narrow for the count beside the title: it goes under it, as the names do. */
@container vars-box (max-width: 520px) {
  .vars summary {
    grid-template-columns: 14px minmax(0, 1fr);
  }

  .vars-note {
    grid-column: 2;
    text-align: left;
  }
}

/* Too narrow for a long name beside its value: the value goes under the name, so neither is cut short. */
@container vars (max-width: 460px) {
  .vars-row {
    grid-template-columns: minmax(0, 1fr) auto 32px;
    row-gap: 0;
    padding-top: 6px;
    padding-bottom: 6px;
  }

  .vars-name {
    grid-column: 1;
    overflow-wrap: anywhere;
    white-space: normal;
  }

  .vars-value {
    grid-column: 1;
    grid-row: 2;
  }

  .vars-sensitive {
    grid-column: 2;
    grid-row: 1 / 3;
  }

  .vars-remove {
    grid-column: 3;
    grid-row: 1 / 3;
  }

  .vars-over {
    margin-top: 4px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .vars-chevron {
    transition: none;
  }
}

.vars-paste {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.vars-paste-label {
  color: var(--text-2);
  font-size: 12.5px;
}

.vars textarea.vars-paste-box {
  min-height: 38px;
  padding: 8px 10px;
  border: 1px dashed var(--control-border);
  border-radius: 6px;
  font-size: 12.5px;
  line-height: 1.5;
}

.vars textarea.vars-paste-box::placeholder {
  color: var(--muted);
}

.vars-paste-help {
  color: var(--muted);
  font-size: 12px;
}

.vars-problem {
  margin: 0;
  font-family: inherit;
  font-size: 12.5px;
}

.vars-list[hidden],
.vars-names[hidden],
.vars-said[hidden],
.vars-problem[hidden] {
  display: none;
}

/* The foot of a finished run's log: the box that writes to it, or the run that carried it on. */
.talk-box {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px 14px;
  border-top: 1px solid var(--border);
  background: var(--panel-2);
}

.talk-continued {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
  color: var(--text-2);
  font-size: 13px;
}

.answer-steps ul,
.log-outcome ul.log-outcome-steps {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* A step only a person can do: the drawer's Needs action glyph, then the step, its links underlined. */
.answer-step,
.log-outcome-steps li {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 5px 0;
  font-size: 13.5px;
  line-height: 1.45;
}

.log-outcome ul.log-outcome-steps {
  padding: 8px 12px 4px;
}

.answer-step a,
.log-outcome-steps a {
  color: var(--text);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.answer-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
}

.answer-actions .btn {
  min-height: 36px;
}

.answer-actions .btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.answer-hint {
  color: var(--muted);
  font-size: 12.5px;
}

.answer-error {
  margin: 0;
  color: var(--fail);
  font-size: 13px;
}

.answer-error:empty {
  display: none;
}

/* A run that was dismissed or answered: one line above its log, with the box under the log still there. */
.answer-handled {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel);
  color: var(--text-2);
  font-size: 13px;
}

.answer-handled-glyph {
  display: inline-flex;
  color: var(--muted);
}

/* What a run asked, in its log, in the outcome's type rather than the log's. */
.log-question {
  padding: 0 12px 4px;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  white-space: normal;
}

.log-question p {
  margin: 0 0 4px;
  font-size: 13px;
}

.log-question .answer-header {
  margin-left: 0;
}

/* The background, as the card shows it, above the options. */
.log-question .log-question-context {
  margin-bottom: 6px;
  color: var(--text-2);
  list-style: disc;
}

.log-question .answer-recommended {
  margin-left: 8px;
}

.log-question ul {
  margin: 0 0 10px;
  padding-left: 20px;
  font-size: 13px;
  line-height: 1.6;
}

/* A follow-up under the run whose questions it answered. */
.run-item.follow-up {
  padding-left: 25px;
}

.run-subitem.follow-up {
  padding-left: 37px;
}

.follow-up-mark {
  margin-right: 6px;
  color: var(--muted);
}

.run-list {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  max-height: 70vh;
  overflow: auto;
}

.run-item {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  border-bottom: 1px solid var(--border);
  color: var(--text);
  padding: 11px 13px;
  cursor: pointer;
  font: inherit;
}

.run-item:hover {
  background: rgba(255, 255, 255, 0.03);
}

.run-item.selected {
  background: var(--selected-bg);
  border-left: 2px solid var(--selected-edge);
}

.run-item .when {
  font-size: 13px;
}

.run-item .meta {
  color: var(--muted);
  font-size: 11.5px;
  margin-top: 3px;
  display: flex;
  gap: 8px;
  align-items: center;
}

.run-subitem {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  border-bottom: 1px solid var(--border);
  color: var(--quiet);
  padding: 7px 13px 7px 25px;
  cursor: pointer;
  font: inherit;
  font-size: 12px;
}

.run-subitem:hover {
  background: rgba(255, 255, 255, 0.03);
}

.run-subitem.selected {
  background: var(--selected-bg);
  border-left: 2px solid var(--selected-edge);
}

/* A job's next run atop its runs: the clock, or the pause mark while a trigger waits. */
.run-next .when {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
}

.run-next-icon {
  display: inline-flex;
  color: var(--muted);
}

.run-next .meta {
  color: var(--text-2);
}

/* What the Next run entry opens: why it waits and how each computer answered, then what can be done. */
.next-body {
  display: grid;
  gap: 12px;
  padding: 14px;
  overflow: auto;
}

.next-body p {
  margin: 0;
  color: var(--text-2);
}

.next-verdicts,
.next-ahead {
  display: grid;
  border: 1px solid var(--border);
  border-radius: 8px;
}

.next-verdict,
.next-ahead-head {
  display: grid;
  grid-template-columns: minmax(90px, 160px) minmax(80px, 110px) minmax(0, 1fr);
  gap: 12px;
  padding: 7px 12px;
  border-top: 1px solid var(--border);
  font-size: 13px;
}

.next-verdict:first-child,
.next-ahead-head {
  border-top: 0;
}

.next-ahead-head {
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.next-computer {
  font-weight: 600;
  overflow-wrap: anywhere;
}

.next-state,
.next-detail {
  color: var(--text-2);
}

.next-verdict.starts .next-state {
  color: var(--text);
}

.next-verdict.no-folder,
.next-verdict.no-agent,
.next-verdict.shell-off,
.next-verdict.outdated,
.next-verdict.offline {
  color: var(--muted);
}

.next-verdict.no-folder .next-detail,
.next-verdict.no-agent .next-detail,
.next-verdict.shell-off .next-detail,
.next-verdict.outdated .next-detail,
.next-verdict.offline .next-detail {
  color: var(--muted);
}

.next-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* A run waiting for values: as tall as what it holds, so its buttons never sit under a scroll, and nothing in it is squeezed. */
.log-panel.values-panel {
  max-height: none;
}

.values-panel .next-body {
  display: flex;
  flex-direction: column;
}

/* What a run waiting for values printed when its check failed. */
.values-check-output {
  flex-shrink: 0;
  margin: 0;
  max-height: 220px;
  padding: 10px 12px;
  overflow: auto;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #12151b;
  color: #cfd6e2;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px;
  line-height: 1.55;
  white-space: pre-wrap;
  word-break: break-word;
}

/* A run's retrospective, set apart from the output it follows. */
.log-panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 320px;
  max-height: 70vh;
}

.log-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 13px;
  border-bottom: 1px solid var(--border);
  background: var(--panel-2);
  flex-wrap: wrap;
}

.log-clock {
  font-variant-numeric: tabular-nums;
}

.log-head .spacer {
  flex: 1;
}

.log-body {
  margin: 0;
  padding: 14px;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px;
  line-height: 1.55;
  color: #cfd6e2;
  flex: 1;
}

/* A line of the node's own in the log: a tool call, or under it, a call that failed. */
.log-tool {
  color: var(--muted);
}

.log-tool.failed {
  color: var(--fail);
}

/*
 * The run's tools, folded above the log body: one line closed, and open, what
 * the run used, what its project brought, the user's own, and the built-ins.
 * Kept short so the log stays in view; the lists scroll inside.
 */
.log-tools {
  flex: none;
  border-bottom: 1px solid var(--border);
}

.log-tools > summary {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 8px 13px;
  min-height: 36px;
  cursor: pointer;
  list-style: none;
  color: var(--muted);
  font-size: 13px;
}

.log-tools > summary::-webkit-details-marker {
  display: none;
}

.log-tools > summary::before {
  content: '▸';
  transition: transform 120ms ease-out;
}

.log-tools[open] > summary::before {
  transform: rotate(90deg);
}

@media (prefers-reduced-motion: reduce) {
  .log-tools > summary::before {
    transition: none;
  }
}

.log-tools > summary:hover {
  color: var(--text);
}

.log-tools > summary:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: -2px;
}

/* The run's prompt: a line like Tools, its first line beside the heading and Copy at the right. */
.log-prompt-row {
  position: relative;
  flex: none;
}

.log-prompt-row[hidden] {
  display: none;
}

.log-prompt > summary {
  padding-right: 130px;
}

.log-prompt-note {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.log-prompt-copy {
  position: absolute;
  top: 4px;
  right: 13px;
}

.log-prompt-body {
  padding: 2px 13px 12px;
}

.log-prompt-body textarea.log-prompt-box {
  min-height: 0;
  max-height: 50vh;
  background: var(--panel);
}

.log-tools-body {
  display: grid;
  gap: 10px;
  max-height: 34vh;
  overflow: auto;
  padding: 2px 13px 12px 30px;
  font-size: 12.5px;
}

.log-tools-group h2 {
  margin: 0 0 4px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

.log-tools-group dl {
  margin: 0;
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: 3px 14px;
}

.log-tools-row {
  display: contents;
}

.log-tools-row dt {
  color: var(--muted);
  white-space: nowrap;
}

.log-tools-row dd {
  margin: 0;
  overflow-wrap: anywhere;
}

/* A status someone can act on. The label says which; the colour only points at it. */
.log-tools-row.warn dt {
  color: var(--warn);
}

.log-tools-row.bad dt {
  color: var(--fail);
}

.breadcrumb {
  color: var(--muted);
  font-size: 12.5px;
  margin-bottom: 10px;
}

.breadcrumb a:hover {
  color: var(--text);
  text-decoration: underline;
}

.toasts {
  position: fixed;
  bottom: 22px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  z-index: 30;
  pointer-events: none;
  max-width: min(560px, calc(100vw - 32px));
}

.toast {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 16px;
  font-size: 13px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
  text-align: center;
  animation: toast-in 160ms ease-out;
  transition: opacity 200ms ease, transform 200ms ease;
}

.toast.leaving {
  opacity: 0;
  transform: translateY(6px);
}

.toast.bad {
  border-color: var(--fail-edge);
  color: var(--fail);
}

@keyframes toast-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@media (max-width: 820px) {
  .logs-layout {
    grid-template-columns: minmax(0, 1fr);
  }
  table {
    font-size: 13px;
  }
  th.hide-sm,
  td.hide-sm {
    display: none;
  }
}

/* The live queue on the Settings page: what is running under the concurrent
   job limit, and what is waiting behind it. */
.queue-body {
  display: grid;
  gap: 12px;
}

.queue-list {
  display: grid;
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: 9px;
  overflow: hidden;
}

.queue-row {
  display: grid;
  grid-template-columns: 26px 1fr auto;
  align-items: center;
  gap: 12px;
  padding: 9px 12px;
  background: var(--panel);
}

/* The place in line, which is the one number the row is really about. */
.queue-pos {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--muted);
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
}

.queue-pos.running {
  border-color: transparent;
  color: var(--live);
}

.queue-when {
  color: var(--muted);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* A name that goes somewhere reads as a link; the row is not clickable itself. */
.queue-row .link:hover {
  color: var(--text);
  text-decoration: underline;
}

.login {
  max-width: 380px;
  margin: 12vh auto 0;
  padding: 0 16px;
}

.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

/*
 * The bug and suggestion dialog. Native <dialog>, so focus, Escape and the
 * backdrop come from the browser; this only dresses it like the drawer.
 */
.dialog {
  width: 480px;
  max-width: calc(100vw - 32px);
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel);
  color: var(--text);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.45);
}

.dialog::backdrop {
  background: rgba(0, 0, 0, 0.5);
}

.dialog-body {
  display: grid;
  gap: 16px;
  padding: 0 18px 18px;
}

.dialog-head {
  padding: 16px 0 0;
}

.dialog .error[hidden] {
  display: none;
}

/* ---- Memory page: what Claude Code keeps, per node --------------------- */

/* The folder list reuses the logs page's run list; these are the two lines a memory entry adds. */
.run-item .title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
}

.run-item .meta.mono {
  word-break: break-all;
}

.memory-panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px 16px;
  min-width: 0;
  display: grid;
  gap: 10px;
}

.memory-panel h2 {
  margin: 0;
}

.memory-panel .meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 8px;
  color: var(--muted);
  font-size: 12px;
  word-break: break-all;
}

/* The file as written, links made live. Monospace because the files are lists of links and one-line hooks. */
.memory-body {
  margin: 0;
  padding: 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  white-space: pre-wrap;
  word-break: break-word;
  font: 12.5px/1.55 ui-monospace, SFMono-Regular, Menlo, monospace;
  max-height: 68vh;
  overflow: auto;
}

.memory-body a {
  color: var(--focus);
  text-decoration: underline;
}

.memory-editor {
  min-height: 50vh;
  resize: vertical;
}

/* A heading between the Skills page's groups: skills, then commands by namespace. */
.skills-group {
  padding: 10px 14px 4px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--quiet);
}

.skills-form {
  display: grid;
  gap: 14px;
}

/* A project heading inside the home page's tables. */
/* Identity only, like the Server Color: a project's heading and sidebar icon. Never a state. */
[data-color="red"] { --project: #e07a80; }
[data-color="orange"] { --project: #e59a62; }
[data-color="amber"] { --project: #d9bb62; }
[data-color="green"] { --project: #74bb8c; }
[data-color="teal"] { --project: #62bcbc; }
[data-color="blue"] { --project: #74a5ec; }
[data-color="violet"] { --project: #a891ee; }
[data-color="pink"] { --project: #df8bc0; }

tr.group-row td {
  padding: 10px 14px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--muted);
  background: var(--panel-2);
  border-top: 1px solid var(--border);
  box-shadow: inset 3px 0 0 var(--project, var(--border));
}

tr.group-row[data-color] td {
  color: var(--project);
  background: color-mix(in srgb, var(--project) 10%, var(--panel-2));
}

.group-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-right: 8px;
  border-radius: 50%;
  background: var(--project, var(--muted));
  vertical-align: 1px;
}

.side-item[data-color] .side-icon {
  color: var(--project);
}

.color-swatches {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.color-swatch {
  position: relative;
  cursor: pointer;
}

.color-swatch input {
  position: absolute;
  opacity: 0;
  inset: 0;
  margin: 0;
  cursor: pointer;
}

.swatch-chip {
  display: block;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--project, transparent);
  border: 2px solid var(--project, var(--option-edge));
  box-shadow: 0 0 0 2px var(--panel);
}

.color-swatch:not([data-color]) .swatch-chip {
  background: linear-gradient(135deg, transparent 45%, var(--muted) 45%, var(--muted) 55%, transparent 55%);
}

.color-swatch input:checked + .swatch-chip {
  box-shadow: 0 0 0 2px var(--panel), 0 0 0 4px var(--text);
}

.color-swatch input:focus-visible + .swatch-chip {
  box-shadow: 0 0 0 2px var(--panel), 0 0 0 4px var(--focus);
}

tbody tr.group-row:hover {
  background: none;
}

tr.subproject-row a {
  color: inherit;
  text-decoration: none;
}

tr.subproject-row a:hover,
tr.subproject-row a:focus-visible {
  text-decoration: underline;
}

.subproject-desc {
  margin-left: 10px;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted);
}

.group-count {
  margin-left: 8px;
  font-weight: 400;
}

.project-list {
  display: grid;
  gap: 10px;
  margin-bottom: 14px;
}

.project-link-row + .project-add {
  margin-top: 8px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
}

.project-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr) 136px;
  gap: 8px;
  align-items: center;
}

@media (max-width: 820px) {
  .project-row {
    grid-template-columns: 1fr;
  }
}

/* A project on the Settings page: its name, which opens its own page, then what it is for and its folder. */
.project-link-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 12px;
  min-width: 0;
}

.project-link-row .group-dot {
  margin-right: 0;
}

.project-link-row .link {
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.project-link-row .mono {
  overflow-wrap: anywhere;
}

/*
 * The variables table on the Settings page and a computer's page: the key,
 * the value or that it is write only, the jobs that pick it, and a menu per
 * row; the button that adds one sits under it. The dialog that adds or edits
 * one is dressed as the feedback dialog is, with these two fields.
 */
.env-table {
  display: grid;
  gap: 10px;
  justify-items: start;
}

/* The border and corners go on a wrapper, since a collapsed table's cannot round; it scrolls sideways before the page does. */
.env-table-wrap {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: auto;
}

.env-table th,
.env-table td {
  padding: 8px 12px;
}

.env-table th:first-child,
.env-table td:first-child {
  padding-left: 14px;
}

.env-key {
  font-weight: 600;
  white-space: nowrap;
}

.env-current {
  overflow-wrap: anywhere;
}

.env-actions {
  width: 1%;
  text-align: right;
}

/* Three dots, not three characters wide: a target the size of a finger. */
.env-more {
  min-width: 34px;
  font-weight: 700;
  letter-spacing: 1px;
}

/* "Sensitive", beside a key or a pick's name: the same quiet pill as a default marker, in no state colour. */
.env-tag {
  display: inline-block;
  margin-left: 8px;
  font-size: 11px;
  font-weight: 400;
  line-height: 18px;
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0 8px;
  vertical-align: 1px;
}

.env-field {
  display: grid;
  gap: 4px;
}

.env-value {
  display: flex;
  align-items: center;
  gap: 8px;
}

.env-value input {
  flex: 1 1 160px;
  min-width: 0;
}

.env-field input[readonly] {
  color: var(--text-2);
}

/* What marking a variable sensitive does to the jobs that pick it: in full-strength words, since it is a consequence, not a note. */
.env-note {
  color: var(--text-2);
}

.env-note[hidden],
.env-value button[hidden] {
  display: none;
}

/* Delete in a row's menu, in the colour the Delete buttons wear. */
.split-item.danger {
  color: var(--fail);
}

/* The job form's picks: one line per name, a sensitive one's tag or a plain one's value beside it, and the agent box under a sensitive one. */
.env-picks {
  display: grid;
  gap: 8px;
}

.env-pick {
  display: grid;
  gap: 4px;
}

.env-pick .check {
  flex-wrap: wrap;
}

.env-pick .env-tag {
  margin-left: 0;
}

.env-pick-name {
  font-weight: 600;
}

.env-pick-value {
  color: var(--muted);
  overflow-wrap: anywhere;
}

.env-pick-gone {
  color: var(--warn);
  font-size: 12px;
}

/* A sensitive pick's two boxes, under its name: whether the agent sees it, and whether a run asks you for it. */
.env-pick-subs {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 18px;
  margin-left: 25px;
}

.env-pick-agent {
  font-size: 12.5px;
  color: var(--text-2);
}

/* A name the hub has no value for yet, which a run will ask you for. */
.env-add {
  display: grid;
  gap: 6px;
  margin-top: 12px;
}

.env-add-label {
  font-size: 13px;
  color: var(--text-2);
}

.env-add-row {
  display: flex;
  gap: 8px;
}

.env-add-row input {
  flex: 1;
  min-width: 0;
}

.env-check {
  margin-top: 12px;
}

.env-pick-agent input:disabled + * {
  color: var(--muted);
}

/* A project's page: Jobs and Settings, drawn as the Sort buttons are, with a folder missing named beside them. */
.project-tabs {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 18px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}

.project-tabs .btn {
  border-color: transparent;
  background: transparent;
  color: var(--muted);
}

.project-tabs .btn:hover {
  color: var(--text);
}

.project-tabs .btn[aria-current='page'] {
  border-color: var(--selected-edge);
  background: var(--selected-bg);
  color: var(--text);
  font-weight: 600;
}

.project-tab-count {
  margin-left: 6px;
  color: var(--muted);
  font-weight: 400;
  font-variant-numeric: tabular-nums;
}

.folder-missing {
  margin-left: 8px;
  font-size: 12.5px;
  color: var(--warn);
}

.folder-missing[hidden] {
  display: none;
}

.project-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 12px;
}

.project-settings {
  display: grid;
  gap: 18px;
  max-width: 640px;
}

/* Each computer's answer for the project's folder, under the field. */
.folder-computers {
  display: grid;
  gap: 4px;
  margin: 6px 0 0;
  padding: 10px 12px;
  list-style: none;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 13px;
  color: var(--text-2);
}

.folder-computers li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 10px;
  min-width: 0;
}

.folder-computers .mono {
  overflow-wrap: anywhere;
}

.folder-computer {
  flex: 0 0 auto;
  min-width: 8em;
  color: var(--text);
  overflow-wrap: anywhere;
}

.folder-warn {
  color: var(--warn);
}

.project-delete {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px 16px;
  margin-top: 12px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
}

.project-delete .sub {
  flex: 1 1 240px;
}

tr.linked-row {
  cursor: pointer;
}


/* A run's log, one box per part: preamble, execution, outcome, retrospective, stats. */
.log-box {
  margin: 0 0 12px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--border);
  border-radius: 6px;
  background: var(--panel-2);
}

.log-box:last-child {
  margin-bottom: 0;
}

.log-box-title {
  white-space: nowrap;
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 8px 12px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--muted);
}

.log-box-note {
  min-width: 0;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.log-box-text {
  margin: 0;
  padding: 0 12px 12px;
  white-space: pre-wrap;
  word-break: break-word;
  font: inherit;
}

.log-box > summary {
  cursor: pointer;
  list-style: none;
}

.log-box > summary::-webkit-details-marker {
  display: none;
}

.log-box > summary::before {
  content: '▸';
}

.log-box[open] > summary::before {
  content: '▾';
}

.log-box[open]:not(.log-preamble) > summary .log-box-note {
  display: none;
}

.log-outcome,
.log-retro {
  border-left-color: var(--warn);
}

.log-outcome.good {
  border-left-color: var(--ok);
}

.log-outcome.bad {
  border-left-color: var(--fail);
}

.log-outcome.skipped {
  border-left-color: var(--muted);
}

/* The notes a run got and left, in the run log and on the job form: plain text, as written. */
.log-notes {
  border-left-color: var(--meter);
}

.run-note {
  display: grid;
  gap: 8px;
  justify-items: start;
}

.run-note-text {
  margin: 0;
  width: 100%;
  box-sizing: border-box;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--panel-2);
  white-space: pre-wrap;
  word-break: break-word;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px;
}

/* A run's last answer, as prose: the log it sits in is monospace and keeps every space. */
.log-result {
  border-left-color: var(--live);
}

.log-result .md {
  padding: 0 16px 14px;
  font: 14px/1.6 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color: var(--text);
  white-space: normal;
}

.md > :first-child {
  margin-top: 0;
}

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

/* An agent breaks its lines on purpose, so a paragraph keeps them. */
.md p {
  margin: 0 0 10px;
  white-space: pre-line;
}

.md h3,
.md h4,
.md h5,
.md h6 {
  margin: 18px 0 8px;
  line-height: 1.3;
  font-size: 14px;
}

.md h3 {
  font-size: 17px;
}

.md h4 {
  font-size: 15px;
}

.md ul,
.md ol {
  margin: 0 0 10px;
  padding-left: 22px;
}

.md li > p {
  margin: 0 0 4px;
}

.md li > ul,
.md li > ol {
  margin: 4px 0;
}

.md code {
  padding: 1px 5px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--panel);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px;
}

.md pre {
  margin: 0 0 10px;
  padding: 10px 12px;
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--panel);
  white-space: pre;
}

.md pre code {
  padding: 0;
  border: 0;
  background: none;
}

.md blockquote {
  margin: 0 0 10px;
  padding-left: 12px;
  border-left: 3px solid var(--border);
  color: var(--text-2);
}

.md hr {
  margin: 14px 0;
  border: 0;
  border-top: 1px solid var(--border);
}

.md a {
  color: var(--text);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.md-table {
  margin: 0 0 10px;
  overflow-x: auto;
}

.md table {
  border-collapse: collapse;
  font-size: 13px;
}

.md th,
.md td {
  padding: 5px 9px;
  border: 1px solid var(--border);
  text-align: left;
  vertical-align: top;
}

.md th {
  background: var(--panel);
  font-weight: 600;
}

.log-retro .log-box-title {
  color: var(--warn);
}

.log-outcome-verdict {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 12px;
  font-weight: 600;
  white-space: normal;
}

.log-outcome ul {
  margin: 8px 0 0;
  padding: 0 12px 12px 32px;
  white-space: normal;
}

.log-box-content > .log-outcome-verdict:last-child {
  padding-bottom: 12px;
}

.log-verdict {
  display: flex;
  align-items: center;
  flex: none;
}

.log-summary {
  flex: none;
  margin: 0;
  padding: 8px 13px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
  line-height: 1.5;
}

.log-summary[hidden] {
  display: none;
}

.log-box-title,
.log-outcome-verdict,
.log-outcome ul {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

.run-status {
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-right: 8px;
  border-radius: 50%;
  vertical-align: 1px;
  background: var(--warn);
}

.run-status.good {
  background: var(--ok);
}

.run-status.bad {
  background: var(--fail);
}

/* Skipped: a check before the prompt found nothing to do. */
.run-status.skipped {
  background: var(--muted);
}

.run-status.settled {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--muted);
}

/* An updated job: the drawer's unread edge, on the row's first cell. */
html:not(.hide-updated) tbody tr.unread {
  background: var(--unread-tint);
}

html:not(.hide-updated) tbody tr.unread:hover {
  background: var(--unread-tint);
}

html:not(.hide-updated) tbody tr.unread td:first-child {
  box-shadow: inset 2px 0 0 var(--primary-bg);
}
/* Workflows: the editor beside its drawn graph. */
.workflow-layout {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(280px, 2fr);
  gap: 16px;
  align-items: start;
}

.workflow-graph-card {
  position: sticky;
  top: 16px;
}

.workflow-graph {
  width: 100%;
  height: auto;
  display: block;
}

.graph-step {
  fill: var(--panel-2);
  stroke: var(--border);
  stroke-width: 1.2;
}

.graph-step.step-claude {
  stroke: var(--meter);
}

.graph-step.step-codex {
  stroke: var(--quiet);
}

.graph-step.step-review {
  stroke: var(--quiet);
  stroke-dasharray: 4 3;
}

.graph-step.step-workflow {
  stroke: var(--accent);
}

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

.graph-kind,
.graph-end {
  fill: var(--muted);
  font-size: 11px;
}

.graph-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 10px;
  color: var(--muted);
  font-size: 12px;
}

.legend-swatch {
  display: inline-block;
  width: 10px;
  height: 3px;
  margin-right: 6px;
  vertical-align: middle;
  border-radius: 2px;
}

.workflow-steps {
  display: grid;
  gap: 12px;
  margin-bottom: 12px;
}

.workflow-step {
  display: grid;
  gap: 10px;
  padding: 12px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--meter);
  border-radius: 8px;
  background: var(--panel-2);
}

.workflow-step.step-codex {
  border-left-color: var(--quiet);
}

.workflow-step.step-shell {
  border-left-color: var(--muted);
}

.workflow-step.step-review {
  border-left-style: dashed;
  border-left-color: var(--quiet);
}

.workflow-step.step-workflow {
  border-left-color: var(--accent);
}

.workflow-step-head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto auto auto;
  gap: 8px;
  align-items: center;
}

.workflow-step-number {
  min-width: 22px;
  color: var(--muted);
  font-weight: 600;
  text-align: center;
}

.workflow-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 10px;
  align-items: start;
}

.edge-label.succeeded {
  color: var(--ok);
}

.edge-label.needs-attention {
  color: var(--warn);
}

.edge-label.failed {
  color: var(--fail);
}

.field-group {
  display: grid;
  gap: 12px;
}

.field-group[hidden] {
  display: none;
}

.log-step {
  border-left-color: var(--meter);
}

.log-step.step-shell {
  border-left-color: var(--muted);
}

.log-step.step-review {
  border-left-color: var(--quiet);
}

.log-step.step-workflow {
  border-left-color: var(--accent);
}

.log-step.good {
  border-left-color: var(--ok);
}

.log-step.bad {
  border-left-color: var(--fail);
}

.log-step.warn {
  border-left-color: var(--warn);
}

.log-step .log-outcome-verdict {
  padding-bottom: 8px;
}

@media (max-width: 820px) {
  .workflow-layout {
    grid-template-columns: 1fr;
  }
  .workflow-graph-card {
    position: static;
  }
  .workflow-step-head {
    grid-template-columns: auto minmax(0, 1fr) auto;
  }
}

/*
 * Usage: the rule a run waits by, said as one sentence. Changed for a cron,
 * the numbers open inside the sentence, which wraps between its parts.
 */
.usage-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 12px;
}

.usage-label {
  font-size: 12.5px;
  color: var(--muted);
}

.usage-state {
  font-size: 12.5px;
  color: var(--text-2);
}

.usage-head .btn {
  margin-left: auto;
}

.usage-line {
  margin: 0;
  color: var(--text);
  font-size: 14px;
}

fieldset.usage-edit {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
  color: var(--text);
  font-size: 14px;
}

fieldset.usage-edit[hidden],
.usage-line[hidden] {
  display: none;
}

.usage-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

input.usage-share {
  appearance: textfield;
  width: 3.4em;
  min-height: 36px;
  padding: 4px 6px;
  background: #12151b;
  border: 1px solid var(--control-border);
  border-radius: 6px;
  color: var(--text);
  font-size: 14px;
  text-align: center;
}

input.usage-share::-webkit-inner-spin-button,
input.usage-share::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* A plain link that does something on the page rather than going somewhere. */
.text-button {
  padding: 0;
  border: 0;
  background: none;
  color: var(--text-2);
  font: inherit;
  font-size: 12.5px;
  text-decoration: underline;
  text-decoration-color: var(--control-border);
  text-underline-offset: 3px;
  cursor: pointer;
}

.usage-head .text-button {
  margin-left: auto;
}

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

.text-button:focus-visible,
.switch:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.text-button[hidden],
.usage-head .btn[hidden] {
  display: none;
}

/* The Node field's One computer or Any with room: one choice of two, the picked one filled. */
.segmented {
  display: inline-flex;
  justify-self: start;
  width: max-content;
  margin-bottom: 8px;
  border: 1px solid var(--control-border);
  border-radius: 8px;
  overflow: hidden;
}

.segment {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 36px;
  padding: 0 14px;
  color: var(--text-2);
  font-size: 13px;
  cursor: pointer;
}

.segment + .segment {
  border-left: 1px solid var(--control-border);
}

.segment input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.segment:has(input:checked) {
  background: var(--primary-bg);
  color: var(--primary-ink);
  font-weight: 600;
}

.segment:has(input:focus-visible) {
  outline: 2px solid var(--focus);
  outline-offset: -2px;
}

.node-any {
  display: grid;
  gap: 6px;
}

.node-any[hidden],
.node-opts[hidden] {
  display: none;
}

/* Where a cron that runs anywhere would go now. */
.node-forecast {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 10px 12px;
  background: var(--panel-2);
  border: 1px solid var(--tip-border);
  border-radius: 8px;
  color: var(--text);
  font-size: 13px;
}

.node-forecast .glyph {
  flex: none;
  display: inline-flex;
  margin-top: 3px;
  color: var(--text-2);
}

/* Running or Paused, in a cron form's heading. */
.run-switch {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border: 1px solid var(--tip-border);
  border-radius: 8px;
}

.switch {
  flex: none;
  position: relative;
  width: 40px;
  height: 22px;
  padding: 0;
  border: 1px solid var(--control-border);
  border-radius: 999px;
  background: var(--track);
  cursor: pointer;
}

.switch-knob {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--muted);
  transition: left 120ms ease-out;
}

.switch[aria-checked='true'] {
  border-color: var(--primary-bg);
  background: var(--primary-bg);
}

.switch[aria-checked='true'] .switch-knob {
  left: 21px;
  background: var(--primary-ink);
}

.switch-text {
  display: grid;
  color: var(--text);
  font-size: 13.5px;
  cursor: pointer;
}

.switch-sub {
  font-size: 12px;
  color: var(--muted);
}

@media (prefers-reduced-motion: reduce) {
  .switch-knob {
    transition: none;
  }
}

@media (pointer: coarse) {
  .switch {
    width: 48px;
    height: 28px;
  }

  .switch-knob {
    top: 4px;
    width: 18px;
    height: 18px;
  }

  .switch[aria-checked='true'] .switch-knob {
    left: 24px;
  }
}

.hide-bell #bell,
.hide-updated .mark-all,
.hide-updated .updated-tag,
.hide-updated .side-count.side-dot {
  display: none;
}

/* A plugin's page fills the view below the header; the plugin draws everything inside it. */
.plugin-frame {
  display: block;
  width: 100%;
  height: calc(100vh - 140px);
  min-height: 420px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
}

/* A plugin's sidebar icon: its file is only a mask, painted in the sidebar's colour. */
.plugin-icon {
  display: inline-block;
  width: 15px;
  height: 15px;
  background: currentColor;
  -webkit-mask: center / contain no-repeat;
  mask: center / contain no-repeat;
}

/* How a plugin updates: as wide as its words, not the row. */
.select.plugin-mode {
  flex: 0 0 auto;
  padding: 5px 9px;
}

/* Each plugin in a box of its own, so its buttons, notes and form read as one. */
.plugin-rows {
  display: grid;
  gap: 12px;
}

.plugin-row {
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 8px;
}

/* A plugin's Configure form, set in under its row. */
.plugin-settings {
  margin: 8px 0 4px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel-2);
}

.plugin-list .preset-row {
  margin-bottom: 6px;
}

.plugin-cell {
  display: flex;
  align-items: center;
  gap: 6px;
}

/* Review my crons: one review on the right of its list, and each suggested schedule in it. */
.review-panel {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding-bottom: 14px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}

.review-panel > :not(.log-head) {
  margin: 0 14px;
}

.review-summary {
  line-height: 1.5;
}

.review-suggestions {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.review-suggestion {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px 14px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
}

.review-suggestion-head {
  display: flex;
  align-items: center;
  gap: 10px;
}

.review-suggestion-head .spacer {
  flex: 1;
}

.review-change {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 10px;
  align-items: baseline;
}

.review-rationale {
  margin: 0;
  color: var(--text-2);
  line-height: 1.5;
}
