/* GENERATED by demo/ade/sync.sh from Eaon ADE's renderer stylesheets.
   Do not edit by hand: change ADE, then re-run the script. */

/* ---- fonts.css ---- */
/*
 * Brand typefaces, bundled rather than fetched. The app runs offline behind a
 * strict CSP, so nothing here may reach the network.
 *
 * Inter and Instrument Serif are the Google Fonts latin subsets. JetBrains Mono
 * is the full official release, not the Google subset — the subset drops the
 * box-drawing block, and a terminal without U+2500–257F tears every CLI border
 * apart. All three are SIL Open Font License 1.1; see LEGAL.md.
 */

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 800;
  font-display: block;
  src: url('fonts/Inter-latin.woff2') format('woff2');
}

@font-face {
  font-family: 'Instrument Serif';
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url('fonts/InstrumentSerif-latin.woff2') format('woff2');
}

@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url('fonts/JetBrainsMono-Regular.woff2') format('woff2');
}

@font-face {
  font-family: 'JetBrains Mono';
  font-style: italic;
  font-weight: 400;
  font-display: block;
  src: url('fonts/JetBrainsMono-Italic.woff2') format('woff2');
}

@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 500;
  font-display: block;
  src: url('fonts/JetBrainsMono-Medium.woff2') format('woff2');
}

@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 700;
  font-display: block;
  src: url('fonts/JetBrainsMono-Bold.woff2') format('woff2');
}

/* ---- tokens.css ---- */
/*
 * Eaon design tokens.
 *
 * Everything below is a fallback for first paint — the active theme overwrites
 * these on :root at runtime (see lib/theme.ts). The values here are the default
 * "Signal" theme, so a cold start never flashes an unstyled window.
 *
 * Two colours carry meaning in every theme: --live means an agent is working,
 * --attention means it is waiting on you. Nothing else may use --attention.
 */

:root {
  /* Surfaces, back to front. */
  --ink-000: #090b0e;
  --ink-050: #0c0f13;
  --ink-100: #10141a;
  --ink-200: #14181f;
  --ink-300: #1a1f27;
  --ink-400: #222833;
  --ink-500: #2b323e;

  --line-100: #1c222a;
  --line-200: #262d37;
  --line-300: #333c48;

  --text-hi: #e9edf3;
  --text-mid: #98a3b3;
  --text-lo: #5d6776;
  --text-dim: #414b58;

  --accent: #4de1c1;
  --accent-dim: #2b8d7c;
  --accent-wash: rgba(77, 225, 193, 0.1);
  --accent-edge: rgba(77, 225, 193, 0.42);
  /* Text that sits on top of --accent. */
  --on-accent: #06110f;

  --live: #4de1c1;
  --attention: #f5a65b;
  --on-attention: #1a1105;
  --danger: #f0565c;

  /* Modal backdrop and the floating conductor / menu surface. */
  --scrim: rgba(9, 11, 14, 0.72);
  --glass: rgba(26, 31, 39, 0.94);

  /*
   * Workspace identity hues. Deliberately fixed across themes — you should be
   * able to recognise a workspace by its colour no matter how the app is
   * painted.
   */
  --hue-aqua: #4de1c1;
  --hue-azure: #5b8cff;
  --hue-violet: #a78bfa;
  --hue-amber: #f5a65b;
  --hue-rose: #f472b6;
  --hue-lime: #9fe05f;

  /* Brand constants. These never change with the theme. */
  --brand-coral: #f17455;
  --brand-ink: #0f0f0f;
  --brand-bone: #f4f2ee;
  --brand-ash: #8a8781;

  /* Type — Inter for interface, Instrument Serif for display, JetBrains Mono
     for anything that is data, code or a terminal. */
  --font-ui: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --font-display: 'Instrument Serif', Georgia, 'Times New Roman', serif;
  --font-mono: 'JetBrains Mono', 'SF Mono', ui-monospace, Menlo, Consolas, monospace;

  --fs-micro: 10px;
  --fs-label: 11px;
  --fs-sm: 12px;
  --fs-base: 13px;
  --fs-md: 15px;
  --fs-lg: 19px;
  --fs-xl: 26px;
  --fs-display: 40px;

  /* Rhythm */
  --r-sm: 5px;
  --r-md: 8px;
  --r-lg: 12px;
  --r-xl: 16px;

  --titlebar-h: 44px;
  --rail-w: 236px;
  --dock-w: 460px;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-md: 0 8px 24px -8px rgba(0, 0, 0, 0.6);
  --shadow-lg: 0 24px 64px -16px rgba(0, 0, 0, 0.72);

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --dur: 150ms;
}

/* Light themes need softer shadows or everything looks bruised. */
:root[data-mode='light'] {
  --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.08);
  --shadow-md: 0 8px 24px -8px rgba(15, 23, 42, 0.18);
  --shadow-lg: 0 24px 64px -16px rgba(15, 23, 42, 0.24);
}

.hue-aqua {
  --hue: var(--hue-aqua);
}
.hue-azure {
  --hue: var(--hue-azure);
}
.hue-violet {
  --hue: var(--hue-violet);
}
.hue-amber {
  --hue: var(--hue-amber);
}
.hue-rose {
  --hue: var(--hue-rose);
}
.hue-lime {
  --hue: var(--hue-lime);
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --dur: 1ms;
  }
}

[data-reduce-motion='true'] {
  --dur: 1ms;
}

/* ---- base.css ---- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body,
#root {
  height: 100%;
  margin: 0;
  overflow: hidden;
}

body {
  background: var(--ink-000);
  color: var(--text-hi);
  font-family: var(--font-ui);
  font-size: var(--fs-base);
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  user-select: none;
  cursor: default;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}

input,
textarea,
select {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  outline: none;
  user-select: text;
}

input::placeholder,
textarea::placeholder {
  color: var(--text-dim);
}

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

::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
::-webkit-scrollbar-track {
  background: transparent;
}
::-webkit-scrollbar-thumb {
  background: var(--ink-400);
  border: 3px solid transparent;
  background-clip: padding-box;
  border-radius: 8px;
}
::-webkit-scrollbar-thumb:hover {
  background: var(--ink-500);
  background-clip: padding-box;
}

/* ---- shared primitives ------------------------------------------------ */

.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-dim);
}

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

/* Lowercase only, Inter 800, tight. Never uppercase, never tracked out. */
.wordmark {
  font-family: var(--font-ui);
  font-weight: 800;
  letter-spacing: -0.05em;
  text-transform: lowercase;
}

.display {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: -0.02em;
}

.icon-btn {
  display: inline-grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: var(--r-sm);
  color: var(--text-lo);
  transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.icon-btn:hover {
  color: var(--text-hi);
  background: var(--ink-300);
}
.icon-btn[data-on='true'] {
  color: var(--accent);
  background: var(--accent-wash);
}
.icon-btn:disabled {
  color: var(--text-dim);
  cursor: not-allowed;
  background: none;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 34px;
  padding: 0 16px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  color: var(--text-mid);
  font-size: var(--fs-sm);
  font-weight: 500;
  white-space: nowrap;
  transition: all var(--dur) var(--ease);
}
.btn:hover {
  color: var(--text-hi);
  border-color: var(--line-300);
  background: var(--ink-300);
}
.btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.btn:disabled:hover {
  background: none;
  border-color: var(--line-200);
  color: var(--text-mid);
}

.btn-primary {
  border-color: transparent;
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 600;
}
.btn-primary:hover {
  background: var(--accent);
  border-color: transparent;
  color: var(--on-accent);
  filter: brightness(1.1);
}

.btn-ghost {
  border-color: transparent;
}
.btn-ghost:hover {
  border-color: transparent;
  background: var(--ink-300);
}

.field {
  display: flex;
  align-items: center;
  gap: 10px;
  height: 44px;
  padding: 0 14px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  background: var(--ink-100);
  transition: border-color var(--dur) var(--ease);
}
.field:focus-within {
  border-color: var(--accent-edge);
}
.field input {
  flex: 1;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 20px;
  padding: 0 7px;
  border-radius: 5px;
  background: var(--ink-300);
  color: var(--text-lo);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.04em;
  white-space: nowrap;
}

.kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 20px;
  padding: 0 6px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-200);
  background: var(--ink-200);
  color: var(--text-lo);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
}

.divider {
  height: 1px;
  background: var(--line-100);
}

.scroll {
  overflow-y: auto;
  overscroll-behavior: contain;
}

.empty {
  display: grid;
  place-items: center;
  gap: 8px;
  padding: 40px 20px;
  text-align: center;
  color: var(--text-lo);
  font-size: var(--fs-sm);
}
.empty strong {
  color: var(--text-mid);
  font-weight: 600;
}

/* ---- chrome.css ---- */
/* Application shell: title bar, workspace rail, side dock. */

.app {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--ink-000);
}

/* ---- title bar -------------------------------------------------------- */

.titlebar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 0 0 var(--titlebar-h);
  height: var(--titlebar-h);
  padding: 0 var(--titlebar-pad-right, 12px) 0 var(--titlebar-pad-left, 88px);
  background: var(--ink-100);
  border-bottom: 1px solid var(--line-100);
  -webkit-app-region: drag;
}
.titlebar button,
.titlebar input,
.titlebar .no-drag {
  -webkit-app-region: no-drag;
}

.titlebar-brand {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}
.titlebar-brand .wordmark {
  font-size: var(--fs-sm);
  color: var(--text-hi);
}
.titlebar-version {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-dim);
  letter-spacing: 0.04em;
}

.titlebar-center {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-width: 0;
  font-size: var(--fs-sm);
  color: var(--text-lo);
}
.titlebar-center .crumb-active {
  color: var(--text-mid);
  font-weight: 500;
}
.titlebar-center .crumb-path {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 340px;
}

.titlebar-actions {
  display: flex;
  align-items: center;
  gap: 2px;
}

.badge-dot {
  position: absolute;
  top: 1px;
  right: 1px;
  min-width: 14px;
  height: 14px;
  padding: 0 3px;
  border-radius: 7px;
  background: var(--attention);
  color: var(--on-attention);
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 700;
  line-height: 14px;
  text-align: center;
}
.has-badge {
  position: relative;
}

/* ---- body ------------------------------------------------------------- */

.body {
  display: flex;
  flex: 1;
  min-height: 0;
}

.stage {
  position: relative;
  flex: 1;
  min-width: 0;
  /* Both axes, deliberately. This used to sit directly in `.body`, a row, so
     only min-width mattered; inside `.stage-wrap` it is a column child, and a
     flex item defaults to min-height:auto — it will not shrink below its own
     content, so the pane grid ran off the bottom of the window. */
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: var(--ink-000);
}

/* ---- workspace rail --------------------------------------------------- */

.rail {
  flex: 0 0 var(--rail-w);
  width: var(--rail-w);
  display: flex;
  flex-direction: column;
  background: var(--ink-050);
  border-right: 1px solid var(--line-100);
}

.rail-head {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  margin-top: 6px;
  padding: 0 8px 0 10px;
}
/* Quiet, but present. Fading these in on hover read as tidier and cost more
   than it saved: an action nobody can see is an action nobody finds, and it
   left the header jumping every time the pointer crossed the rail. */
.rail-head .icon-btn {
  color: var(--text-lo);
  transition: color var(--dur) var(--ease);
}
.rail-head .icon-btn:hover,
.rail-head .icon-btn:focus-visible {
  color: var(--text-mid);
}
.rail-head .eyebrow {
  flex: 1;
}
.rail-count {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-dim);
}

.rail-list {
  flex: 1;
  min-height: 0;
  padding: 2px 8px 8px;
  overflow-y: auto;
}

.ws-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  height: 34px;
  padding: 0 8px 0 10px;
  margin-bottom: 1px;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  color: var(--text-mid);
  text-align: left;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.ws-item:hover {
  background: var(--ink-100);
  color: var(--text-hi);
}
.ws-item[data-active='true'] {
  background: var(--ink-200);
  color: var(--text-hi);
}

.ws-glyph {
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  border-radius: 4px;
  color: var(--text-lo);
  flex: 0 0 auto;
  transition: color var(--dur) var(--ease);
}
.ws-item:hover .ws-glyph,
.ws-item[data-active='true'] .ws-glyph {
  color: var(--text-mid);
}

.ws-glyph svg {
  display: block;
}
.ws-name {
  flex: 1;
  min-width: 0;
  font-size: var(--fs-sm);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ws-count {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-lo);
  font-variant-numeric: tabular-nums;
}
.ws-attention {
  min-width: 16px;
  height: 16px;
  border-radius: 8px;
  background: var(--attention);
  color: var(--on-attention);
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  padding: 0 4px;
}
.rail-foot {
  padding: 8px;
  border-top: 1px solid var(--line-100);
  display: grid;
  gap: 4px;
}

.rail-action {
  display: flex;
  align-items: center;
  gap: 11px;
  height: 32px;
  padding: 0 8px;
  border-radius: var(--r-sm);
  color: var(--text-lo);
  font-size: var(--fs-sm);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.rail-action:hover {
  background: var(--ink-100);
  color: var(--text-hi);
}
/* The last accent in the rail. Nothing here is a state you act on — the two
   colours that mean something (--live, --attention) are still on the rows
   themselves, where they say which agent needs you. */
.rail-action[data-on='true'] {
  color: var(--text-hi);
}

/* ---- side dock -------------------------------------------------------- */

.dock {
  flex: 0 0 var(--dock-w);
  width: var(--dock-w);
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: var(--ink-050);
  border-left: 1px solid var(--line-100);
}

.dock-tabs {
  display: flex;
  align-items: center;
  gap: 4px;
  height: 44px;
  padding: 0 10px;
  border-bottom: 1px solid var(--line-100);
}

.dock-tab {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 28px;
  padding: 0 11px;
  border-radius: var(--r-md);
  border: 1px solid transparent;
  color: var(--text-lo);
  font-size: var(--fs-sm);
  font-weight: 500;
  transition: all var(--dur) var(--ease);
}
.dock-tab:hover {
  color: var(--text-hi);
  background: var(--ink-200);
}
.dock-tab[data-on='true'] {
  color: var(--accent);
  background: var(--accent-wash);
  border-color: var(--accent-edge);
}
.dock-tab:disabled {
  color: var(--text-dim);
  cursor: not-allowed;
}
.dock-tab:disabled:hover {
  background: none;
}

.dock-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.dock-resizer {
  flex: 0 0 4px;
  cursor: col-resize;
  background: transparent;
  transition: background var(--dur) var(--ease);
}
.dock-resizer:hover,
.dock-resizer[data-dragging='true'] {
  background: var(--accent-edge);
}

/* ---- rail: panels alongside workspaces ---------------------------------- *
 *
 * Board, Vault and Brain live in the same list as the terminal workspaces,
 * because that is what they are now — somewhere you switch to, not a screen
 * that covers the one you were on. They are set apart by a heading and a
 * second line naming the project they are pointed at, so the list never
 * suggests a panel is holding shells.
 */

.rail-empty {
  padding: 10px 10px 0;
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--text-dim);
}

.ws-label {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1px;
}
.ws-label .ws-name {
  flex: 0 0 auto;
}

.ws-where {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ws-item[data-panel='true'] {
  height: 44px;
}

/* A panel row still reads as "a view onto a project" rather than a project,
   but by the inset tile its glyph sits in, not by colour. */
.ws-item[data-panel='true'] .ws-glyph {
  background: var(--ink-200);
  border-radius: 6px;
  width: 22px;
  height: 22px;
}

/* ---- rail folders ------------------------------------------------------- */

.ws-folder {
  border-radius: var(--r-md);
  margin-bottom: 2px;
}
/* The whole group lights up, so what you are dropping into is the block you
   are pointing at rather than a line somewhere inside it. */
.ws-folder[data-drop='true'] {
  background: var(--accent-wash);
  box-shadow: inset 0 0 0 1px var(--accent-edge);
}

.ws-folder-row {
  margin-bottom: 0;
  height: 34px;
  padding-left: 4px;
  color: var(--text-lo);
}
/* A shut folder still says one of its workspaces is the one on screen. */
.ws-folder-row[data-holding='true'] .ws-folder-glyph,
.ws-folder-row[data-holding='true'] .ws-name {
  color: var(--text-hi);
}

.ws-caret {
  display: grid;
  place-items: center;
  width: 16px;
  flex: 0 0 auto;
  color: var(--text-dim);
  transition: transform var(--dur) var(--ease);
}
.ws-caret[data-open='true'] {
  transform: rotate(90deg);
}

.ws-folder-glyph {
  color: var(--text-lo);
}

/*
 * The line down the left is what makes "inside" readable at a glance. Without
 * it an indented row is just a row that starts further along.
 */
.ws-folder-body {
  margin: 1px 0 4px 12px;
  padding-left: 8px;
  border-left: 1px solid var(--line-200);
}

.ws-folder-empty {
  margin: 2px 0 4px;
  padding: 5px 8px;
  font-size: var(--fs-micro);
  color: var(--text-dim);
}

/* Dropping onto empty space in the list is how something leaves a folder, so
   that space has to look like a target while a drag is in the air. */
.rail-list[data-drop='true'] {
  box-shadow: inset 0 0 0 1px var(--accent-edge);
  border-radius: var(--r-md);
}

.ws-item[data-nested='true'] {
  height: 34px;
}

/* Renaming happens in the row, so the field has to sit exactly where the name
   was rather than pushing the row around it. */
.ws-rename {
  flex: 1;
  min-width: 0;
  height: 22px;
  padding: 0 6px;
  border-radius: var(--r-sm);
  border: 1px solid var(--accent-edge);
  background: var(--ink-000);
  color: var(--text-hi);
  font-family: inherit;
  font-size: var(--fs-sm);
}
.ws-rename:focus {
  outline: none;
  border-color: var(--accent);
}

/*
 * Right-click menu. Positioned in viewport coordinates from the pointer, so it
 * is fixed rather than absolute — the rail scrolls, and a menu that scrolled
 * with it would drift away from the row it belongs to.
 */
.rail-menu {
  position: fixed;
  z-index: 60;
  min-width: 208px;
  max-width: 264px;
  padding: 5px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  background: var(--ink-300);
  box-shadow: var(--shadow-md);
}
.rail-menu .menu-item {
  white-space: nowrap;
  overflow: hidden;
}
.rail-menu-note {
  margin: 4px 4px 2px;
  padding: 0 5px;
  font-size: var(--fs-micro);
  line-height: 1.5;
  color: var(--text-dim);
  white-space: normal;
}

/* ---- the working indicator ---------------------------------------------- */

/*
 * A workspace with an agent mid-run says so in the rail, so a grid of eight can
 * be read without opening any of them.
 *
 * The shape is Eaon's own. The mark is a letter A drawn on a grid of rounded
 * squares with a single cell lit; this is that grid with the light going round
 * it, which is why it is squares on a grid and not the ring every other app
 * uses. Small on purpose — at 11px it sits inside the icon's footprint and
 * reads as a detail of the row rather than a thing bolted onto it.
 *
 * It wears --live, the same colour as the breathing dot on a pane header,
 * because it means the same thing. Not --attention: amber in this app is
 * reserved for "waiting on you", which is the opposite state and the one you
 * are meant to act on.
 */
.ws-glyph {
  position: relative;
}

/*
 * The icon and the grid cross over rather than swapping.
 *
 * Blur is doing the real work: without it you see two distinct shapes overlap
 * for 180ms and read it as two things trading places. Blurred, the eye takes it
 * as one thing changing form.
 */
.ws-glyph > svg,
.ws-pulse {
  transition:
    opacity 180ms var(--ease),
    transform 180ms var(--ease),
    filter 180ms var(--ease);
}
.ws-glyph[data-working='true'] > svg {
  opacity: 0;
  transform: scale(0.86);
  filter: blur(2.5px);
}

.ws-pulse {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 12px;
  height: 12px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 1fr);
  gap: 1.2px;
  opacity: 0;
  /* Never from scale(0): nothing arrives from nothing, and at this size the
     difference between 0 and 0.86 is the difference between a pop and a fade. */
  transform: scale(0.86);
  filter: blur(2.5px);
  pointer-events: none;
}
.ws-glyph[data-working='true'] .ws-pulse {
  opacity: 1;
  transform: scale(1);
  filter: blur(0);
}

.ws-pulse i {
  display: block;
  border-radius: 0.5px;
  background: var(--live);
  /* The unlit cells of the mark: dim, but plainly there. The grid has to read
     as a grid, or the travelling front has nothing to travel across. Lower
     than the ring's 0.24 — a symmetric wave spends longer near its floor than
     a comet trail did, so the same value read as a grid that never went dark. */
  opacity: 0.15;
}

/*
 * A wavefront driving left to right, not a light going round a ring.
 *
 * Each cell's delay is `(column + |row - 1|) x 90ms`: the middle row leads and
 * the outer rows trail it by one step, so the lit edge is a chevron rather than
 * a straight column. The cycle is 650ms and the sweep across three columns is
 * 270ms, so the next front sets off before the last has cleared — two are in
 * flight at once, which is what keeps it reading as continuous work instead of
 * a bar filling up.
 *
 * The centre cell animates too, unlike the ring this replaces. A chevron with
 * a hole in it is a chevron with a hole in it.
 *
 * Only opacity animates. Nine elements moving would be nine the compositor has
 * to think about on every frame of a rail that may carry a dozen rows; nine
 * fading is free.
 */
.ws-glyph[data-working='true'] .ws-pulse i {
  animation: ws-pulse 650ms ease-in-out infinite;
}

/*
 * Delays are the chevron's, minus one whole cycle.
 *
 * 650ms is subtracted from every one of them purely to make them negative. A
 * negative delay starts an animation already part-way through, so on the first
 * frame the grid is mid-sweep; the positive originals would begin with every
 * cell at its dim value and light up one at a time, which reads as loading
 * rather than as work already under way. Phase is unchanged — a delay and that
 * delay minus the duration are the same point in the cycle — so the front
 * still travels rightwards.
 *
 * Written with the full prefix on purpose: the `animation` shorthand above
 * resets animation-delay and out-specifies a bare `.ws-pulse i:nth-child()`,
 * which silently puts all nine cells in phase and turns a travelling front into
 * a grid blinking on and off together.
 */
.ws-glyph[data-working='true'] .ws-pulse i:nth-child(4) {
  animation-delay: -650ms; /* column 0, middle row — the front of the chevron */
}
.ws-glyph[data-working='true'] .ws-pulse i:nth-child(1),
.ws-glyph[data-working='true'] .ws-pulse i:nth-child(5),
.ws-glyph[data-working='true'] .ws-pulse i:nth-child(7) {
  animation-delay: -560ms;
}
.ws-glyph[data-working='true'] .ws-pulse i:nth-child(2),
.ws-glyph[data-working='true'] .ws-pulse i:nth-child(6),
.ws-glyph[data-working='true'] .ws-pulse i:nth-child(8) {
  animation-delay: -470ms;
}
.ws-glyph[data-working='true'] .ws-pulse i:nth-child(3),
.ws-glyph[data-working='true'] .ws-pulse i:nth-child(9) {
  animation-delay: -380ms;
}

/*
 * Lit and back down, symmetrically.
 *
 * The ring this replaces used a comet decay — a sharp peak trailing off — which
 * suited a single light chasing its own tail. A wavefront wants every cell to
 * rise and fall the same way, so the shape of the front is the same wherever it
 * is on the grid. `ease-in-out` on a symmetric curve is what makes the sweep
 * look like one object moving rather than nine cells taking turns.
 */
@keyframes ws-pulse {
  0%,
  100% {
    opacity: 0.15;
  }
  50% {
    opacity: 1;
  }
}

/*
 * Reduced motion keeps the signal and drops the travel. The whole grid breathes
 * together instead — the same breath a pane header already uses, so the meaning
 * survives without anything moving across the screen.
 *
 * One selector, not two: the ring this replaced held its centre cell static
 * with its own rule, so that cell needed naming here to be brought back in.
 * Every cell animates now, so `i` covers the grid.
 *
 * It ties on specificity with the per-cell delay rules above and wins on source
 * order, and the `animation` shorthand resets their animation-delay — which is
 * what stops nine staggered breaths from looking like the sweep it replaced.
 */
[data-reduce-motion='true'] .ws-glyph[data-working='true'] .ws-pulse i {
  animation: breathe 1.6s var(--ease) infinite;
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  .ws-glyph[data-working='true'] .ws-pulse i {
    animation: breathe 1.6s var(--ease) infinite;
    opacity: 1;
  }
}

/* ---- rows arriving ------------------------------------------------------ */

/*
 * A row that appears from nothing reads as a glitch. Four pixels and 200ms is
 * enough to say "this arrived" without being something you wait for — and it
 * doubles as the reveal when a folder is opened, since those rows mount then
 * too.
 */
@keyframes ws-in {
  from {
    opacity: 0;
    transform: translateY(-3px) scale(0.985);
  }
}
.ws-item {
  animation: ws-in 200ms var(--ease) both;
}
[data-reduce-motion='true'] .ws-item {
  animation: none;
}
@media (prefers-reduced-motion: reduce) {
  .ws-item {
    animation: none;
  }
}

/* Softens the drop target lighting up, so a drag across the rail does not
   strobe as the pointer crosses each folder. */
.ws-folder {
  transition:
    background 150ms var(--ease),
    box-shadow 150ms var(--ease);
}

/* ---- workspace tabs ------------------------------------------------------
 * A tab per workspace across the top of the stage. The rail is where you
 * organise; this is where you flip between the two or three you are in.
 */

.stage-wrap {
  flex: 1;
  min-width: 0;
  /* Same reason as `.stage` below: without this the wrapper grows to fit the
     grid instead of the grid being told how much room it has. */
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.ws-tabs {
  display: flex;
  align-items: center;
  gap: 4px;
  flex: 0 0 auto;
  height: 34px;
  padding: 0 6px;
  background: var(--ink-050);
  border-bottom: 1px solid var(--line-100);
}

.ws-tabs-scroll {
  display: flex;
  align-items: center;
  gap: 3px;
  flex: 1;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.ws-tabs-scroll::-webkit-scrollbar {
  display: none;
}

.ws-tab {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  max-width: 200px;
  height: 26px;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  color: var(--text-lo);
  transition:
    background var(--dur) var(--ease),
    color var(--dur) var(--ease),
    border-color var(--dur) var(--ease);
}
.ws-tab:hover {
  background: var(--ink-200);
  color: var(--text-hi);
}
.ws-tab[data-on='true'] {
  background: var(--ink-300);
  color: var(--text-hi);
  border-color: var(--line-200);
}
/* Working and waiting are the same two states the rail carries, said the same
   way — an accent edge for output, the attention colour for a decision. */
.ws-tab[data-working='true'] {
  border-color: var(--accent-edge);
}
.ws-tab[data-waiting='true'] {
  border-color: var(--attention);
}

.ws-tab-face {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  height: 100%;
  padding: 0 4px 0 9px;
  border: none;
  background: none;
  color: inherit;
  font-size: var(--fs-micro);
  cursor: pointer;
}

.ws-tab-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ws-tab-count {
  flex: 0 0 auto;
  padding: 0 4px;
  border-radius: 4px;
  background: var(--ink-400);
  color: var(--text-lo);
  font-family: var(--font-mono);
  font-size: 9px;
}

.ws-tab-close {
  display: inline-grid;
  place-items: center;
  width: 18px;
  height: 100%;
  padding: 0 7px 0 2px;
  border: none;
  background: none;
  color: var(--text-dim);
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--dur) var(--ease), color var(--dur) var(--ease);
}
.ws-tab:hover .ws-tab-close,
.ws-tab[data-on='true'] .ws-tab-close {
  opacity: 1;
}
.ws-tab-close:hover {
  color: var(--danger);
}

.ws-tab-add {
  display: inline-grid;
  place-items: center;
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  border-radius: var(--r-sm);
  border: none;
  background: none;
  color: var(--text-lo);
  cursor: pointer;
  transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.ws-tab-add:hover {
  color: var(--text-hi);
  background: var(--ink-200);
}

/*
 * The app's own surfaces, at the far right of the strip.
 *
 * Kept off the end and behind a rule so it never reads as one more tab. Tabs
 * are this project's, they come and go, and they carry the project's colour;
 * these four are always the same four and are the same on every project — so
 * they are quiet, glyph-only, and out of the way until wanted.
 */
.ws-places {
  display: inline-flex;
  align-items: center;
  gap: 1px;
  flex: 0 0 auto;
  margin-left: 4px;
  padding-left: 5px;
  border-left: 1px solid var(--line-100);
}

.ws-place {
  display: inline-grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: var(--r-sm);
  border: none;
  background: none;
  color: var(--text-lo);
  cursor: pointer;
  transition:
    color var(--dur) var(--ease),
    background var(--dur) var(--ease);
}
.ws-place:hover {
  color: var(--text-hi);
  background: var(--ink-200);
}
/* Where you are. The same treatment the selected tab gets, so "the stage is
   showing this" looks the same whichever half of the strip it is in. */
.ws-place[data-on='true'] {
  color: var(--text-hi);
  background: var(--ink-200);
}
.ws-place:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--accent-wash);
}

/* ---- rail destinations ---------------------------------------------------
 * The named places, above the project list. Rows are 34pt with a 15pt glyph
 * and a 12pt gap, which is what makes a label read as a destination rather
 * than as one more item in a list — the project rows below are deliberately
 * tighter and carry a colour, so the two blocks never look like one list.
 */

.rail-new {
  display: flex;
  align-items: center;
  gap: 10px;
  width: calc(100% - 16px);
  height: 34px;
  margin: 8px 8px 6px;
  padding: 0 7px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-100);
  background: transparent;
  color: var(--text-mid);
  font-size: var(--fs-sm);
  cursor: pointer;
  transition:
    background var(--dur) var(--ease),
    border-color var(--dur) var(--ease),
    color var(--dur) var(--ease);
}
.rail-new:hover {
  background: var(--ink-100);
  border-color: var(--line-200);
  color: var(--text-hi);
}

.rail-new-glyph {
  display: inline-grid;
  place-items: center;
  width: 20px;
  height: 20px;
  border-radius: 4px;
  background: var(--ink-200);
  color: var(--text-lo);
  transition: color var(--dur) var(--ease);
}
.rail-new:hover .rail-new-glyph {
  color: var(--text-mid);
}

.rail-dests {
  display: flex;
  flex-direction: column;
  padding: 2px 8px 4px;
}

.rail-dest {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  height: 34px;
  padding: 0 8px;
  margin-bottom: 1px;
  border-radius: var(--r-sm);
  border: none;
  background: none;
  color: var(--text-mid);
  font-size: var(--fs-sm);
  text-align: left;
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.rail-dest:hover {
  background: var(--ink-100);
  color: var(--text-hi);
}
.rail-dest[data-on='true'] {
  background: var(--ink-200);
  color: var(--text-hi);
}
.rail-dest svg {
  flex: 0 0 auto;
  color: var(--text-lo);
  transition: color var(--dur) var(--ease);
}

.rail-dest:hover svg,
.rail-dest[data-on='true'] svg {
  color: var(--text-mid);
}

/* The project the strip belongs to, so a row of tabs never reads as a row of
   unrelated things. Tabs are scoped to one project and never span two. */
.ws-tabs-project {
  flex: 0 0 auto;
  padding: 0 10px 0 4px;
  margin-right: 4px;
  border-right: 1px solid var(--line-100);
  color: var(--text-lo);
  font-size: var(--fs-micro);
  font-weight: 600;
  white-space: nowrap;
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Marks a tab that owns its own worktree — its files are its own. The first
   tab of a project works in the repository itself and carries no branch. */
.ws-tab-branch {
  display: inline-grid;
  place-items: center;
  flex: 0 0 auto;
  color: var(--text-dim);
}
.ws-tab[data-on='true'] .ws-tab-branch {
  color: var(--accent);
}

.ws-tab-add:disabled {
  opacity: 0.5;
  cursor: default;
}

/* ---- the project's branch, in the tab strip ------------------------------
 * Beside the project name, not on a tab: every tab of a project shares one
 * folder and therefore one branch, and switching moves all of them at once.
 */

.ws-branch-wrap {
  position: relative;
  flex: 0 0 auto;
  display: inline-flex;
}

.ws-branch {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 22px;
  max-width: 190px;
  padding: 0 7px;
  margin-right: 6px;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  background: none;
  color: var(--text-lo);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.ws-branch:hover:not(:disabled) {
  background: var(--ink-200);
  color: var(--text-hi);
}
.ws-branch:disabled {
  opacity: 0.6;
  cursor: default;
}

.ws-branch-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Catches the click that closes the menu, without stealing the first click
   from whatever is underneath the way a full-screen overlay would. */
.ws-branch-scrim {
  position: fixed;
  inset: 0;
  z-index: 40;
}

.ws-branch-menu {
  position: absolute;
  top: 26px;
  left: 0;
  z-index: 41;
  display: flex;
  flex-direction: column;
  min-width: 190px;
  max-height: 300px;
  overflow-y: auto;
  padding: 4px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  background: var(--ink-200);
  box-shadow: var(--shadow-pop, 0 12px 28px rgba(0, 0, 0, 0.32));
}

.ws-branch-item {
  display: flex;
  align-items: center;
  gap: 7px;
  height: 26px;
  padding: 0 8px;
  border: none;
  border-radius: var(--r-sm);
  background: none;
  color: var(--text-mid);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  text-align: left;
  cursor: pointer;
  white-space: nowrap;
}
.ws-branch-item:hover {
  background: var(--ink-300);
  color: var(--text-hi);
}
.ws-branch-item[data-on='true'] {
  color: var(--accent);
}

.ws-branch-note {
  padding: 6px 8px;
  color: var(--text-dim);
  font-size: var(--fs-micro);
}

/* A browser tab, held in the stage whether or not it is the tab in front.
   `hidden` rather than unmounted: re-attaching a <webview> reloads its page. */
.stage-slot {
  position: absolute;
  inset: 0;
  display: flex;
  min-height: 0;
}
.stage-slot[hidden] {
  display: none;
}

/* ---- surfaces.css ---- */
/* Launcher, setup wizard, board and vault. */

.surface-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

.surface-inner {
  width: min(880px, 100%);
  margin: 0 auto;
  padding: 56px 32px 72px;
}

/* ---- launcher --------------------------------------------------------- */

.launcher {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
}

.launcher-mark {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 34px;
}
.launcher-mark .wordmark {
  font-size: 46px;
  line-height: 1;
  color: var(--text-hi);
}

.launcher-head {
  font-family: var(--font-display);
  font-size: 54px;
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--text-hi);
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: 4px;
}
.launcher-caret {
  display: inline-block;
  width: 0.5em;
  height: 0.85em;
  background: var(--accent);
  transform: translateY(0.06em);
  animation: caret 1.15s steps(1, end) infinite;
}
@keyframes caret {
  0%,
  50% {
    opacity: 1;
  }
  50.01%,
  100% {
    opacity: 0;
  }
}
[data-reduce-motion='true'] .launcher-caret {
  animation: none;
}

.launcher-sub {
  margin: 14px 0 40px;
  color: var(--text-lo);
  font-size: var(--fs-md);
}

.modes {
  display: grid;
  gap: 10px;
  width: 100%;
  max-width: 620px;
}

.mode-card {
  position: relative;
  display: grid;
  grid-template-columns: 40px 1fr auto;
  align-items: center;
  gap: 16px;
  padding: 18px 18px 18px 16px;
  border-radius: var(--r-lg);
  border: 1px solid var(--line-100);
  background: var(--ink-100);
  text-align: left;
  overflow: hidden;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}
.mode-card::before {
  content: '';
  position: absolute;
  inset: 0 auto 0 0;
  width: 2px;
  background: var(--accent);
  transform: scaleY(0);
  transform-origin: center;
  transition: transform 220ms var(--ease);
}
.mode-card:hover,
.mode-card:focus-visible {
  border-color: var(--line-300);
  background: var(--ink-200);
  transform: translateY(-1px);
}
.mode-card:hover::before,
.mode-card:focus-visible::before {
  transform: scaleY(1);
}
.mode-card:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.mode-card:disabled:hover {
  transform: none;
  background: var(--ink-100);
  border-color: var(--line-100);
}

.mode-glyph {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  background: var(--ink-200);
  color: var(--text-mid);
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.mode-card:hover .mode-glyph {
  color: var(--accent);
  border-color: var(--accent-edge);
}

.mode-text {
  display: block;
  min-width: 0;
}
.mode-name {
  display: block;
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--text-hi);
  letter-spacing: -0.01em;
}
.mode-desc {
  display: block;
  margin-top: 3px;
  font-size: var(--fs-sm);
  color: var(--text-dim);
  transition: color var(--dur) var(--ease);
}
.mode-card:hover .mode-desc {
  color: var(--text-lo);
}

.launcher-hints {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px 22px;
  margin-top: 44px;
  color: var(--text-dim);
}
.launcher-hint {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: var(--fs-micro);
  font-family: var(--font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* ---- stepper ---------------------------------------------------------- */

.stepper {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0;
  margin-bottom: 38px;
}
.step {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: var(--text-dim);
  font-size: var(--fs-sm);
  font-weight: 500;
}
.step[data-state='current'] {
  color: var(--text-hi);
}
.step[data-state='done'] {
  color: var(--text-lo);
}
.step-num {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1px solid var(--line-200);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
}
.step[data-state='current'] .step-num {
  border-color: var(--accent);
  color: var(--accent);
}
.step[data-state='done'] .step-num {
  border-color: var(--accent-edge);
  background: var(--accent-wash);
  color: var(--accent);
}
.step-rule {
  width: 68px;
  height: 1px;
  margin: 0 14px;
  background: var(--line-200);
}
.step-rule[data-done='true'] {
  background: var(--accent-dim);
}

/* ---- wizard ----------------------------------------------------------- */

.wizard-head {
  text-align: center;
  margin-bottom: 34px;
}
.wizard-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 34px;
  font-weight: 400;
  letter-spacing: -0.02em;
  color: var(--text-hi);
}
.wizard-sub {
  margin: 8px 0 0;
  color: var(--text-lo);
  font-size: var(--fs-base);
}

.section {
  margin-bottom: 30px;
}
.section-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 12px;
}
.section-title {
  font-size: var(--fs-base);
  font-weight: 600;
  color: var(--text-hi);
}
.section-note {
  font-size: var(--fs-sm);
  color: var(--text-dim);
}
.section-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
}

.layout-tiles {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 8px;
}
.layout-tile {
  display: grid;
  place-items: center;
  gap: 10px;
  padding: 16px 6px 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-100);
  background: var(--ink-100);
  color: var(--text-lo);
  transition: all var(--dur) var(--ease);
}
.layout-tile:hover {
  border-color: var(--line-300);
  background: var(--ink-200);
  color: var(--text-mid);
}
.layout-tile[data-on='true'] {
  border-color: var(--accent);
  background: var(--accent-wash);
  color: var(--accent);
}
.layout-tile-n {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
}
.tile-preview {
  display: grid;
  gap: 2px;
  width: 34px;
}
.tile-cell {
  height: 5px;
  border-radius: 1px;
  background: currentColor;
  opacity: 0.32;
}
.layout-tile[data-on='true'] .tile-cell {
  opacity: 1;
}

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

.folder-card {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 11px 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-100);
  background: var(--ink-100);
  text-align: left;
  transition: all var(--dur) var(--ease);
}
.folder-card:hover {
  border-color: var(--line-300);
  background: var(--ink-200);
}
.folder-card[data-on='true'] {
  border-color: var(--accent-edge);
  background: var(--accent-wash);
}
.folder-card svg {
  color: var(--text-dim);
  flex: 0 0 auto;
}
.folder-card:hover svg {
  color: var(--accent);
}
.folder-text {
  display: block;
  min-width: 0;
  flex: 1;
}
.folder-name {
  display: block;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text-hi);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.folder-path {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  direction: rtl;
  text-align: left;
}

.preset-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.preset-chip {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  height: 34px;
  padding: 0 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-100);
  background: var(--ink-100);
  color: var(--text-mid);
  font-size: var(--fs-sm);
  transition: all var(--dur) var(--ease);
}
.preset-chip:hover {
  border-color: var(--line-300);
  color: var(--text-hi);
  background: var(--ink-200);
}
.preset-chip[data-on='true'] {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-wash);
}
.preset-chip .preset-edit {
  color: var(--text-dim);
  display: grid;
  place-items: center;
}
.preset-chip .preset-edit:hover {
  color: var(--text-hi);
}
.preset-chip-new {
  border-style: dashed;
}

.mini-grid {
  display: grid;
  gap: 1.5px;
  width: 15px;
  flex: 0 0 auto;
}
.mini-grid i {
  height: 3px;
  border-radius: 1px;
  background: currentColor;
  opacity: 0.45;
}

.agent-list {
  display: grid;
  gap: 8px;
}
.agent-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-100);
  background: var(--ink-100);
  text-align: left;
  width: 100%;
  transition: all var(--dur) var(--ease);
}
.agent-row:hover {
  border-color: var(--line-300);
  background: var(--ink-200);
}
.agent-row[data-on='true'] {
  border-color: var(--accent);
  background: var(--accent-wash);
}
.agent-row:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.agent-mark {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-200);
  background: var(--ink-200);
  color: var(--text-mid);
  flex: 0 0 auto;
}
.agent-row[data-on='true'] .agent-mark {
  color: var(--accent);
  border-color: var(--accent-edge);
}
/* A brand mark holds its colour at the row's 45% opacity and can still read as
   available. Draining it says "not on this machine" the way the greyed name
   and the `not found on PATH` line already do. */
.agent-row:disabled .agent-mark {
  filter: grayscale(1);
}
.agent-meta {
  display: block;
  flex: 1;
  min-width: 0;
}
.agent-name {
  display: block;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-hi);
}
.agent-blurb {
  display: block;
  font-size: var(--fs-micro);
  color: var(--text-dim);
  margin-top: 2px;
}

.prompt-box {
  width: 100%;
  min-height: 84px;
  padding: 12px 14px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  background: var(--ink-100);
  color: var(--text-hi);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  line-height: 1.6;
  resize: vertical;
  transition: border-color var(--dur) var(--ease);
}
.prompt-box:focus {
  border-color: var(--accent-edge);
}

.wizard-foot {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-top: 22px;
  margin-top: 8px;
  border-top: 1px solid var(--line-100);
}
.wizard-foot .spacer {
  flex: 1;
}

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

.board-cols {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
  align-items: start;
}
.board-col {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px;
  border-radius: var(--r-lg);
  border: 1px solid var(--line-100);
  background: var(--ink-050);
  min-height: 180px;
}
.board-col-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 2px 4px 6px;
}
.board-col-head .eyebrow {
  flex: 1;
}
.board-card {
  padding: 11px 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  background: var(--ink-100);
  cursor: grab;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.board-card:hover {
  border-color: var(--line-300);
  background: var(--ink-200);
}
.board-card[data-dragging='true'] {
  opacity: 0.4;
}
.board-col[data-over='true'] {
  border-color: var(--accent-edge);
  background: var(--accent-wash);
}
.board-card-title {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text-hi);
  word-break: break-word;
}
.board-card-foot {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 9px;
}

/* ---- vault ------------------------------------------------------------ */

.vault-layout {
  display: grid;
  grid-template-columns: 240px 1fr;
  gap: 14px;
  min-height: 420px;
}
.vault-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-right: 4px;
  border-right: 1px solid var(--line-100);
}
.vault-item {
  padding: 9px 10px;
  border-radius: var(--r-md);
  border: 1px solid transparent;
  text-align: left;
  color: var(--text-mid);
  transition: all var(--dur) var(--ease);
}
.vault-item:hover {
  background: var(--ink-100);
  color: var(--text-hi);
}
.vault-item[data-on='true'] {
  background: var(--ink-200);
  border-color: var(--line-200);
  color: var(--text-hi);
}
.vault-item-title {
  font-size: var(--fs-sm);
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.vault-item-when {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-dim);
  margin-top: 2px;
}
.vault-editor {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}
.vault-title-input {
  width: 100%;
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--text-hi);
  padding: 4px 0;
  border-bottom: 1px solid var(--line-100);
}
.vault-body-input {
  flex: 1;
  min-height: 320px;
  width: 100%;
  padding: 12px 0;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  line-height: 1.7;
  color: var(--text-mid);
  resize: none;
}

/* ---- grid.css ---- */
/* Terminal grid, panes, the pulse spine and the conductor dock. */

/* Holds the trial strip above the grid, when there is one. */
.grid-wrap {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

.grid-stage {
  position: relative;
  flex: 1;
  min-height: 0;
  padding: 6px;
}
/* Keep the conductor off the bottom row instead of floating over output. */
.grid-stage[data-conductor='true'] {
  padding-bottom: 64px;
}

.grid {
  display: grid;
  height: 100%;
}
/*
 * No `gap`. The space between panes is a track of its own, holding the divider
 * you drag — which is what keeps the divider exactly on the seam without
 * anything having to measure where the seam is.
 */
.grid[data-zoomed='true'] {
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
}

/* ---- dividers ---------------------------------------------------------- */

/*
 * The seam between two panes.
 *
 * Invisible until it is worth noticing. The grid already reads as separated —
 * every pane has its own border — so a line drawn down the middle of the gap
 * would be a second border saying the same thing. What the seam adds is a
 * larger place to aim at than the six pixels it occupies, which is why it
 * reaches past its own track.
 */
.pane-seam {
  position: relative;
  z-index: 2;
}
.pane-seam[data-axis='cols'] {
  cursor: col-resize;
}
.pane-seam[data-axis='rows'] {
  cursor: row-resize;
}

/* The part you can actually hit: wider than the seam, centred on it. */
.pane-seam::before {
  content: '';
  position: absolute;
  inset: 0;
}
.pane-seam[data-axis='cols']::before {
  left: -3px;
  right: -3px;
}
.pane-seam[data-axis='rows']::before {
  top: -3px;
  bottom: -3px;
}

/* And the part you can see, which only appears once you are on it. */
.pane-seam::after {
  content: '';
  position: absolute;
  border-radius: 999px;
  background: var(--accent);
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}
.pane-seam[data-axis='cols']::after {
  top: 22%;
  bottom: 22%;
  left: 2px;
  right: 2px;
}
.pane-seam[data-axis='rows']::after {
  left: 22%;
  right: 22%;
  top: 2px;
  bottom: 2px;
}
.pane-seam:hover::after,
.pane-seam[data-dragging='true']::after {
  opacity: 1;
}

/*
 * The single track where a column seam and a row seam cross. Both of those
 * already reach across this point (a column seam runs the full height, a row
 * seam the full width), so without this a press here would always resolve to
 * whichever was last in the DOM. Sits above both; which axis it resizes
 * follows the direction actually dragged, decided in PaneGrid.tsx.
 */
.pane-seam-corner {
  position: relative;
  z-index: 3;
  cursor: move;
}
.pane-seam-corner::before {
  content: '';
  position: absolute;
  inset: -3px;
}
.pane-seam-corner::after {
  content: '';
  position: absolute;
  inset: 2px;
  border-radius: 999px;
  background: var(--accent);
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}
.pane-seam-corner:hover::after {
  opacity: 1;
}

/* While a divider is moving, the pointer belongs to it and nothing else. */
.grid[data-dragging='true'] {
  user-select: none;
}
.grid[data-dragging='true'] .pane-term {
  pointer-events: none;
}

/* ---- carrying a pane --------------------------------------------------- */

/* The one being carried stays where it is, lightened, so the grid does not
   rearrange itself under the pointer mid-drag. */
.pane[data-carrying='true'] {
  opacity: 0.4;
}
/* The one it would trade places with. */
.pane[data-over='true'] {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent-edge), 0 0 28px -12px var(--accent);
}
.pane-head {
  cursor: grab;
}
.grid[data-carrying='true'] .pane-head {
  cursor: grabbing;
}

/* ---- pane ------------------------------------------------------------- */

.pane {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  border-radius: var(--r-md);
  border: 1px solid var(--line-100);
  background: var(--ink-200);
  overflow: hidden;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.pane[data-active='true'] {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent-edge), 0 0 28px -12px var(--accent);
}
.pane[data-status='attention'] {
  border-color: var(--attention);
}
.pane[data-status='attention'][data-active='true'] {
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--attention) 50%, transparent),
    0 0 28px -12px var(--attention);
}
.pane[data-status='exited'] {
  opacity: 0.72;
}

.pane-head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 30px;
  height: 30px;
  padding: 0 5px 0 10px;
  background: var(--ink-100);
  border-bottom: 1px solid var(--line-100);
  cursor: default;
}

.pane-dot {
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--text-dim);
}

/* ---- preview / diff panes: SurfacePaneChrome --------------------------- */

.pane-surface-icon {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  color: var(--text-dim);
}

.pane-surface-body {
  flex: 1;
  min-height: 0;
  display: flex;
  overflow: hidden;
}

/* GitPanel expects height:100% from a flex/definite-height parent. */
.pane-surface-fill {
  flex: 1;
  min-height: 0;
  min-width: 0;
  display: flex;
  overflow: hidden;
}
.pane[data-status='live'] .pane-dot {
  background: var(--live);
  animation: breathe 1.5s var(--ease) infinite;
}
.pane[data-status='attention'] .pane-dot {
  background: var(--attention);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--attention) 20%, transparent);
}
.pane[data-status='exited'] .pane-dot {
  background: var(--danger);
}
@keyframes breathe {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.35;
  }
}
[data-reduce-motion='true'] .pane-dot {
  animation: none !important;
}

.pane-index {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--text-dim);
  flex: 0 0 auto;
}

.pane-label {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: baseline;
  gap: 7px;
  overflow: hidden;
}
.pane-name {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-hi);
  letter-spacing: -0.005em;
  flex: 0 0 auto;
}
.pane-title {
  font-size: var(--fs-micro);
  color: var(--text-lo);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.pane-context {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 18px;
  padding: 0 7px 0 6px;
  border-radius: 9px;
  background: var(--ink-300);
  flex: 0 0 auto;
}
.pane-context-bar {
  width: 26px;
  height: 3px;
  border-radius: 2px;
  background: var(--ink-500);
  overflow: hidden;
}
.pane-context-fill {
  height: 100%;
  border-radius: 2px;
  background: var(--accent);
  transition: width 400ms var(--ease);
}
.pane-context[data-low='true'] .pane-context-fill {
  background: var(--attention);
}
.pane-context-num {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--text-mid);
}

.pane-branch {
  max-width: 120px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pane-tools {
  display: flex;
  align-items: center;
  gap: 1px;
  flex: 0 0 auto;
}
.pane-tools .icon-btn {
  width: 22px;
  height: 22px;
  color: var(--text-dim);
}
.pane-tools .icon-btn:hover {
  color: var(--text-hi);
  background: var(--ink-300);
}
.pane-tools .pane-kill:hover {
  color: var(--danger);
}

.pane-term {
  flex: 1;
  min-height: 0;
  position: relative;
  padding: 4px 2px 2px 6px;
  overflow: hidden;
}
.pane-term .xterm {
  height: 100%;
}
.pane-term .xterm-viewport {
  overflow-y: auto !important;
  background: transparent !important;
}
.pane-term .xterm-viewport::-webkit-scrollbar {
  width: 8px;
}

/* Transient grid size, the way a terminal shows it while you drag. */
.pane-size {
  position: absolute;
  right: 10px;
  bottom: 8px;
  z-index: 6;
  padding: 3px 8px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-200);
  background: var(--glass);
  color: var(--text-mid);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  pointer-events: none;
  animation: fade 100ms var(--ease);
}

/* Sits under the context menu so the next click anywhere dismisses it. */
.context-catcher {
  position: fixed;
  inset: 0;
  z-index: 19;
}

.pane-overlay {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  gap: 12px;
  background: rgba(9, 11, 14, 0.86);
  backdrop-filter: blur(2px);
  z-index: 4;
  padding: 20px;
  text-align: center;
}
.pane-overlay-msg {
  font-size: var(--fs-sm);
  color: var(--text-mid);
}

.pane-menu {
  position: absolute;
  top: 30px;
  right: 6px;
  z-index: 20;
  min-width: 196px;
  padding: 5px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  background: var(--ink-300);
  box-shadow: var(--shadow-md);
}
.menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  height: 30px;
  padding: 0 9px;
  border-radius: var(--r-sm);
  color: var(--text-mid);
  font-size: var(--fs-sm);
  text-align: left;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.menu-item:hover {
  background: var(--ink-400);
  color: var(--text-hi);
}
.menu-item .kbd {
  margin-left: auto;
}
.menu-item[data-danger='true']:hover {
  color: var(--danger);
}
.menu-sep {
  height: 1px;
  margin: 4px 6px;
  background: var(--line-200);
}

/* ---- pane search ------------------------------------------------------ */

.pane-find {
  position: absolute;
  top: 48px;
  right: 8px;
  z-index: 15;
  display: flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  padding: 0 6px 0 10px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  background: var(--ink-300);
  box-shadow: var(--shadow-md);
}
.pane-find input {
  width: 150px;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
}

/* ---- conductor dock --------------------------------------------------- */

.conductor {
  position: absolute;
  left: 50%;
  bottom: 12px;
  transform: translateX(-50%);
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 8px;
  width: min(720px, calc(100% - 48px));
  padding: 8px 8px 8px 12px;
  border-radius: 999px;
  border: 1px solid var(--line-200);
  background: var(--glass);
  backdrop-filter: blur(18px);
  box-shadow: var(--shadow-lg);
}
.conductor[data-expanded='true'] {
  border-radius: var(--r-lg);
  flex-direction: column;
  align-items: stretch;
  padding: 10px;
}

.conductor-orb {
  position: relative;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 1px solid var(--accent-edge);
  background: var(--accent-wash);
  color: var(--accent);
  flex: 0 0 auto;
}

.conductor-target {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 26px;
  padding: 0 10px;
  border-radius: 999px;
  border: 1px solid var(--line-200);
  background: var(--ink-200);
  color: var(--text-mid);
  font-size: var(--fs-micro);
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
  white-space: nowrap;
  flex: 0 0 auto;
  transition: all var(--dur) var(--ease);
}
.conductor-target:hover {
  color: var(--text-hi);
  border-color: var(--line-300);
}

.conductor-input {
  flex: 1;
  min-width: 0;
  height: 28px;
  font-size: var(--fs-base);
  color: var(--text-hi);
}

.conductor-row {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
}

.conductor-multi {
  width: 100%;
  min-height: 76px;
  max-height: 220px;
  padding: 8px 4px;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  line-height: 1.6;
  color: var(--text-hi);
  resize: none;
}

.conductor-send {
  display: inline-grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--on-accent);
  flex: 0 0 auto;
  transition: filter var(--dur) var(--ease);
}
.conductor-send:hover {
  filter: brightness(1.12);
}
.conductor-send:disabled {
  background: var(--ink-400);
  color: var(--text-dim);
  cursor: not-allowed;
}

.target-menu {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 44px;
  z-index: 40;
  min-width: 210px;
  max-height: 300px;
  overflow-y: auto;
  padding: 5px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  background: var(--ink-300);
  box-shadow: var(--shadow-md);
}

/* ---- dropping a file onto a pane ---------------------------------------- *
 *
 * The whole pane lights rather than a strip or a badge: the question a drag
 * asks is "which of these twelve gets it?", and only the outline of the target
 * answers that from the corner of your eye.
 */
.pane[data-dropping='true']::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
  border-radius: inherit;
  border: 1.5px dashed var(--accent-edge);
  background: var(--accent-wash);
}

.pane[data-dropping='true'] .pane-head {
  color: var(--accent);
}

/* Reached by keyboard, the seam has to show where it is — there is no pointer
   sitting on it to make it visible. */
.pane-seam:focus-visible {
  outline: none;
}
.pane-seam:focus-visible::after {
  opacity: 1;
  box-shadow: 0 0 0 2px var(--accent-wash);
}

/* ---- the agent in a pane header ------------------------------------------
 * The mark sits between the pane's number and its handle, so a row of panes
 * reads "which agent, then which one of them" left to right. The mark keeps
 * its own brand colour and is never recoloured by theme or status — the dot
 * to its left already carries status, and a logo tinted by state stops being
 * a logo.
 */

.pane-agent {
  display: inline-grid;
  place-items: center;
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
}

/* Shown only when the agent has not set a title of its own — a real title is
   always more specific than the agent's name, so it wins the slot. */
.pane-agent-name {
  color: var(--text-dim);
  font-size: var(--fs-micro);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---- overlays.css ---- */
/* Modals, command palette, notifications and the dock panels. */

.scrim {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  background: var(--scrim);
  backdrop-filter: blur(3px);
  animation: fade 120ms var(--ease);
}
.scrim[data-align='top'] {
  align-content: start;
  justify-content: center;
  padding-top: 13vh;
}
.scrim[data-align='center'] {
  place-content: center;
  padding: 24px;
}
@keyframes fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.modal {
  width: min(560px, calc(100vw - 48px));
  max-height: min(76vh, 720px);
  display: flex;
  flex-direction: column;
  border-radius: var(--r-xl);
  border: 1px solid var(--line-200);
  background: var(--ink-100);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  animation: rise 160ms var(--ease);
}
.modal-wide {
  width: min(760px, calc(100vw - 48px));
}
@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(6px) scale(0.99);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
[data-reduce-motion='true'] .modal,
[data-reduce-motion='true'] .scrim {
  animation: none;
}

.modal-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 16px 14px;
  border-bottom: 1px solid var(--line-100);
}
.modal-mark {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: var(--r-md);
  border: 1px solid var(--accent-edge);
  background: var(--accent-wash);
  color: var(--accent);
  flex: 0 0 auto;
}
.modal-titles {
  flex: 1;
  min-width: 0;
}
.modal-title {
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--text-hi);
}
.modal-sub {
  font-size: var(--fs-sm);
  color: var(--text-lo);
  margin-top: 1px;
}
.modal-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 14px 16px;
}
.modal-foot {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
  border-top: 1px solid var(--line-100);
  background: var(--ink-050);
}
.modal-foot .spacer {
  flex: 1;
}
.modal-foot-note {
  font-size: var(--fs-sm);
  color: var(--text-dim);
}

/* ---- command palette -------------------------------------------------- */

.palette {
  width: min(600px, calc(100vw - 48px));
  border-radius: var(--r-lg);
  border: 1px solid var(--line-200);
  background: var(--ink-100);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  animation: rise 140ms var(--ease);
}
.palette-input-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 14px;
  height: 50px;
  border-bottom: 1px solid var(--line-100);
}
.palette-input-row input {
  flex: 1;
  font-size: var(--fs-md);
}
.palette-list {
  max-height: 380px;
  overflow-y: auto;
  padding: 6px;
}
.palette-item {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  height: 36px;
  padding: 0 10px;
  border-radius: var(--r-md);
  color: var(--text-mid);
  text-align: left;
  transition: background 80ms var(--ease);
}
.palette-item[data-on='true'] {
  background: var(--ink-300);
  color: var(--text-hi);
}
.palette-item svg {
  color: var(--text-dim);
  flex: 0 0 auto;
}
.palette-item[data-on='true'] svg {
  color: var(--accent);
}
.palette-item-label {
  flex: 1;
  min-width: 0;
  font-size: var(--fs-sm);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.palette-item-hint {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-dim);
}
.palette-group {
  padding: 10px 10px 5px;
}

/* ---- resume dialog ---------------------------------------------------- */

/* Folder / everywhere switch, sitting in the dialog head. */
.resume-scope {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-100);
  background: var(--ink-050);
}

.resume-scope-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 24px;
  padding: 0 9px;
  border: 0;
  border-radius: calc(var(--r-md) - 3px);
  background: transparent;
  color: var(--text-lo);
  font-size: 11.5px;
  font-family: var(--font-ui);
  cursor: pointer;
  white-space: nowrap;
}

.resume-scope-btn:hover {
  color: var(--text-hi);
}

.resume-scope-btn[data-on='true'] {
  background: var(--ink-200);
  color: var(--text-hi);
}

.resume-scope-n {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-lo);
}

.resume-scope-btn[data-on='true'] .resume-scope-n {
  color: var(--accent);
}

.resume-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-100);
  background: var(--ink-050);
  margin-bottom: 7px;
}
.resume-item:hover {
  border-color: var(--line-200);
}
.resume-meta {
  flex: 1;
  min-width: 0;
}
.resume-top {
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.resume-tool {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-hi);
}
.resume-when {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-dim);
  margin-left: auto;
}
.resume-label {
  font-size: var(--fs-micro);
  color: var(--text-lo);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-top: 2px;
}
.resume-cmd {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 7px;
  padding: 5px 8px;
  border-radius: var(--r-sm);
  background: var(--ink-200);
  border: 1px solid var(--line-100);
}
.resume-cmd code {
  flex: 1;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-mid);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  user-select: text;
}

/* ---- notifications ---------------------------------------------------- */

.notices {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 60;
  width: 320px;
  display: grid;
  gap: 6px;
  pointer-events: none;
}
.notice {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 11px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  background: var(--ink-300);
  box-shadow: var(--shadow-md);
  pointer-events: auto;
  animation: slide 180ms var(--ease);
}
@keyframes slide {
  from {
    opacity: 0;
    transform: translateX(8px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
.notice[data-kind='attention'] {
  border-color: color-mix(in srgb, var(--attention) 42%, transparent);
}
.notice[data-kind='error'] {
  border-color: color-mix(in srgb, var(--danger) 42%, transparent);
}
.notice-icon {
  color: var(--accent);
  flex: 0 0 auto;
  margin-top: 1px;
}
.notice[data-kind='attention'] .notice-icon {
  color: var(--attention);
}
.notice[data-kind='error'] .notice-icon {
  color: var(--danger);
}
.notice-body {
  flex: 1;
  min-width: 0;
}
.notice-title {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-hi);
}
.notice-text {
  font-size: var(--fs-micro);
  color: var(--text-lo);
  margin-top: 2px;
  word-break: break-word;
}

/* ---- dock panels ------------------------------------------------------ */

.panel {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
}
.panel-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 38px;
  height: 38px;
  padding: 0 10px;
  border-bottom: 1px solid var(--line-100);
}
.panel-bar .field {
  height: 26px;
  flex: 1;
  padding: 0 9px;
  background: var(--ink-100);
}
.panel-bar .field input {
  font-size: var(--fs-micro);
}
.panel-split {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: 210px 1fr;
}
.panel-side {
  min-height: 0;
  overflow-y: auto;
  border-right: 1px solid var(--line-100);
  padding: 6px;
}
.panel-main {
  min-height: 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.tree-row {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  height: 26px;
  padding: 0 6px;
  border-radius: var(--r-sm);
  color: var(--text-mid);
  font-size: var(--fs-sm);
  text-align: left;
  transition: background 80ms var(--ease);
}
.tree-row:hover {
  background: var(--ink-100);
  color: var(--text-hi);
}
.tree-row[data-on='true'] {
  background: var(--ink-300);
  color: var(--text-hi);
}
.tree-row svg {
  flex: 0 0 auto;
  color: var(--text-dim);
}
.tree-row[data-dir='true'] svg {
  color: var(--accent-dim);
}
.tree-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.editor-host {
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

/* The rich-preview body, filling the same space .editor-host would. */
.fp-scroll {
  flex: 1;
  min-height: 0;
  overflow: auto;
}
.editor-host .cm-editor {
  height: 100%;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
}
.editor-host .cm-scroller {
  font-family: var(--font-mono);
}
.editor-host .cm-focused {
  outline: none !important;
}

.git-file {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  height: 28px;
  padding: 0 8px;
  border-radius: var(--r-sm);
  color: var(--text-mid);
  font-size: var(--fs-sm);
  text-align: left;
}
.git-file:hover {
  background: var(--ink-100);
  color: var(--text-hi);
}
.git-file[data-on='true'] {
  background: var(--ink-300);
  color: var(--text-hi);
}
.git-code {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  width: 18px;
  flex: 0 0 auto;
  text-align: center;
  color: var(--accent);
}
.git-code[data-kind='D'] {
  color: var(--danger);
}
.git-code[data-kind='?'] {
  color: var(--text-dim);
}
.git-path {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  direction: rtl;
  text-align: left;
}

.diff {
  flex: 1;
  min-height: 0;
  overflow: auto;
  padding: 8px 0;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  line-height: 1.55;
  user-select: text;
}
.diff-line {
  padding: 0 12px;
  white-space: pre;
  color: var(--text-mid);
}
.diff-line[data-t='+'] {
  background: color-mix(in srgb, var(--live) 12%, transparent);
  color: var(--live);
}
.diff-line[data-t='-'] {
  background: color-mix(in srgb, var(--danger) 12%, transparent);
  color: var(--danger);
}
.diff-line[data-t='@'] {
  color: var(--violet);
  background: var(--ink-100);
}
.diff-line[data-t='h'] {
  color: var(--text-dim);
}

.tool-card {
  padding: 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-100);
  background: var(--ink-100);
  margin-bottom: 8px;
}
.tool-card-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-hi);
  margin-bottom: 4px;
}
.tool-card-desc {
  font-size: var(--fs-micro);
  color: var(--text-dim);
  margin-bottom: 10px;
}
.tool-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.setting-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 11px 0;
  border-bottom: 1px solid var(--line-100);
}
.setting-row:last-child {
  border-bottom: none;
}
.setting-text {
  flex: 1;
  min-width: 0;
}
.setting-name {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text-hi);
}
.setting-desc {
  font-size: var(--fs-micro);
  color: var(--text-dim);
  margin-top: 2px;
}
.setting-control {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
}

.toggle {
  width: 36px;
  height: 20px;
  border-radius: 10px;
  background: var(--ink-400);
  padding: 2px;
  transition: background var(--dur) var(--ease);
}
.toggle[data-on='true'] {
  background: var(--accent);
}
.toggle i {
  display: block;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--text-lo);
  transition: transform var(--dur) var(--ease), background var(--dur) var(--ease);
}
.toggle[data-on='true'] i {
  transform: translateX(16px);
  background: var(--on-accent);
}

.swatches {
  display: flex;
  gap: 6px;
}
.swatch {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 2px solid transparent;
  transition: transform var(--dur) var(--ease);
}
.swatch[data-on='true'] {
  border-color: var(--text-hi);
  transform: scale(1.08);
}

.select {
  height: 28px;
  padding: 0 8px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-200);
  background: var(--ink-200);
  color: var(--text-mid);
  font-size: var(--fs-sm);
}
.select option {
  background: var(--ink-300);
  color: var(--text-hi);
}

/* ---- settings ---------------------------------------------------------
 *
 * Settings is a surface, not a dialog: it takes the stage beside the workspace
 * rail and stays there until you leave it. The nav is a quiet index — a hairline
 * marks the active row rather than a filled pill, so the eye goes to the
 * content, and the section name carries the display face.
 */

.settings-surface {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: 216px minmax(0, 1fr);
  background: var(--ink-000);
}

.settings-nav {
  display: flex;
  flex-direction: column;
  /* No gap: the groups space themselves now, and a gap here would add to
     theirs and push Documentation around as the list is filtered. */
  min-height: 0;
  padding: 16px 12px 12px;
  border-right: 1px solid var(--line-100);
  background: var(--ink-050);
}
.settings-nav-title {
  padding: 0 10px;
  margin: 0 0 12px;
}
.settings-nav-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 11px;
  height: 34px;
  padding: 0 10px;
  border-radius: var(--r-md);
  color: var(--text-lo);
  font-size: var(--fs-base);
  text-align: left;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.settings-nav-item svg {
  flex: 0 0 auto;
  opacity: 0.75;
}
.settings-nav-item:hover {
  background: var(--ink-100);
  color: var(--text-hi);
}
.settings-nav-item[data-on='true'] {
  color: var(--text-hi);
  background: var(--ink-200);
}
.settings-nav-item[data-on='true']::before {
  content: '';
  position: absolute;
  left: -12px;
  top: 8px;
  bottom: 8px;
  width: 2px;
  border-radius: 0 2px 2px 0;
  background: var(--accent);
}
.settings-nav-item[data-on='true'] svg {
  color: var(--accent);
  opacity: 1;
}
.settings-nav-foot {
  margin-top: auto;
  padding: 12px 10px 2px;
  font-size: var(--fs-micro);
  color: var(--text-dim);
  border-top: 1px solid var(--line-100);
}

.settings-main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  /*
   * One column width for everything in here, so every left edge agrees and the
   * whole thing can be centred as a unit. Two different caps — one for text,
   * a wider one for the theme grid — cannot both be centred without their
   * edges disagreeing by fifty pixels.
   */
  --settings-col: 860px;
  /* Matches ::-webkit-scrollbar in base.css. The pane reserves this on both
     sides so its column stays centred; the heading has to be inset by the
     same amount or the title sits proud of the content beneath it. */
  --settings-gutter: 10px;
}

.settings-head {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 0 0 auto;
  padding: 22px calc(26px + var(--settings-gutter)) 14px;
  width: 100%;
  max-width: calc(var(--settings-col) + 52px + var(--settings-gutter) * 2);
  margin-inline: auto;
}
.settings-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 32px;
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--text-hi);
}
.settings-head .spacer {
  flex: 1;
}

.settings-pane {
  flex: 1;
  min-height: 0;
  min-width: 0;
  overflow-y: auto;
  padding: 0 26px 32px;
  /*
   * The column is centred by the track, not by each child's own margins.
   * Several of these set `margin` in full — `.settings-lede` among them — and
   * that shorthand lands later at the same specificity, quietly resetting an
   * auto margin back to zero and stranding the content against the rail.
   * Placing one grid track leaves child margins to do their own job.
   */
  display: grid;
  grid-template-columns: minmax(0, var(--settings-col));
  justify-content: center;
  align-content: start;
  /*
   * Reserved on both sides, so the scrollbar cannot shift the centred column a
   * few pixels away from the heading above it — which reads as a jog between
   * the title and the content it belongs to.
   */
  scrollbar-gutter: stable both-edges;
}

.settings-lede {
  margin: 0 0 20px;
  font-size: var(--fs-sm);
  color: var(--text-lo);
  line-height: 1.65;
  max-width: 62ch;
}

.theme-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(198px, 1fr));
  align-items: stretch;
  gap: 10px;
}

.theme-card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 8px 8px 11px;
  border-radius: var(--r-lg);
  border: 1px solid var(--line-100);
  background: var(--ink-100);
  text-align: left;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}
.theme-card:hover {
  border-color: var(--line-300);
  background: var(--ink-200);
  transform: translateY(-1px);
}
.theme-card[data-on='true'] {
  border-color: var(--accent);
  background: var(--accent-wash);
}

.theme-preview {
  display: block;
  border-radius: var(--r-md);
  border: 1px solid;
  overflow: hidden;
  margin-bottom: 10px;
}
.tp-bar {
  display: flex;
  align-items: center;
  gap: 3px;
  height: 15px;
  padding: 0 6px;
  border-bottom: 1px solid;
}
.tp-bar i {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  opacity: 0.8;
}
.tp-body {
  display: block;
  padding: 9px 8px 10px;
}
.tp-line {
  display: block;
  height: 4px;
  border-radius: 2px;
  margin-bottom: 5px;
}
.tp-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 7px;
}
.tp-pill {
  display: block;
  width: 34px;
  height: 11px;
  border-radius: 6px;
  flex: 0 0 auto;
}
.tp-status {
  display: flex;
  gap: 4px;
  margin-top: 9px;
}
.tp-status i {
  width: 5px;
  height: 5px;
  border-radius: 50%;
}

.theme-meta {
  display: block;
  padding: 0 2px;
}
.theme-name {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-hi);
}
.theme-name svg {
  color: var(--text-dim);
}
/* Two lines' worth whether the blurb needs them or not, so every card's name
   sits on the same baseline across a row. */
.theme-blurb {
  display: block;
  margin-top: 2px;
  min-height: 2.9em;
  font-size: var(--fs-micro);
  color: var(--text-dim);
  line-height: 1.45;
}

.theme-check {
  position: absolute;
  top: 14px;
  right: 14px;
  display: grid;
  place-items: center;
  width: 19px;
  height: 19px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: var(--shadow-sm);
}

.swatch-auto {
  background: linear-gradient(135deg, var(--accent) 0%, var(--accent) 48%, var(--ink-400) 52%);
}

.shortcut-list {
  display: grid;
  gap: 1px;
}
.shortcut-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 9px 2px;
  border-bottom: 1px solid var(--line-100);
  font-size: var(--fs-sm);
  color: var(--text-mid);
}
.shortcut-row:last-child {
  border-bottom: none;
}
.shortcut-row .kbd {
  min-width: 82px;
  justify-content: flex-start;
  padding: 0 8px;
}

.stepper-num {
  display: flex;
  align-items: center;
  gap: 2px;
}
.stepper-num .icon-btn {
  width: 22px;
  height: 22px;
  border: 1px solid var(--line-200);
}
.stepper-num span {
  min-width: 34px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-hi);
}

/* ---- file tree -----------------------------------------------------------
 * The project as a tree, a branch at a time. Rows are 24pt and dense on
 * purpose: this panel answers "where does this live", which needs many rows
 * visible at once far more than it needs breathing room.
 */

.ft-panel .ft-field {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 1;
  height: 26px;
  padding: 0 8px;
  border-radius: var(--r-sm);
  background: var(--ink-100);
  color: var(--text-lo);
}
.ft-panel .ft-field input {
  flex: 1;
  min-width: 0;
  border: none;
  background: none;
  color: var(--text-hi);
  font-size: var(--fs-micro);
  outline: none;
}

.ft-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 4px 4px 10px;
}

.ft-row {
  display: flex;
  align-items: center;
  gap: 5px;
  width: 100%;
  height: 24px;
  padding-right: 8px;
  border: none;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-mid);
  font-size: var(--fs-sm);
  text-align: left;
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.ft-row:hover {
  background: var(--ink-100);
  color: var(--text-hi);
}
.ft-row[data-on='true'] {
  background: var(--ink-300);
  color: var(--text-hi);
}

/* Reserved even for files, so names line up whether or not a row can open. */
.ft-twist {
  display: inline-grid;
  place-items: center;
  flex: 0 0 auto;
  width: 12px;
  color: var(--text-dim);
  transition: transform var(--dur) var(--ease);
}
.ft-twist[data-open='true'] {
  transform: rotate(90deg);
}

.ft-icon {
  display: inline-grid;
  place-items: center;
  flex: 0 0 auto;
  color: var(--text-lo);
}

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

/* Search results say where the hit was, since the tree shape is gone. */
.ft-where {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: right;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
}

/* ---- the tab strip's add menu --------------------------------------------
 * In overlays.css rather than chrome.css on purpose: another session owns
 * chrome.css right now, and a new block appended there would have collided.
 */

.ws-add-wrap {
  position: relative;
  flex: 0 0 auto;
  display: inline-flex;
}

.ws-add-scrim {
  position: fixed;
  inset: 0;
  z-index: 40;
}

.ws-add-menu {
  position: absolute;
  top: 28px;
  right: 0;
  z-index: 41;
  display: flex;
  flex-direction: column;
  min-width: 180px;
  padding: 4px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  background: var(--ink-200);
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.32);
}

.ws-add-item {
  display: flex;
  align-items: center;
  gap: 9px;
  height: 30px;
  padding: 0 9px;
  border: none;
  border-radius: var(--r-sm);
  background: none;
  color: var(--text-mid);
  font-size: var(--fs-sm);
  text-align: left;
  cursor: pointer;
}
.ws-add-item:hover {
  background: var(--ink-300);
  color: var(--text-hi);
}
.ws-add-item svg {
  flex: 0 0 auto;
  color: var(--text-lo);
}
.ws-add-item span {
  flex: 1;
}
.ws-add-item kbd {
  flex: 0 0 auto;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
}

/* A browser tab fills the stage.
 *
 * `.browser` was written for the dock's narrow column, where the column set
 * the width and it only had to manage height. In a stage slot the slot is the
 * flex parent and nothing was claiming the width, so it collapsed to its
 * content — measured at 355px of webview inside a 1234px stage. */
.stage-slot > .browser {
  flex: 1;
  min-width: 0;
  width: 100%;
}

/* ---- settings, regrouped -------------------------------------------------
 * A sidebar of named blocks rather than one long list, a search field that
 * matches what is *on* a page rather than its name, and a page that opens with
 * its title and one line saying what it is for.
 */

.settings-back {
  display: flex;
  align-items: center;
  gap: 9px;
  height: 28px;
  padding: 0 8px;
  margin-bottom: 6px;
  border: none;
  border-radius: var(--r-sm);
  background: none;
  color: var(--text-lo);
  font-size: var(--fs-sm);
  cursor: pointer;
  transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.settings-back:hover {
  color: var(--text-hi);
  background: var(--ink-100);
}

.settings-nav-title {
  margin: 0 0 14px;
  padding: 0 8px;
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text-hi);
}

.settings-search {
  display: flex;
  align-items: center;
  gap: 7px;
  height: 30px;
  margin: 0 0 16px;
  padding: 0 9px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-100);
  background: var(--ink-100);
  color: var(--text-lo);
}
.settings-search input {
  flex: 1;
  min-width: 0;
  border: none;
  background: none;
  color: var(--text-hi);
  font-size: var(--fs-sm);
  outline: none;
}
.settings-search input::placeholder {
  color: var(--text-dim);
}

/* The scroller, so a long list never pushes Documentation off the bottom. */
.settings-groups {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.settings-group {
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.settings-group-title {
  padding: 0 10px;
  margin: 0 0 4px;
}

.settings-none {
  padding: 8px 10px;
  color: var(--text-dim);
  font-size: var(--fs-micro);
}

.settings-doc {
  display: flex;
  align-items: center;
  gap: 9px;
  flex: 0 0 auto;
  height: 32px;
  margin-top: 12px;
  padding: 0 8px;
  border: none;
  border-top: 1px solid var(--line-100);
  border-radius: 0;
  background: none;
  color: var(--text-lo);
  font-size: var(--fs-sm);
  cursor: pointer;
  transition: color var(--dur) var(--ease);
}
.settings-doc:hover {
  color: var(--text-hi);
}

/* The page's own heading: what it is, then one line on what it is for. */
.settings-heading {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}
.settings-blurb {
  margin: 0;
  max-width: 62ch;
  color: var(--text-lo);
  font-size: var(--fs-sm);
  line-height: 1.5;
}

/* ---- what is hidden in Settings ---------------------------------------- */

/* sudo, in the search box's nothing-matched slot. */
.egg-sudo {
  color: var(--text-mid);
  line-height: 1.6;
}
.egg-sudo b {
  color: var(--text-hi);
  font-weight: 500;
}

/*
 * xyzzy.
 *
 * Grid-max rather than a height in px: the readout is eight rows of data whose
 * longest value is a shell path, and a fixed height would either clip a long
 * one or leave a gap under a short one. 1fr is the content's own height, and
 * animating between 0fr and 1fr is the one way to transition to auto.
 */
.egg-machine {
  display: grid;
  grid-template-rows: 1fr;
  margin: 22px 0 0;
  padding: 14px 16px;
  border: 1px solid var(--line-100);
  border-radius: var(--r-md);
  background: var(--ink-100);
  color: var(--text-mid);
  font-size: var(--fs-micro);
  line-height: 1.75;
  white-space: pre;
  overflow-x: auto;
}
.egg-machine .egg-said {
  color: var(--text-lo);
}
.egg-machine .egg-rows {
  display: block;
  color: var(--text-mid);
  animation: egg-in 420ms var(--ease) both;
}
.egg-machine[data-open='true'] {
  border-color: var(--accent-edge);
}

@keyframes egg-in {
  from {
    opacity: 0;
    transform: translateY(4px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* The note after the konami code. */
.egg-note {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 14px;
  padding: 10px 12px;
  border: 1px solid var(--accent-edge);
  border-radius: var(--r-md);
  background: var(--accent-wash);
  color: var(--text-mid);
  font-size: var(--fs-micro);
  animation: egg-in 420ms var(--ease) both;
}
.egg-note svg {
  flex: 0 0 auto;
  color: var(--accent);
}
.egg-note span {
  flex: 1 1 auto;
}
.egg-note b {
  color: var(--text-hi);
  font-weight: 500;
}

[data-reduce-motion='true'] .egg-note,
[data-reduce-motion='true'] .egg-machine .egg-rows {
  animation: none;
}

/* ---- voice.css ---- */
/* Voice dictation: the recording readout and the model manager. */

/* ---- dictation HUD ------------------------------------------------------
 *
 * A pill at the bottom of the window with the caption stacked above it. The
 * stage is fixed rather than parented to the grid so the readout sits in the
 * same place whichever surface you are on, and lifts to clear the conductor
 * when that is open.
 */

.dictation-stage {
  position: fixed;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  z-index: 55;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  width: min(600px, calc(100vw - 48px));
  /* The stage is a spacer; only the pill and the caption take the pointer. */
  pointer-events: none;
}
.dictation-stage[data-lifted='true'] {
  bottom: 70px;
}

/* ---- caption ---- */

.dictation-caption {
  pointer-events: auto;
  /*
   * Sized to its words, not to the stage. A three-word phrase in a 600px card
   * reads as an error; the card should look like it is holding exactly what
   * you said, and grow only as you keep talking.
   */
  align-self: center;
  width: fit-content;
  max-width: 100%;
  padding: 12px 16px 13px;
  border-radius: 14px;
  border: 1px solid var(--line-200);
  background: color-mix(in srgb, var(--ink-050) 92%, transparent);
  backdrop-filter: blur(20px);
  box-shadow:
    var(--shadow-lg),
    inset 0 1px 0 rgb(255 255 255 / 4%);
  animation: caption-in 220ms var(--ease) both;
}

@keyframes caption-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
}

/*
 * The eyebrow is the one place the interface speaks in the terminal's own
 * register: monospace, uppercase, widely tracked — the way a status line reads.
 */
.dictation-eyebrow {
  display: flex;
  align-items: center;
  gap: 7px;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-lo);
}

.dictation-arrow {
  color: var(--accent);
  letter-spacing: 0;
}

.dictation-said {
  margin: 7px 0 0;
  font-size: var(--fs-md);
  line-height: 1.55;
  color: var(--text-hi);
  /* Long dictation scrolls rather than growing the card off the screen. */
  max-height: 4.65em;
  overflow-y: auto;
  overflow-wrap: anywhere;
}

.dictation-quote {
  color: var(--text-lo);
}

/*
 * Three dots that fill while a phrase is still being transcribed. The closing
 * quote is withheld until they clear, so the sentence visibly stays open.
 */
.dictation-pending::after {
  content: '…';
  margin-left: 2px;
  color: var(--text-lo);
  animation: pending 1.2s steps(4, end) infinite;
}

@keyframes pending {
  0% {
    content: '';
  }
  25% {
    content: '.';
  }
  50% {
    content: '..';
  }
  75% {
    content: '...';
  }
}

/* ---- pill ---- */

.dictation-pill {
  pointer-events: auto;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 7px 16px 7px 7px;
  border-radius: 999px;
  border: 1px solid var(--line-200);
  background: color-mix(in srgb, var(--ink-050) 92%, transparent);
  backdrop-filter: blur(20px);
  box-shadow:
    var(--shadow-lg),
    inset 0 1px 0 rgb(255 255 255 / 5%);
  animation: pill-in 240ms var(--ease) both;
  transition: border-color var(--dur) var(--ease);
}
.dictation-pill:hover {
  border-color: var(--line-300);
}
.dictation-pill:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

@keyframes pill-in {
  from {
    opacity: 0;
    transform: translateY(10px) scale(0.94);
  }
}

/*
 * The mark identifies; the ring indicates. Keeping those on one element means
 * the recording state has a home rather than needing its own red dot.
 */
.dictation-tile {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  flex: 0 0 auto;
  border-radius: 9px;
  /*
   * The tile is tinted by the theme; the mark inside it stays coral, following
   * the rule the mark sets for itself — its palette is part of the mark, and
   * only its surroundings follow the interface. Dark tile, coral mark: the app
   * icon as it actually is. The inverse (pale mark on a coral tile) swallows
   * the lit counter-dot, which is the part of the mark that carries meaning.
   */
  border: 1px solid color-mix(in srgb, var(--accent) 34%, transparent);
  background: linear-gradient(
    155deg,
    color-mix(in srgb, var(--accent) 14%, var(--ink-000)),
    var(--ink-000)
  );
}
.dictation-tile[data-live='true'] {
  animation: tile-breathe 2.4s var(--ease) infinite;
}

@keyframes tile-breathe {
  0%,
  100% {
    box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 30%, transparent);
  }
  50% {
    box-shadow: 0 0 0 5px transparent;
  }
}

.dictation-rule {
  width: 1px;
  height: 20px;
  flex: 0 0 auto;
  background: var(--line-300);
}

/*
 * Fixed 3px columns on a 6px pitch: a monospace cell grid, square-capped. The
 * heights are a scrolling window of real input levels, so the shape is the
 * waveform rather than a decoration that merely reacts.
 */
.dictation-meter {
  display: flex;
  align-items: center;
  gap: 3px;
  height: 20px;
  flex: 0 0 auto;
}
.dictation-meter i {
  display: block;
  width: 3px;
  min-height: 3px;
  border-radius: 1px;
  background: var(--accent);
  transition:
    height 90ms linear,
    opacity 90ms linear;
}

.conductor-mic[data-on='true'] {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}

/* Motion here is ambient, so it is the first thing to go when asked. */
[data-reduce-motion='true'] .dictation-tile[data-live='true'],
[data-reduce-motion='true'] .dictation-pending::after {
  animation: none;
}
[data-reduce-motion='true'] .dictation-caption,
[data-reduce-motion='true'] .dictation-pill {
  animation-duration: 1ms;
}
[data-reduce-motion='true'] .dictation-pending::after {
  content: '…';
}

@media (prefers-reduced-motion: reduce) {
  .dictation-tile[data-live='true'],
  .dictation-pending::after {
    animation: none;
  }
  .dictation-pending::after {
    content: '…';
  }
}

/* ---- model manager ------------------------------------------------------ */

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

.model-card {
  padding: 11px 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  background: var(--ink-200);
  transition:
    border-color var(--dur) var(--ease),
    background var(--dur) var(--ease);
}
.model-card[data-on='true'] {
  border-color: var(--accent-edge);
  background: var(--accent-wash);
}

.model-head {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}

.model-titles {
  flex: 1;
  min-width: 0;
}

.model-name {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: var(--fs-base);
  color: var(--text-hi);
}

.model-tag {
  padding: 1px 6px;
  border-radius: 999px;
  border: 1px solid var(--accent-edge);
  background: var(--accent-wash);
  color: var(--accent);
  font-size: var(--fs-micro);
  font-family: var(--font-mono);
  letter-spacing: 0.03em;
}

.model-blurb {
  margin-top: 3px;
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--text-lo);
}

.model-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
}

.model-inuse {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 26px;
  padding: 0 10px;
  border-radius: 999px;
  border: 1px solid var(--accent-edge);
  color: var(--accent);
  font-size: var(--fs-micro);
  font-family: var(--font-mono);
  white-space: nowrap;
}

.model-facts {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 9px;
}

.model-progress {
  margin-top: 10px;
}

.model-bar {
  height: 3px;
  border-radius: 2px;
  background: var(--ink-400);
  overflow: hidden;
}
.model-bar i {
  display: block;
  height: 100%;
  border-radius: 2px;
  background: var(--accent);
  transition: width 160ms linear;
}

.model-progress-note {
  margin-top: 6px;
  font-size: var(--fs-micro);
  font-family: var(--font-mono);
  color: var(--text-lo);
}

/* ---- spoken alerts ------------------------------------------------------ */

.slider {
  width: 132px;
  height: 20px;
  appearance: none;
  background: none;
  cursor: pointer;
}
.slider::-webkit-slider-runnable-track {
  height: 3px;
  border-radius: 2px;
  background: var(--ink-400);
}
.slider::-webkit-slider-thumb {
  appearance: none;
  width: 13px;
  height: 13px;
  margin-top: -5px;
  border-radius: 50%;
  background: var(--accent);
  transition: transform var(--dur) var(--ease);
}
.slider:hover::-webkit-slider-thumb {
  transform: scale(1.15);
}
.slider:focus-visible::-webkit-slider-thumb {
  box-shadow: 0 0 0 3px var(--accent-wash);
}

/*
 * The nudge towards a voice that does not sound like a robot. Shown only when
 * the machine has nothing but the compact voices installed, which is the
 * default state of every Mac.
 */
.speech-hint {
  display: flex;
  gap: 11px;
  margin-top: 18px;
  padding: 13px 14px;
  border-radius: var(--r-md);
  border: 1px solid var(--accent-edge);
  background: var(--accent-wash);
  color: var(--accent);
}
.speech-hint strong {
  display: block;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-hi);
}
.speech-hint p {
  margin: 5px 0 11px;
  font-size: var(--fs-micro);
  line-height: 1.7;
  color: var(--text-mid);
}
.speech-hint em {
  font-style: normal;
  font-family: var(--font-mono);
  color: var(--accent);
}

/* ---- update.css ---- */
/*
 * The update card.
 *
 * Restrained on purpose: it sits in a corner over a grid of running agents, so
 * it earns attention with one lit edge and a single filling bar rather than
 * colour and motion everywhere.
 */

.update-card {
  position: absolute;
  right: 14px;
  bottom: 14px;
  z-index: 55;
  width: 340px;
  padding: 14px 14px 12px;
  border-radius: var(--r-lg);
  border: 1px solid var(--line-200);
  background: var(--glass);
  backdrop-filter: blur(20px);
  box-shadow: var(--shadow-lg);
  overflow: hidden;

  opacity: 0;
  transform: translateY(10px) scale(0.985);
  transition: opacity 260ms var(--ease), transform 260ms var(--ease),
    border-color 400ms var(--ease);
}
.update-card[data-shown='true'] {
  opacity: 1;
  transform: none;
}
/* Once it is actually actionable, the accent edge comes up. */
.update-card[data-ready='true'] {
  border-color: var(--accent-edge);
}

[data-reduce-motion='true'] .update-card {
  transition: none;
  opacity: 1;
  transform: none;
}

/* A soft wash behind the card, only when there is something to install. */
.update-glow {
  position: absolute;
  inset: auto -40% -70% -40%;
  height: 130px;
  border-radius: 50%;
  background: var(--accent);
  opacity: 0;
  filter: blur(48px);
  pointer-events: none;
  transition: opacity 600ms var(--ease);
}
.update-card[data-ready='true'] .update-glow {
  opacity: 0.13;
}

.update-head {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 11px;
}

.update-mark {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  flex: 0 0 auto;
  border-radius: 50%;
  border: 1px solid var(--line-200);
  background: var(--ink-200);
  color: var(--text-lo);
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease),
    background var(--dur) var(--ease);
}
.update-card[data-ready='true'] .update-mark {
  color: var(--on-accent);
  background: var(--accent);
  border-color: transparent;
}

.update-titles {
  flex: 1;
  min-width: 0;
}
.update-title {
  font-size: var(--fs-base);
  color: var(--text-hi);
  letter-spacing: -0.005em;
}
.update-title b {
  font-weight: 600;
}
.update-sub {
  margin-top: 2px;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

.update-track {
  position: relative;
  height: 2px;
  margin: 12px 0 0;
  border-radius: 1px;
  background: var(--ink-400);
  overflow: hidden;
}
.update-fill {
  display: block;
  height: 100%;
  border-radius: 1px;
  background: var(--accent);
  transition: width 320ms var(--ease);
}

/* Collapsed to nothing until asked for, so the card stays one line tall. */
.update-notes {
  position: relative;
  max-height: 0;
  overflow: hidden;
  transition: max-height 260ms var(--ease), margin 260ms var(--ease);
}
.update-notes[data-expanded='true'] {
  max-height: 190px;
  margin-top: 10px;
  overflow-y: auto;
}
.update-notes p {
  margin: 0;
  padding-right: 4px;
  font-size: var(--fs-sm);
  line-height: 1.55;
  color: var(--text-mid);
  white-space: pre-line;
}

.update-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 12px;
}
.update-actions .spacer {
  flex: 1;
}
.update-actions .btn {
  height: 30px;
  padding: 0 13px;
}

.update-link {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: var(--fs-micro);
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
  color: var(--text-lo);
  transition: color var(--dur) var(--ease);
}
.update-link:hover {
  color: var(--accent);
}

/* Titlebar indicator, so a dismissed update is still reachable. */
.update-dot {
  position: absolute;
  top: 3px;
  right: 3px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 2px var(--ink-100);
}

/* ---- Settings › About ---------------------------------------------------- */

.update-row {
  display: flex;
  align-items: center;
  gap: 10px;
}
.update-status {
  font-size: var(--fs-sm);
  color: var(--text-lo);
}
.update-status b {
  color: var(--text-hi);
  font-weight: 600;
}

/* ---- brain.css ---- */
/* Eaon Brain — list, editor and graph over the .eaonbrain/ folder. */

.brain {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  background: var(--ink-000);
}

.brain-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 0 0 auto;
  padding: 16px 20px 14px;
  border-bottom: 1px solid var(--line-100);
}

.brain-identity {
  display: flex;
  align-items: baseline;
  gap: 12px;
  min-width: 0;
}
.brain-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--text-hi);
}
.brain-stats {
  font-size: var(--fs-micro);
  color: var(--text-dim);
  white-space: nowrap;
}

/*
 * Which folder's memory is on screen. Always shown, even when there is only
 * one — a brain is per folder, and leaving that implicit is what made it
 * possible to read one project's notes thinking they were another's.
 */
.brain-folder-name {
  flex: 0 0 auto;
  max-width: 200px;
  padding: 0 9px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  border: 1px solid var(--line-200);
  background: var(--ink-100);
  color: var(--text-mid);
  font-size: var(--fs-micro);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.brain-search {
  flex: 1;
  max-width: 320px;
  height: 30px;
}

/* Quiet until it is actually wired to agents, then it earns the accent. */
.brain-mcp {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 22px;
  padding: 0 9px;
  border-radius: 999px;
  border: 1px solid var(--line-200);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.08em;
  white-space: nowrap;
}
.brain-mcp[data-on='true'] {
  color: var(--accent);
  border-color: var(--accent-edge);
  background: var(--accent-wash);
}

.brain-body {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: 244px minmax(0, 1fr) 236px;
}

.brain-list {
  min-height: 0;
  overflow-y: auto;
  padding: 8px;
  border-right: 1px solid var(--line-100);
  background: var(--ink-050);
}

.brain-item {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  width: 100%;
  padding: 8px 9px;
  margin-bottom: 1px;
  border-radius: var(--r-md);
  border: 1px solid transparent;
  color: var(--text-mid);
  text-align: left;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.brain-item svg {
  flex: 0 0 auto;
  margin-top: 2px;
  color: var(--text-dim);
}
.brain-item:hover {
  background: var(--ink-100);
  color: var(--text-hi);
}
.brain-item[data-on='true'] {
  background: var(--ink-200);
  border-color: var(--line-200);
  color: var(--text-hi);
}
.brain-item[data-on='true'] svg {
  color: var(--accent);
}
.brain-item-text {
  display: block;
  min-width: 0;
  flex: 1;
}
.brain-item-title {
  display: block;
  font-size: var(--fs-sm);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.brain-item-meta {
  display: block;
  margin-top: 2px;
  font-size: 9px;
  color: var(--text-dim);
}

.brain-main {
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  position: relative;
}

.brain-canvas {
  width: 100%;
  height: 100%;
  display: block;
}

.brain-editor {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  padding: 20px 24px 0;
}
.brain-editor-title {
  width: 100%;
  font-family: var(--font-display);
  font-size: 30px;
  font-weight: 400;
  letter-spacing: -0.02em;
  color: var(--text-hi);
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line-100);
}
.brain-editor-body {
  flex: 1;
  min-height: 0;
  width: 100%;
  margin-top: 14px;
  padding: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  line-height: 1.75;
  color: var(--text-mid);
  resize: none;
}
.brain-editor-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
  padding: 12px 0;
  border-top: 1px solid var(--line-100);
}
.brain-editor-foot .btn {
  height: 30px;
}
.brain-path {
  font-size: var(--fs-micro);
  color: var(--text-dim);
}

.brain-inspector {
  min-height: 0;
  overflow-y: auto;
  padding: 16px 14px;
  border-left: 1px solid var(--line-100);
  background: var(--ink-050);
}

.brain-ref {
  display: flex;
  align-items: center;
  gap: 7px;
  width: 100%;
  padding: 6px 8px;
  margin-top: 2px;
  border-radius: var(--r-sm);
  color: var(--text-mid);
  font-size: var(--fs-sm);
  text-align: left;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.brain-ref svg {
  flex: 0 0 auto;
  color: var(--text-dim);
}
button.brain-ref:hover {
  background: var(--ink-200);
  color: var(--text-hi);
}
/* A link written before the note it points at exists. */
.brain-ref[data-missing='true'] {
  color: var(--text-dim);
  font-style: italic;
}

.brain-suggested {
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
}
.brain-terms {
  font-size: 9px;
  color: var(--text-dim);
}

.brain-hint {
  margin: 6px 2px;
  font-size: var(--fs-micro);
  line-height: 1.6;
  color: var(--text-dim);
}

/* ---- stats.css ---- */
/* ---- Stats surface ------------------------------------------------------ */

.stats {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
  background: var(--ink-000);
}

.stats-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 16px 22px 14px;
  border-bottom: 1px solid var(--line-100);
  flex: none;
}

.stats-title {
  font-family: var(--font-display);
  font-size: 25px;
  font-weight: 400;
  letter-spacing: -0.01em;
  color: var(--text-hi);
  margin: 0;
}

.stats-sub {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-lo);
}

.stats-scope {
  display: flex;
  gap: 2px;
  padding: 2px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-100);
  background: var(--ink-050);
  align-self: center;
}

.stats-scope-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 24px;
  padding: 0 9px;
  border: 0;
  border-radius: calc(var(--r-md) - 3px);
  background: transparent;
  color: var(--text-lo);
  font-family: var(--font-ui);
  font-size: 11.5px;
  cursor: pointer;
  white-space: nowrap;
}

.stats-scope-btn:hover {
  color: var(--text-hi);
}

.stats-scope-btn[data-on='true'] {
  background: var(--ink-200);
  color: var(--text-hi);
}

.stats-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 18px 22px 28px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* ---- streak -------------------------------------------------------------- */

.stats-streaks {
  display: flex;
  align-items: center;
  gap: 28px;
  padding: 18px 20px;
  border: 1px solid var(--line-100);
  border-radius: var(--r-lg);
  background: linear-gradient(
    100deg,
    color-mix(in srgb, var(--accent) 12%, var(--ink-050)),
    var(--ink-050) 62%
  );
}

.streak-main {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--accent);
}

.streak-n {
  font-family: var(--font-display);
  font-size: 40px;
  line-height: 1;
  color: var(--text-hi);
}

.streak-side {
  display: flex;
  gap: 28px;
  padding-left: 26px;
  border-left: 1px solid var(--line-100);
}

.streak-n-sm {
  font-family: var(--font-display);
  font-size: 22px;
  line-height: 1.2;
  color: var(--text-hi);
}

.streak-label {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--text-lo);
  margin-top: 2px;
}

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

.stats-card {
  border: 1px solid var(--line-100);
  border-radius: var(--r-lg);
  background: var(--ink-050);
  padding: 14px 16px 15px;
}

.stats-card-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
}

.stats-metrics {
  display: flex;
  gap: 2px;
  padding: 2px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-100);
  background: var(--ink-000);
}

.stats-metric {
  height: 22px;
  padding: 0 9px;
  border: 0;
  border-radius: calc(var(--r-md) - 3px);
  background: transparent;
  color: var(--text-lo);
  font-family: var(--font-ui);
  font-size: 11px;
  cursor: pointer;
}

.stats-metric:hover:not(:disabled) {
  color: var(--text-hi);
}

.stats-metric[data-on='true'] {
  background: var(--ink-200);
  color: var(--text-hi);
}

.stats-metric:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

/* ---- heatmap ------------------------------------------------------------- */

.heatmap-wrap {
  overflow-x: auto;
  padding-bottom: 2px;
}

.heatmap-months {
  display: grid;
  margin-left: 30px;
  margin-bottom: 4px;
  font-family: var(--font-mono);
  font-size: 9.5px;
  color: var(--text-lo);
  min-width: max-content;
}

.heatmap-rows {
  display: flex;
  gap: 4px;
  min-width: max-content;
}

.heatmap-days {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  width: 26px;
  height: 91px;
  font-family: var(--font-mono);
  font-size: 9.5px;
  color: var(--text-lo);
}

.heatmap {
  display: flex;
  gap: 3px;
}

.heatmap-week {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.heatmap-cell {
  width: 10px;
  height: 10px;
  border-radius: 2px;
  background: var(--ink-200);
  border: 1px solid transparent;
}

.heatmap-cell[data-level='1'] {
  background: color-mix(in srgb, var(--accent) 28%, var(--ink-100));
}
.heatmap-cell[data-level='2'] {
  background: color-mix(in srgb, var(--accent) 50%, var(--ink-100));
}
.heatmap-cell[data-level='3'] {
  background: color-mix(in srgb, var(--accent) 74%, var(--ink-100));
}
.heatmap-cell[data-level='4'] {
  background: var(--accent);
}

.heatmap-week .heatmap-cell:hover {
  border-color: var(--text-hi);
}

.heatmap-foot {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 11px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--text-mid);
}

.heatmap-readout strong {
  color: var(--text-hi);
  font-weight: 500;
}

.heatmap-legend {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  color: var(--text-lo);
}

.heatmap-legend i {
  display: inline-block;
}

/* ---- tiles --------------------------------------------------------------- */

.stats-tiles {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
}

.stats-tile {
  border: 1px solid var(--line-100);
  border-radius: var(--r-lg);
  background: var(--ink-050);
  padding: 13px 14px;
  color: var(--text-lo);
}

.tile-n {
  font-family: var(--font-display);
  font-size: 26px;
  line-height: 1.15;
  color: var(--text-hi);
  margin-top: 6px;
}

.tile-add {
  color: var(--ok, var(--accent));
}

.tile-del {
  color: var(--text-mid);
}

.tile-label {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--text-lo);
}

/* ---- split ---------------------------------------------------------------- */

.stats-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  align-items: start;
}

@media (max-width: 1080px) {
  .stats-split,
  .stats-tiles {
    grid-template-columns: 1fr 1fr;
  }
}

/* ---- languages ------------------------------------------------------------ */

.lang-bar {
  display: flex;
  height: 9px;
  border-radius: 999px;
  overflow: hidden;
  background: var(--ink-200);
  margin-bottom: 12px;
}

.lang-bar span {
  display: block;
  min-width: 2px;
}

.lang-bar span[data-i='0'],
.lang-list i[data-i='0'] {
  background: var(--accent);
}
.lang-bar span[data-i='1'],
.lang-list i[data-i='1'] {
  background: color-mix(in srgb, var(--accent) 62%, var(--text-mid));
}
.lang-bar span[data-i='2'],
.lang-list i[data-i='2'] {
  background: color-mix(in srgb, var(--accent) 38%, var(--text-mid));
}
.lang-bar span[data-i='3'],
.lang-list i[data-i='3'] {
  background: var(--text-mid);
}
.lang-bar span[data-i='4'],
.lang-list i[data-i='4'] {
  background: color-mix(in srgb, var(--text-mid) 60%, var(--ink-200));
}
.lang-bar span[data-i='5'],
.lang-list i[data-i='5'] {
  background: var(--ink-300, var(--ink-200));
}

.lang-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 6px;
}

.lang-list li {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-mid);
}

.lang-list i {
  width: 8px;
  height: 8px;
  border-radius: 2px;
  flex: none;
}

.lang-name {
  color: var(--text-hi);
  flex: 1;
}

.lang-pct {
  color: var(--text-lo);
  width: 34px;
  text-align: right;
}

.lang-lines {
  color: var(--text-lo);
  width: 56px;
  text-align: right;
}

/* ---- hours ---------------------------------------------------------------- */

.hours {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  height: 84px;
}

.hour {
  flex: 1;
  height: 100%;
  display: flex;
  align-items: flex-end;
}

.hour-bar {
  width: 100%;
  border-radius: 2px 2px 0 0;
  background: color-mix(in srgb, var(--accent) 60%, var(--ink-200));
}

.hours-axis {
  display: flex;
  justify-content: space-between;
  margin-top: 6px;
  font-family: var(--font-mono);
  font-size: 9.5px;
  color: var(--text-lo);
}

.stats-peak,
.stats-note,
.stats-none {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--text-lo);
}

.stats-note {
  margin: 12px 0 0;
  line-height: 1.5;
}

.stats-none {
  margin: 0;
}

/* ---- usage overview ------------------------------------------------------
   The token figures, above the year grid. Built from the pieces already here —
   the same tiles, the same heatmap cell — so it reads as part of the page
   rather than a panel that wandered in from somewhere else. */

.usage-overview {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.usage-split {
  display: grid;
  grid-template-columns: 1.35fr 1fr;
  gap: 10px;
  /* Each card only as tall as what is in it. Stretching the shorter one to
     match left a third of a card empty under six weeks of squares. */
  align-items: start;
}
@media (max-width: 900px) {
  .usage-split {
    grid-template-columns: minmax(0, 1fr);
  }
}

.usage-lede {
  margin: 2px 0 12px;
}

.usage-best {
  margin-left: auto;
}

/*
 * Six weeks, one square a day, left to right.
 *
 * Not the calendar shape the year grid below uses — that one is arranged in
 * week columns because a year only makes sense read that way. Six weeks is
 * short enough to read as a plain run of days, and a run says "recently, and
 * how hard" at a glance.
 *
 * The squares stretch to fill rather than sitting at their fixed 10px: the
 * shared cell is sized for a grid 53 columns wide, and six weeks of it left
 * most of the card empty. Auto-fit wraps them if the card is ever too narrow
 * to take the lot on one line.
 */
.usage-strip {
  display: grid;
  /* Three weeks a row, so six weeks come out as two even rows rather than one
     long line and a stub of whatever did not fit. */
  grid-template-columns: repeat(21, minmax(0, 1fr));
  gap: 4px;
}
.usage-strip .heatmap-cell {
  width: auto;
  height: auto;
  aspect-ratio: 1;
  border-radius: 3px;
}
/* A day with nothing in it still has to read as a day, or the run looks like
   it has holes cut in it rather than quiet patches. */
.usage-strip .heatmap-cell[data-level='0'] {
  background: var(--ink-300);
}

.usage-scale {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
  color: var(--text-dim);
  font-size: var(--fs-micro);
}
.usage-legend {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  margin: 0 auto;
}

/* ---- the mix ---- */

.usage-bar {
  display: flex;
  height: 10px;
  border-radius: 999px;
  overflow: hidden;
  background: var(--ink-300);
}
.usage-bar > span {
  min-width: 2px;
  transition: width var(--dur) var(--ease);
}

/* Three shades of one hue rather than three colours: these are parts of a
   single quantity, not unrelated categories, and the accent already means
   "yours" everywhere else on this surface. */
[data-tone='input'] {
  background: var(--accent);
}
[data-tone='output'] {
  background: color-mix(in srgb, var(--accent) 55%, var(--ink-400));
}
[data-tone='cache'] {
  background: color-mix(in srgb, var(--accent) 22%, var(--ink-400));
}

.usage-keys,
.usage-models {
  display: flex;
  flex-direction: column;
  gap: 7px;
  margin: 13px 0 0;
  padding: 0;
  list-style: none;
}
.usage-models {
  margin-top: 11px;
  padding-top: 11px;
  border-top: 1px solid var(--line-100);
}

.usage-keys li,
.usage-models li {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-sm);
}
.usage-keys i {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 999px;
}
.usage-key-label {
  flex: 1;
  min-width: 0;
  color: var(--text-mid);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.usage-key-n {
  color: var(--text-hi);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
}
.usage-key-pct {
  min-width: 46px;
  text-align: right;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
}

/* ---- browser.css ---- */
/*
 * Preview browser in the side panel.
 *
 * Laid out the way every browser lays this out — title, then back / forward /
 * reload / address / overflow, then the page — because that arrangement is the
 * one nobody has to think about. The materials are Eaon's own: the app's inks,
 * its accent, its mono face in the address bar so a URL reads as a URL.
 */

.dock-slot {
  height: 100%;
  min-height: 0;
}
.dock-slot[hidden] {
  display: none;
}

.browser {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
}

/* Standing in for a tab: the one thing a tab strip would have told you. */
.browser-title {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  padding: 7px 10px 6px;
  color: var(--text-mid);
  font-size: var(--fs-label);
  line-height: 1;
  border-bottom: 1px solid var(--line-100);
}
.browser-title svg {
  flex: 0 0 auto;
  opacity: 0.65;
}
.browser-title-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.browser-bar {
  display: flex;
  align-items: center;
  gap: 3px;
  padding: 7px 8px;
  border-bottom: 1px solid var(--line-100);
  flex: 0 0 auto;
}

/* ---- the address bar ---------------------------------------------------- */

.browser-omnibox {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  padding: 0 4px 0 9px;
  margin: 0 4px;
  border-radius: 999px;
  border: 1px solid var(--line-200);
  background: var(--ink-100);
  transition:
    border-color var(--dur) var(--ease),
    background var(--dur) var(--ease),
    box-shadow var(--dur) var(--ease);
}
.browser-omnibox:hover {
  border-color: var(--line-300);
}
.browser-omnibox[data-focused='true'] {
  border-color: var(--accent-edge);
  background: var(--ink-050);
  box-shadow: 0 0 0 3px var(--accent-wash);
}

.browser-address {
  flex: 1;
  min-width: 0;
  height: 100%;
  border: 0;
  background: none;
  color: var(--text-hi);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  letter-spacing: -0.01em;
}
.browser-address:focus {
  outline: none;
}
.browser-address::placeholder {
  color: var(--text-dim);
  font-family: var(--font-ui);
  letter-spacing: 0;
}

/*
 * The one indicator worth having. Loopback is a secure context to a browser
 * and is where this panel spends nearly all its time, so it gets its own
 * quiet mark rather than the warning a plain http site earns.
 */
.browser-safety {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  color: var(--text-dim);
}
/* Neutral, as a modern browser's lock is — it means "nothing to report". */
.browser-safety[data-tone='secure'] {
  color: var(--text-mid);
}
/* A dev server on this machine is the case this panel exists for, so it is the
   one that gets the accent. */
.browser-safety[data-tone='local'] {
  color: var(--accent);
}
.browser-safety[data-tone='warn'] {
  color: var(--danger);
}

.browser-zoom-pill {
  flex: 0 0 auto;
  height: 20px;
  padding: 0 8px;
  border-radius: 999px;
  border: 1px solid var(--line-200);
  background: var(--ink-200);
  color: var(--text-mid);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  cursor: pointer;
}
.browser-zoom-pill:hover {
  color: var(--text-hi);
  border-color: var(--line-300);
}

/* ---- overflow menu ------------------------------------------------------ */

.browser-more {
  position: relative;
  display: inline-flex;
  flex: 0 0 auto;
}

.browser-menu {
  top: 32px;
  right: 0;
  min-width: 232px;
}

.browser-menu-zoom {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 7px 12px;
  color: var(--text-mid);
  font-size: var(--fs-sm);
}
.browser-menu-zoom > span:first-child {
  flex: 1;
}
.browser-menu-zoom .icon-btn {
  width: 24px;
  height: 24px;
  font-size: 14px;
  line-height: 1;
}

.browser-zoom-value {
  min-width: 48px;
  padding: 3px 0;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--text-hi);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  cursor: pointer;
  text-align: center;
}
.browser-zoom-value:hover {
  background: var(--ink-300);
}

.browser-context {
  position: absolute;
  min-width: 208px;
}

/* ---- find in page ------------------------------------------------------- */

.browser-find {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 6px 8px;
  border-bottom: 1px solid var(--line-100);
  background: var(--ink-100);
  flex: 0 0 auto;
}
.browser-find input {
  flex: 1;
  min-width: 0;
  height: 24px;
  padding: 0 8px;
  border-radius: 6px;
  border: 1px solid var(--line-200);
  background: var(--ink-050);
  color: var(--text-hi);
  font-size: var(--fs-sm);
}
.browser-find input:focus {
  outline: none;
  border-color: var(--accent-edge);
}
.browser-find-count {
  flex: 0 0 auto;
  min-width: 42px;
  text-align: right;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
}

/*
 * Ports that are actually listening. This is the panel's front door: in a tool
 * whose whole job is watching agents build something, the address you want is
 * nearly always a dev server that just came up.
 */
.browser-ports {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 6px 10px;
  border-bottom: 1px solid var(--line-100);
  color: var(--text-dim);
  flex: 0 0 auto;
  overflow-x: auto;
  scrollbar-width: none;
}
.browser-ports::-webkit-scrollbar {
  display: none;
}

.browser-ports-label {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-right: 2px;
}

.browser-port {
  cursor: pointer;
  white-space: nowrap;
  transition:
    color var(--dur) var(--ease),
    border-color var(--dur) var(--ease),
    background var(--dur) var(--ease);
}
.browser-port:hover {
  color: var(--text-hi);
  border-color: var(--line-300);
}
.browser-port[data-on='true'] {
  color: var(--accent);
  border-color: var(--accent-edge);
  background: var(--accent-wash);
}

/* ---- the page ----------------------------------------------------------- */

.browser-view {
  position: relative;
  flex: 1;
  min-height: 0;
  /* White, not the theme surface: a page with no background of its own should
     look the way it will look in a real browser, not tinted by the app. */
  background: #fff;
}

.browser-view webview {
  border: 0;
}

/* Where a link goes, in the corner, the way a browser does it. */
.browser-status {
  position: absolute;
  left: 0;
  bottom: 0;
  max-width: 85%;
  padding: 3px 9px 4px;
  border-radius: 0 6px 0 0;
  background: var(--ink-050);
  border-top: 1px solid var(--line-100);
  border-right: 1px solid var(--line-100);
  color: var(--text-mid);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  line-height: 1.4;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
}

/* An indeterminate sliver rather than a spinner — it belongs to the edge of the
   viewport the way a browser's does, and does not sit on top of the page. */
.browser-loading {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  overflow: hidden;
  background: transparent;
}
.browser-loading::after {
  content: '';
  position: absolute;
  inset: 0;
  width: 34%;
  background: var(--accent);
  animation: browser-sweep 1.05s var(--ease) infinite;
}

@keyframes browser-sweep {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(392%);
  }
}

.browser-error {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 28px;
  text-align: center;
  background: var(--ink-100);
  color: var(--text-mid);
  font-size: var(--fs-sm);
  line-height: 1.6;
}
.browser-error strong {
  font-weight: 400;
  color: var(--text-hi);
  max-width: 34ch;
}

.browser-error-actions {
  display: flex;
  gap: 8px;
}

[data-reduce-motion='true'] .browser-loading::after {
  animation: none;
  width: 100%;
  opacity: 0.4;
}

@media (prefers-reduced-motion: reduce) {
  .browser-loading::after {
    animation: none;
    width: 100%;
    opacity: 0.4;
  }
}

/* ---- usage.css ---- */
/* Plan usage: the title-bar pill and the panel it opens. */

.usage-root {
  position: relative;
  display: inline-flex;
}

.usage-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 24px;
  padding: 0 9px;
  border-radius: 999px;
  border: 1px solid var(--line-200);
  background: var(--ink-100);
  color: var(--text-mid);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  white-space: nowrap;
  transition:
    color var(--dur) var(--ease),
    border-color var(--dur) var(--ease),
    background var(--dur) var(--ease);
}
.usage-pill:hover,
.usage-pill[data-on='true'] {
  color: var(--text-hi);
  border-color: var(--line-300);
  background: var(--ink-200);
}

.usage-pill-figure {
  color: var(--text-hi);
}
.usage-pill-sep,
.usage-pill-unit {
  color: var(--text-dim);
}

/*
 * One bar, used at three sizes. Colour only enters as it fills: a meter that is
 * always coloured says nothing, and the point of this readout is to be ignorable
 * until it is not.
 */
.usage-meter {
  display: block;
  flex: 0 0 auto;
  width: 34px;
  height: 4px;
  border-radius: 2px;
  background: var(--ink-400);
  overflow: hidden;
}
.usage-meter i {
  display: block;
  height: 100%;
  border-radius: 2px;
  background: var(--text-lo);
  transition:
    width 260ms var(--ease),
    background var(--dur) var(--ease);
}
.usage-meter[data-level='mid'] i {
  background: var(--accent);
}
.usage-meter[data-level='high'] i {
  background: var(--attention);
}
/* Shares stay quiet — see the note in UsagePill. */
.usage-meter[data-level='share'] i {
  background: var(--text-lo);
}

/* ---- the panel ---------------------------------------------------------- */

.usage-panel {
  position: absolute;
  top: 30px;
  right: 0;
  z-index: 70;
  width: 320px;
  border-radius: var(--r-lg);
  border: 1px solid var(--line-200);
  background: var(--glass);
  backdrop-filter: blur(20px);
  box-shadow: var(--shadow-lg);
  animation: usage-in 160ms var(--ease) both;
  overflow: hidden;
}

@keyframes usage-in {
  from {
    opacity: 0;
    transform: translateY(-4px);
  }
}

.usage-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 10px 9px 14px;
}

.usage-title {
  font-size: var(--fs-md);
  color: var(--text-hi);
}

.usage-source {
  flex: 1;
  text-align: right;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-dim);
}

.usage-tabs {
  display: flex;
  gap: 2px;
  margin: 0 12px 4px;
  padding: 2px;
  border-radius: var(--r-md);
  background: var(--ink-100);
}
.usage-tabs button {
  flex: 1;
  height: 26px;
  border-radius: calc(var(--r-md) - 2px);
  color: var(--text-lo);
  font-size: var(--fs-sm);
  transition:
    background var(--dur) var(--ease),
    color var(--dur) var(--ease);
}
.usage-tabs button[data-on='true'] {
  background: var(--ink-300);
  color: var(--text-hi);
}

.usage-body {
  padding: 8px 14px 4px;
}

.usage-window + .usage-window {
  margin-top: 14px;
}

.usage-window-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 6px;
}
.usage-window-name {
  font-size: var(--fs-sm);
  color: var(--text-hi);
}
.usage-window-reset {
  flex: 1;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-dim);
}
.usage-window-pct {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-hi);
}

/* The bar inside the panel spans the card rather than the pill's 34px. */
.usage-window .usage-meter,
.usage-model .usage-meter {
  width: auto;
  flex: 1;
  height: 5px;
}
.usage-window .usage-meter {
  width: 100%;
}

.usage-window-detail {
  margin-top: 5px;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-lo);
}

.usage-models {
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid var(--line-100);
}

.usage-model {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-top: 8px;
}
.usage-model-name {
  width: 74px;
  flex: 0 0 auto;
  font-size: var(--fs-sm);
  color: var(--text-mid);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.usage-model-figure {
  width: 46px;
  flex: 0 0 auto;
  text-align: right;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-lo);
}

.usage-foot {
  margin-top: 12px;
  padding: 10px 14px 12px;
  border-top: 1px solid var(--line-100);
}

.usage-note,
.usage-warn {
  display: block;
  font-size: var(--fs-micro);
  line-height: 1.55;
  color: var(--text-dim);
}
.usage-warn {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  color: var(--attention);
}

.usage-more {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-top: 9px;
  color: var(--text-mid);
  font-size: var(--fs-sm);
  transition: color var(--dur) var(--ease);
}
.usage-more:hover {
  color: var(--text-hi);
}

/* ---- the Codex readout, beside the Claude one -------------------------- */

.cu-codex {
  margin-top: 26px;
  padding-top: 18px;
  border-top: 1px solid var(--line-100);
}

.cu-windows {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 10px;
}

.cu-window-head,
.cu-window-foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}
.cu-window-name {
  color: var(--text-hi);
  font-size: var(--fs-sm);
}
.cu-window-num {
  color: var(--text-mid);
  font-size: var(--fs-micro);
  font-variant-numeric: tabular-nums;
}
.cu-window-foot {
  margin-top: 4px;
  color: var(--text-lo);
  font-size: var(--fs-micro);
  font-variant-numeric: tabular-nums;
}

.cu-bar {
  height: 5px;
  margin-top: 6px;
  border-radius: 999px;
  background: var(--ink-300);
  overflow: hidden;
}
/* scaleX rather than width: this animates on the compositor, not in layout. */
.cu-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--accent);
  transform-origin: left center;
  transition: transform var(--dur) var(--ease);
}

/* ---- token-usage.css ---- */
/*
 * Token usage.
 *
 * A headline figure, the shape of the spending beside it, the five counts it
 * decomposes into, and two tables. The chart is drawn in its own coordinate
 * space and stretched by the box, so it fills whatever width the stage gives
 * it without the component knowing anything about pixels.
 *
 * Secondary text here is --text-lo, not --text-dim: --text-dim clears WCAG's
 * 3:1 floor in none of the app's 20 themes (1.62 at worst), and every number
 * on this surface is read rather than decorative.
 */

.tu {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line-200);
  border-radius: var(--r-md);
  background: var(--ink-100);
  overflow: hidden;
}

.tu-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  flex-wrap: wrap;
}

.tu-window {
  flex: 1;
  min-width: 0;
  color: var(--text-lo);
  font-size: var(--fs-micro);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tu-sep {
  margin: 0 5px;
  opacity: 0.6;
}

.tu-controls {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
}

/* A segmented control: one lit, the rest quiet, no border between them. */
.tu-seg {
  display: inline-flex;
  padding: 2px;
  border-radius: var(--r-sm);
  background: var(--ink-200);
}
.tu-seg button {
  padding: 3px 9px;
  border: 0;
  border-radius: 4px;
  background: none;
  color: var(--text-lo);
  font-size: var(--fs-micro);
  cursor: pointer;
  transition:
    color var(--dur) var(--ease),
    background var(--dur) var(--ease);
}
.tu-seg button:hover {
  color: var(--text-hi);
}
.tu-seg button[data-on='true'] {
  background: var(--ink-400);
  color: var(--text-hi);
}

.tu-body {
  display: grid;
  grid-template-columns: minmax(180px, 230px) 1fr;
  gap: 18px;
  padding: 4px 14px 16px;
}
/* Below this the chart has no width worth having, so it goes under. */
@media (max-width: 900px) {
  .tu-body {
    grid-template-columns: 1fr;
  }
}

.tu-total {
  font-size: var(--fs-xl);
  color: var(--text-hi);
  line-height: 1.1;
  letter-spacing: -0.02em;
}
.tu-star {
  color: var(--text-lo);
}

.tu-foot {
  margin: 4px 0 0;
  color: var(--text-lo);
  font-size: var(--fs-micro);
}

/* The line that says the figure above is not a bill. */
.tu-free {
  margin: 2px 0 0;
  color: var(--live);
  font-size: var(--fs-micro);
}

.tu-legend {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.tu-legend li {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: var(--fs-micro);
}
.tu-legend-name {
  flex: 1;
  min-width: 0;
  color: var(--text-mid);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tu-legend-n {
  color: var(--text-hi);
  font-family: var(--font-mono);
}
.tu-legend-pct {
  width: 34px;
  color: var(--text-lo);
  font-family: var(--font-mono);
  text-align: right;
}

.tu-swatch {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 2px;
  background: var(--accent);
}

.tu-chart {
  display: flex;
  gap: 8px;
  min-width: 0;
}

/* Spread top to bottom so each label sits on the gridline it names. */
.tu-axis {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  flex: 0 0 auto;
  padding-bottom: 16px;
  color: var(--text-lo);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  text-align: right;
}

.tu-plot {
  flex: 1;
  min-width: 0;
}
.tu-plot svg {
  display: block;
  width: 100%;
  height: 150px;
}

.tu-grid {
  stroke: var(--line-100);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

.tu-area {
  fill: var(--accent);
  opacity: 0.16;
}

/* non-scaling-stroke, or the horizontal squash would thin the line. */
.tu-line {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.5;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

.tu-xaxis {
  display: flex;
  justify-content: space-between;
  margin-top: 4px;
  color: var(--text-lo);
  font-size: var(--fs-micro);
}
.tu-xaxis span:nth-child(2) {
  /* The middle label is centred on the chart, not on its own slot. */
  transform: translateX(-50%);
  margin-left: 50%;
}
.tu-xaxis span:last-child {
  margin-left: auto;
}

/* ---- the five counts ---------------------------------------------------- */

.tu-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 1px;
  border-top: 1px solid var(--line-100);
  background: var(--line-100);
}

.tu-stat {
  padding: 11px 14px;
  background: var(--ink-100);
}

.tu-stat-label {
  color: var(--text-lo);
  font-size: var(--fs-micro);
}

.tu-stat-value {
  margin-top: 3px;
  color: var(--text-hi);
  font-size: var(--fs-base);
}
.tu-stat-sub {
  color: var(--text-lo);
  font-size: var(--fs-micro);
}

/* ---- the two tables ------------------------------------------------------ */

/*
 * Two tables, each its own height.
 *
 * `align-items: start` matters: as equal-height grid items the shorter table
 * stretched to match the taller one and its rows shared out the slack, which
 * turned 27px rows into 47px ones on whichever table happened to be shorter.
 * The divider is a real border for the same reason — a 1px gap showing a
 * coloured background underneath only works while both items fill the row.
 */
.tu-tables {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: start;
  border-top: 1px solid var(--line-100);
  background: var(--ink-100);
}
.tu-table + .tu-table {
  border-left: 1px solid var(--line-100);
}
@media (max-width: 900px) {
  .tu-tables {
    grid-template-columns: 1fr;
  }
}

.tu-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--ink-100);
  font-size: var(--fs-micro);
}

.tu-table th {
  padding: 10px 14px 7px;
  color: var(--text-lo);
  font-weight: 400;
  text-align: left;
  white-space: nowrap;
}

.tu-table td {
  padding: 6px 14px;
  color: var(--text-mid);
  vertical-align: middle;
}

/* The name cell carries the bar, which sits under the text rather than beside
   it — a column of its own would cost the width the names need. */
.tu-table td:first-child {
  position: relative;
  color: var(--text-hi);
  max-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tu-table td:first-child .tu-swatch {
  display: inline-block;
  margin-right: 7px;
  vertical-align: middle;
}

.tu-num {
  text-align: right;
  font-family: var(--font-mono);
  white-space: nowrap;
}
.tu-dim {
  color: var(--text-lo);
}

/* Which of these is the whole list and which is a page of it. */
.tu-all {
  color: var(--text-lo);
  font-family: var(--font-ui);
}

.tu-ws-name {
  position: relative;
  z-index: 1;
}

.tu-ws-bar {
  position: absolute;
  left: 14px;
  bottom: 2px;
  height: 2px;
  border-radius: 1px;
  background: var(--accent);
  opacity: 0.3;
  max-width: calc(100% - 28px);
}

.tu-table tfoot td {
  padding-top: 9px;
  padding-bottom: 11px;
  border-top: 1px solid var(--line-100);
  color: var(--text-hi);
}

.tu-reading {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 0;
  padding: 9px 14px;
  border-top: 1px solid var(--line-100);
  color: var(--text-lo);
  font-size: var(--fs-micro);
}

/* ---- accounts.css ---- */
/*
 * Claude accounts in Settings.
 *
 * A row per account, laid out the way an account switcher is everywhere else —
 * mark, name, plan, and the state on the right — because that arrangement is
 * the one nobody has to read twice. The whole row is the switch; the only
 * separate control is removal, which is the one action worth making distinct.
 */

.account-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 14px;
}

/* Shell, mark and type come from settings-rows.css, shared with the host and
   integration rows. Only what is the account row's own stays here. */
.account {
  cursor: pointer;
  transition:
    border-color var(--dur) var(--ease),
    background var(--dur) var(--ease);
}
.account:hover {
  border-color: var(--line-300);
  background: var(--ink-200);
}
.account:focus-visible {
  outline: none;
  border-color: var(--accent-edge);
  box-shadow: 0 0 0 3px var(--accent-wash);
}
/* The active one is not a hover state that got stuck, so it holds the accent. */
.account[data-active='true'] {
  border-color: var(--accent-edge);
  background: var(--accent-wash);
  cursor: default;
}

.account-mark {
  background: var(--ink-300);
  color: var(--text-mid);
}
.account[data-active='true'] .account-mark {
  background: var(--accent);
  border-color: transparent;
  color: var(--on-accent);
}

.account-body {
  display: flex;
  flex-direction: column;
  gap: 1px;
  flex: 1;
  min-width: 0;
}
.account-name {
  display: flex;
  align-items: center;
  gap: 7px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Colour and size: settings-rows.css. */
.account-meta {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Says which account every other tool on the machine is already using. */
.account-tag {
  flex: 0 0 auto;
  padding: 1px 6px;
  border-radius: 999px;
  border: 1px solid var(--line-200);
  color: var(--text-dim);
  font-size: var(--fs-micro);
  font-weight: 400;
}

.account-on {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  flex: 0 0 auto;
  color: var(--accent);
  font-size: var(--fs-micro);
}
/* Shown only on hover: every inactive row would otherwise shout "Switch". */
.account-switch {
  flex: 0 0 auto;
  color: var(--text-dim);
  font-size: var(--fs-micro);
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}
.account:hover .account-switch,
.account:focus-visible .account-switch {
  opacity: 1;
}

.account-confirm {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 10px 12px;
  margin-bottom: 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--danger);
  background: var(--ink-100);
  color: var(--text-mid);
  font-size: var(--fs-sm);
}
.account-confirm > span {
  flex: 1;
}
.account-confirm svg {
  flex: 0 0 auto;
  color: var(--danger);
}

.account-add {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

/* ---- the sign-in ---------------------------------------------------------- */

.account-login {
  margin-top: 14px;
  padding: 13px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  background: var(--ink-050);
}

.account-step {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--text-mid);
  font-size: var(--fs-sm);
  line-height: 1.45;
}
.account-step svg {
  flex: 0 0 auto;
  color: var(--text-dim);
}
.account-step[data-tone='good'] svg {
  color: var(--accent);
}
.account-step[data-tone='bad'] svg {
  color: var(--danger);
}

.account-code {
  display: flex;
  gap: 7px;
  margin-top: 11px;
}
.account-code input {
  flex: 1;
  min-width: 0;
  height: 32px;
  padding: 0 10px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-200);
  background: var(--ink-100);
  color: var(--text-hi);
  /* A pasted code is a string of characters to be checked, not read. */
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
}
.account-code input:focus {
  outline: none;
  border-color: var(--accent-edge);
  box-shadow: 0 0 0 3px var(--accent-wash);
}

.account-link {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  margin-top: 10px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text-dim);
  font-size: var(--fs-micro);
  cursor: pointer;
}
.account-link:hover {
  color: var(--text-mid);
}

/* The last thing Claude Code drew, when the flow was not recognised. */
.account-output {
  max-height: 190px;
  margin: 11px 0 0;
  padding: 9px 10px;
  overflow: auto;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-100);
  background: var(--ink-200);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-all;
}

.account-login-foot {
  display: flex;
  justify-content: flex-end;
  margin-top: 12px;
}

/* ---- the Codex sign-in hand-off ---------------------------------------- */

/*
 * There is no browser flow to drive here, so this is a short set of
 * instructions rather than a dialog that follows along: make a home, run the
 * command, come back. It is deliberately plain — the work is happening in a
 * terminal a few centimetres away.
 */
.cx-pending {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--accent-edge);
  background: var(--accent-wash);
}

.cx-cmd {
  padding: 8px 10px;
  border-radius: var(--r-sm);
  background: var(--ink-300);
  color: var(--text-mid);
  font-size: var(--fs-micro);
  overflow-x: auto;
  white-space: nowrap;
  user-select: all;
}

.cx-pending-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* ---- remote hosts --------------------------------------------------------
   Same row as an account: mark, name, detail. They are the same kind of thing
   — something you pick and then work inside — so they look alike. */

.host-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 14px;
}

/* The host row's shell and mark are settings-rows.css entirely. */
.host-mark {
  background: var(--ink-300);
  color: var(--text-mid);
}

.host-body {
  display: flex;
  flex-direction: column;
  gap: 1px;
  flex: 1;
  min-width: 0;
}
.host-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Mono because an address is one. Colour and size: settings-rows.css. */
.host-meta {
  font-family: var(--font-mono);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.host-add {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.host-form {
  display: grid;
  grid-template-columns: 2fr 1fr 0.7fr;
  gap: 10px;
  padding: 13px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  background: var(--ink-050);
}
.host-form-wide {
  grid-column: 1 / -1;
}
.host-form label {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-width: 0;
}
.host-form label > span {
  color: var(--text-dim);
  font-size: var(--fs-micro);
}
.host-form input {
  height: 30px;
  padding: 0 10px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-200);
  background: var(--ink-100);
  color: var(--text-hi);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
}
.host-form input:focus {
  outline: none;
  border-color: var(--accent-edge);
  box-shadow: 0 0 0 3px var(--accent-wash);
}

.host-form-foot {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 8px;
}
.host-form-foot > .stats-note {
  flex: 1;
  margin: 0;
}

/* ---- integrations.css ---- */
/*
 * Connected services in Settings.
 *
 * Same row grammar as the account switcher — mark, body, state on the right —
 * so the two settings pages read as one app. The one addition is the strip of
 * variable names, which is the only thing on the page that is genuinely
 * diagnostic: it says which half of a two-part credential you are missing
 * without ever saying what either half contains.
 */

.ig-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 14px;
}

/* Shell, mark and type: settings-rows.css, shared with the account and host
   rows. What stays here is what a connected service has and they do not. */
.ig-card {
  transition: border-color var(--dur) var(--ease);
}
.ig-card:hover {
  border-color: var(--line-300);
}
/* Connected is a state worth seeing at a glance down the list, not a hover. */
.ig-card[data-status='connected'] {
  border-color: var(--accent-edge);
}

/*
 * A real brand mark carries its own colour and needs a surface that reads
 * the same regardless of theme or status — the fixed --brand-bone/-ink pair
 * (never themed, see tokens.css) rather than the card's own dark/light ink
 * scale, which would fight a fixed-colour logo half the time. The provider
 * with no verified mark (Azure DevOps — no maintained brand-asset source
 * was worth a second dependency for one icon) falls back to its initial on
 * the same chip, so every row still reads as one family.
 */
.ig-mark {
  background: var(--brand-bone);
  color: var(--brand-ink);
}

.ig-body {
  display: flex;
  flex-direction: column;
  gap: 3px;
  flex: 1;
  min-width: 0;
}

.ig-name {
  display: flex;
  align-items: center;
  gap: 7px;
}

.ig-account {
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--accent-wash);
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 500;
}

/* ---- credential variables ------------------------------------------- */

.ig-envs {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 3px;
}

.ig-env {
  padding: 1px 6px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-200);
  background: var(--ink-300);
  color: var(--text-lo);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  /* The name is the whole content; wrapping it mid-token helps nobody. */
  white-space: nowrap;
}
.ig-env[data-set='true'] {
  border-color: var(--accent-edge);
  background: var(--accent-wash);
  color: var(--accent);
}
/*
 * Unset names stay legible rather than being hidden: you need to read the one
 * you have not exported yet. The strike says "absent" without dimming it to
 * the point of being unreadable, which a 10px mono face cannot afford.
 */
.ig-env[data-set='false'] {
  text-decoration: line-through;
  text-decoration-thickness: 1px;
  opacity: 0.72;
}

/* ---- state on the right --------------------------------------------- */

.ig-side {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 5px;
  flex: 0 0 auto;
}

.ig-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--line-200);
  background: var(--ink-300);
  color: var(--text-mid);
  font-size: var(--fs-micro);
  font-weight: 500;
  white-space: nowrap;
}
.ig-pill[data-status='connected'] {
  border-color: transparent;
  background: var(--accent-wash);
  color: var(--accent);
}
.ig-pill[data-status='needs-auth'] {
  border-color: transparent;
  background: rgba(245, 166, 91, 0.14);
  color: var(--attention);
}

.ig-hint {
  padding: 2px 6px;
  border-radius: var(--r-sm);
  background: var(--ink-300);
  color: var(--text-mid);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  user-select: all;
}

.ig-link {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 0;
  border: none;
  background: none;
  color: var(--text-lo);
  font-size: var(--fs-micro);
  cursor: pointer;
  transition:
    color var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}
.ig-link:hover {
  color: var(--text-hi);
}
.ig-link:active {
  transform: scale(0.97);
}
.ig-link:focus-visible {
  outline: none;
  color: var(--text-hi);
  text-decoration: underline;
}

/* ---- footer ---------------------------------------------------------- */

.ig-foot {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.ig-refresh {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 11px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  background: var(--ink-200);
  color: var(--text-hi);
  font-size: var(--fs-sm);
  cursor: pointer;
  transition:
    border-color var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}
.ig-refresh:hover:not(:disabled) {
  border-color: var(--line-300);
}
.ig-refresh:active:not(:disabled) {
  transform: scale(0.97);
}
.ig-refresh:focus-visible {
  outline: none;
  border-color: var(--accent-edge);
  box-shadow: 0 0 0 3px var(--accent-wash);
}
.ig-refresh:disabled {
  opacity: 0.55;
  cursor: default;
}

.ig-foot-note {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--text-lo);
  font-size: var(--fs-label);
}

/* ---- trial.css ---- */
/*
 * The trial strip above a set of isolated panes.
 *
 * It has to sit above the grid without stealing much from it — the agents are
 * the thing you are watching. One line per attempt, the numbers that let you
 * tell them apart, and the diff only when asked for.
 */

.trialbar {
  flex: 0 0 auto;
  padding: 9px 12px 10px;
  border-bottom: 1px solid var(--line-200);
  background: var(--ink-100);
}

.tr-head {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 8px;
}

.tr-prompt {
  flex: 1;
  min-width: 0;
  color: var(--text-hi);
  font-size: var(--fs-sm);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tr-base {
  flex: 0 0 auto;
  color: var(--text-lo);
  font-size: var(--fs-micro);
}

.tr-head-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
}

.tr-confirm {
  color: var(--text-mid);
  font-size: var(--fs-label);
}

/* ---- rows -------------------------------------------------------------- */

.tr-members {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.tr-member {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 5px 8px;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  background: var(--ink-200);
  transition: border-color var(--dur) var(--ease);
}
.tr-member:hover {
  border-color: var(--line-300);
}
.tr-member[data-won='true'] {
  border-color: var(--accent-edge);
  background: var(--accent-wash);
}

.tr-label {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  border: 1px solid var(--line-200);
  background: var(--ink-300);
  color: var(--text-hi);
  font-size: var(--fs-micro);
  font-weight: 600;
  cursor: pointer;
  transition: transform var(--dur) var(--ease);
}
.tr-label:hover {
  border-color: var(--accent-edge);
}
.tr-label:active {
  transform: scale(0.94);
}
.tr-member[data-won='true'] .tr-label {
  background: var(--accent);
  border-color: transparent;
  color: var(--on-accent);
}

.tr-body {
  display: flex;
  align-items: baseline;
  gap: 9px;
  flex: 1;
  min-width: 0;
}

.tr-stat {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  font-size: var(--fs-label);
}
.tr-stat-idle {
  color: var(--text-lo);
  font-size: var(--fs-label);
}
.tr-files {
  color: var(--text-hi);
}
/* Tabular figures: these numbers change every few seconds and must not jitter. */
.tr-add,
.tr-del {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-variant-numeric: tabular-nums;
}
.tr-add {
  color: var(--accent);
}
.tr-del {
  color: var(--danger);
}

.tr-branch {
  color: var(--text-lo);
  font-size: var(--fs-micro);
}

/* ---- actions ----------------------------------------------------------- */

.tr-link,
.tr-merge,
.tr-danger,
.tr-icon {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-200);
  background: var(--ink-300);
  color: var(--text-mid);
  font-size: var(--fs-micro);
  cursor: pointer;
  transition:
    border-color var(--dur) var(--ease),
    color var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}
.tr-link,
.tr-merge,
.tr-danger {
  padding: 3px 8px;
}
.tr-icon {
  padding: 3px;
}

.tr-link:hover,
.tr-merge:hover:not(:disabled),
.tr-icon:hover {
  color: var(--text-hi);
  border-color: var(--line-300);
}
.tr-link:active,
.tr-merge:active:not(:disabled),
.tr-icon:active,
.tr-danger:active {
  transform: scale(0.97);
}
.tr-merge:disabled {
  opacity: 0.45;
  cursor: default;
}

.tr-danger {
  border-color: transparent;
  background: var(--danger);
  color: var(--brand-bone);
}

.tr-merged {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px;
  color: var(--accent);
  font-size: var(--fs-micro);
  font-weight: 500;
}

.tr-link:focus-visible,
.tr-merge:focus-visible,
.tr-icon:focus-visible,
.tr-danger:focus-visible,
.tr-label:focus-visible {
  outline: none;
  border-color: var(--accent-edge);
  box-shadow: 0 0 0 3px var(--accent-wash);
}

/* ---- diff -------------------------------------------------------------- */

.tr-diff {
  max-height: 240px;
  margin-top: 8px;
  padding: 9px 10px;
  overflow: auto;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-200);
  background: var(--ink-300);
  color: var(--text-mid);
  font-size: var(--fs-micro);
  line-height: 1.5;
  white-space: pre;
}

.tr-won,
.tr-note {
  display: flex;
  align-items: center;
  gap: 5px;
  margin: 0 0 8px;
  color: var(--text-lo);
  font-size: var(--fs-label);
}
.tr-won {
  color: var(--accent);
}
.tr-note {
  margin: 8px 0 0;
}

/* ---- the isolation toggle in the setup wizard -------------------------- */

.iso-toggle {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  background: var(--ink-100);
  cursor: pointer;
  transition:
    border-color var(--dur) var(--ease),
    background var(--dur) var(--ease);
}
.iso-toggle:hover {
  border-color: var(--line-300);
}
.iso-toggle[data-on='true'] {
  border-color: var(--accent-edge);
  background: var(--accent-wash);
}
.iso-toggle input {
  margin-top: 2px;
  accent-color: var(--accent);
}
.iso-toggle:focus-within {
  border-color: var(--accent-edge);
  box-shadow: 0 0 0 3px var(--accent-wash);
}

.iso-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.iso-name {
  color: var(--text-hi);
  font-size: var(--fs-sm);
}
.iso-note {
  color: var(--text-mid);
  font-size: var(--fs-label);
  line-height: 1.5;
}

/* ---- host-picker.css ---- */
/*
 * Choosing local vs. remote, and picking a host, in the setup wizard.
 *
 * The tab switcher matches the settings nav's own on/off language rather than
 * inventing a new one; the host cards reuse .folder-card outright, since a
 * host in this list plays exactly the role a recent folder does one step
 * over — something you tap once to fill in "where."
 */

.loc-toggle {
  display: flex;
  gap: 4px;
  margin-bottom: 16px;
  padding: 3px;
  border-radius: var(--r-md);
  background: var(--ink-100);
  border: 1px solid var(--line-100);
}

.loc-toggle button {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  flex: 1;
  height: 32px;
  border-radius: calc(var(--r-md) - 3px);
  border: none;
  background: transparent;
  color: var(--text-mid);
  font-size: var(--fs-sm);
  cursor: pointer;
  transition:
    background var(--dur) var(--ease),
    color var(--dur) var(--ease);
}
.loc-toggle button:hover {
  color: var(--text-hi);
}
.loc-toggle button[data-on='true'] {
  background: var(--ink-300);
  color: var(--text-hi);
}
.loc-toggle button:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--accent-edge);
}

/* ---- the "Add a host" mini-form ---------------------------------------- */

.host-manual-toggle {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-top: 10px;
  padding: 0;
  border: none;
  background: none;
  color: var(--text-mid);
  font-size: var(--fs-sm);
  cursor: pointer;
  transition: color var(--dur) var(--ease);
}
.host-manual-toggle:hover {
  color: var(--text-hi);
}
.host-manual-chevron {
  transition: transform var(--dur) var(--ease);
}
.host-manual-chevron[data-open='true'] {
  transform: rotate(180deg);
}

.host-manual-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 10px;
  padding: 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-100);
  background: var(--ink-100);
}

.host-manual-row {
  display: flex;
  gap: 8px;
}
.host-manual-row .field {
  flex: 1;
}
.host-manual-port {
  max-width: 88px;
}

/* ---- settings-rows.css ---- */
/*
 * The settings row.
 *
 * Accounts, Remote hosts and Integrations all draw the same object — a mark, a
 * name with a line under it, and a control on the right — and each had drawn it
 * separately. Measured on the real stylesheets, the same row came out at three
 * different sizes on three pages of one window:
 *
 *            padding      mark    row height
 *   account  10px 12px    30px    56px
 *   host      9px 12px    28px    53px
 *   ig-card  11px 12px    30px    81px
 *
 * None of that was decided; it is three people landing within two pixels of
 * each other. `integrations.css` even opens by saying it uses "the same row
 * grammar as the account switcher" — the intent was always one row, so this is
 * that row, in one place, rather than three that have to be kept in step by
 * hand.
 *
 * Loaded after the three panel sheets so this is the last word on the grammar
 * they share; everything that is genuinely particular to one of them stays in
 * its own file and still wins by being more specific.
 *
 * Deliberately NOT unified, because the content differs rather than the taste:
 *   · the integration mark's fixed bone/ink pair — a real brand logo needs a
 *     surface that does not move with the theme (see integrations.css)
 *   · the mono face on a host's address, which is an address
 *   · each row's own status colours and hover edges
 *   · the control on the right: a status pill, an add button and a switch
 *     button are three different acts and should not look like one
 */

.account,
.host-row,
.ig-card {
  display: flex;
  gap: 11px;
  padding: 10px 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  background: var(--ink-100);
}

/* Two lines centre on the mark; three lines start at it, or the glyph floats
   in the middle of a stack it is meant to label. */
.account,
.host-row {
  align-items: center;
}
.ig-card {
  align-items: flex-start;
}

.account-mark,
.host-mark,
.ig-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  border-radius: 999px;
  border: 1px solid var(--line-200);
  font-size: var(--fs-sm);
  font-weight: 600;
}

.account-name,
.host-name,
.ig-name {
  color: var(--text-hi);
  font-size: var(--fs-sm);
  font-weight: 500;
}

/*
 * One secondary step, not three — and no `--text-dim` anywhere in this row.
 *
 * Integrations was running its description at 12px and its diagnostic line at
 * 11px — `--fs-label`, which nothing else in the settings area uses at all —
 * while every other page said 10px. A description the same size as the name it
 * sits under is what made those cards half again as tall as the rows beside
 * them. Size is uniform now and colour carries the hierarchy instead.
 *
 * On the colour: these lines are not decoration. `ubuntu@10.0.0.4 · port 22`,
 * `Claude Max · current`, `LINEAR_API_KEY set` — you read them to decide
 * something. They were on `--text-dim`, which is the dimmest step the app has.
 *
 * CONTRAST IS PER THEME, so no fixed ratio belongs in this comment. themes.ts
 * derives the text tokens as `mix(fg, bg, t)` at a constant t for every theme
 * — textMid 0.30, textLo 0.52, textDim 0.68 — so identical CSS lands at a
 * different ratio in each palette, depending only on how far apart that
 * theme's fg and bg are. Measured across all 20 themes, this row's value line
 * against its own `--ink-100`:
 *
 *   on --text-dim (before)   every one of the 20 under 3.0, best 2.84
 *   on --text-lo  (now)      17 of 20 clear 3.0; spread 2.17 → 4.66
 *
 * The three still short are Catppuccin Latte 2.17, Solarized Light 2.69 and
 * One Dark 2.77 — low-contrast palettes by design, which is the point of them,
 * so a fixed 52% mix cannot clear the floor there. Fixing those three properly
 * means clamping the derivation in themes.ts against measured contrast rather
 * than trusting a constant, which is a whole-app change and not this file's to
 * make. If it lands, this row gets it for free.
 */
.account-meta,
.host-meta,
.ig-detail {
  font-size: var(--fs-micro);
  color: var(--text-lo);
}

/* A step brighter again, because it is the one line that is a description
   rather than a value, and should read first. `--text-mid` clears 3.0 in all
   20 themes (worst: Catppuccin Latte at 3.39). */
.ig-blurb {
  font-size: var(--fs-micro);
  color: var(--text-mid);
}

/* ---- tasks.css ---- */
/*
 * Work waiting for you, in the side dock.
 *
 * The dock is narrow, so a row is two lines: what it is on top, and the
 * details that let you tell two similar-looking tickets apart underneath.
 * The tone stripe down the left is the only colour on a row — it carries
 * open/draft/merged/closed at a glance without a badge for each.
 */

.wk-panel {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.wk-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 6px;
}

/* ---- filters ------------------------------------------------------------ */

.wk-filters {
  display: flex;
  gap: 3px;
}

.wk-filter {
  padding: 3px 8px;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-lo);
  font-size: var(--fs-micro);
  cursor: pointer;
  transition:
    color var(--dur) var(--ease),
    background var(--dur) var(--ease);
}
.wk-filter:hover {
  color: var(--text-hi);
}
.wk-filter[data-on='true'] {
  background: var(--ink-300);
  color: var(--text-hi);
}
.wk-filter:focus-visible {
  outline: none;
  border-color: var(--accent-edge);
}

/* ---- rows --------------------------------------------------------------- */

.wk-row {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 8px 9px 8px 10px;
  margin-bottom: 4px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-100);
  border-left-width: 2px;
  background: var(--ink-100);
  transition: border-color var(--dur) var(--ease);
}
.wk-row:hover {
  border-color: var(--line-300);
}
/* The one piece of colour on the row, and it means state. */
.wk-row[data-tone='open'] {
  border-left-color: var(--accent);
}
.wk-row[data-tone='draft'] {
  border-left-color: var(--text-lo);
}
.wk-row[data-tone='merged'] {
  border-left-color: var(--hue-violet);
}
.wk-row[data-tone='closed'] {
  border-left-color: var(--danger);
}

.wk-icon {
  flex: 0 0 auto;
  margin-top: 1px;
  color: var(--text-lo);
}

.wk-body {
  display: flex;
  flex-direction: column;
  gap: 3px;
  flex: 1;
  min-width: 0;
}

.wk-title-line {
  display: flex;
  align-items: baseline;
  gap: 6px;
  min-width: 0;
}

.wk-ref {
  flex: 0 0 auto;
  padding: 0;
  border: none;
  background: none;
  color: var(--text-lo);
  font-size: var(--fs-micro);
  cursor: pointer;
  transition: color var(--dur) var(--ease);
}
.wk-ref:hover {
  color: var(--accent);
  text-decoration: underline;
}

.wk-title {
  flex: 1;
  min-width: 0;
  color: var(--text-hi);
  font-size: var(--fs-sm);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.wk-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  font-size: var(--fs-micro);
  color: var(--text-lo);
}

.wk-state {
  text-transform: lowercase;
}
.wk-state[data-tone='open'] {
  color: var(--accent);
}
.wk-state[data-tone='merged'] {
  color: var(--hue-violet);
}
.wk-state[data-tone='closed'] {
  color: var(--danger);
}

.wk-review {
  display: inline-flex;
  align-items: center;
  gap: 3px;
}
.wk-review[data-kind='approved'] {
  color: var(--accent);
}
.wk-review[data-kind='changes'] {
  color: var(--attention);
}

.wk-label {
  padding: 0 5px;
  border-radius: var(--r-sm);
  background: var(--ink-300);
  color: var(--text-mid);
}

/* ---- actions ------------------------------------------------------------ */

.wk-actions {
  display: flex;
  align-items: center;
  gap: 4px;
  flex: 0 0 auto;
}

.wk-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-200);
  background: var(--ink-300);
  color: var(--text-mid);
  font-size: var(--fs-micro);
  cursor: pointer;
  white-space: nowrap;
  transition:
    border-color var(--dur) var(--ease),
    color var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}
.wk-btn:hover:not(:disabled) {
  color: var(--text-hi);
  border-color: var(--line-300);
}
.wk-btn:active:not(:disabled) {
  transform: scale(0.97);
}
.wk-btn:disabled {
  opacity: 0.45;
  cursor: default;
}
.wk-btn-primary {
  border-color: var(--accent-edge);
  color: var(--accent);
}
.wk-btn:focus-visible {
  outline: none;
  border-color: var(--accent-edge);
  box-shadow: 0 0 0 3px var(--accent-wash);
}

/* ---- notes -------------------------------------------------------------- */

.wk-note {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin: 6px 2px;
  color: var(--text-lo);
  font-size: var(--fs-label);
  line-height: 1.5;
}
.wk-note-warn {
  color: var(--text-mid);
}
.wk-note-warn svg {
  flex: 0 0 auto;
  margin-top: 2px;
  color: var(--attention);
}

/* ---- new Linear issue --------------------------------------------------- */

.wk-new {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px;
  margin-bottom: 8px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  background: var(--ink-100);
}

.wk-select,
.wk-input {
  width: 100%;
  padding: 6px 8px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-200);
  background: var(--ink-300);
  color: var(--text-hi);
  font-size: var(--fs-sm);
}
.wk-select:focus,
.wk-input:focus {
  outline: none;
  border-color: var(--accent-edge);
}
.wk-textarea {
  min-height: 54px;
  resize: vertical;
  font-family: inherit;
}

/* ---- pull request review -------------------------------------------------
 * Files/Changes/Review, opened from a PR's row. Files lists the changeset
 * grouped by directory (from `gh pr view --json files`, no diff parsing
 * needed for the counts); Changes shows one file's patch, reusing GitPanel's
 * own DiffView; Review is the three ways to answer it.
 */

.pr-stat {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  padding: 8px 10px;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  border-bottom: 1px solid var(--line-100);
}

.pr-add {
  color: var(--live);
}
.pr-del {
  color: var(--danger);
}
.pr-dim {
  color: var(--text-dim);
}

.pr-tabs {
  display: flex;
  gap: 4px;
  flex: 0 0 auto;
  padding: 6px 8px;
  border-bottom: 1px solid var(--line-100);
}

.pr-tab {
  padding: 3px 10px;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-lo);
  font-size: var(--fs-micro);
  cursor: pointer;
  transition:
    color var(--dur) var(--ease),
    background var(--dur) var(--ease);
}
.pr-tab:hover {
  color: var(--text-hi);
}
.pr-tab[data-on='true'] {
  background: var(--ink-300);
  color: var(--text-hi);
}

.pr-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.pr-files {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 4px;
}

.pr-file {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  height: 26px;
  padding: 0 8px;
  border: none;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-mid);
  font-size: var(--fs-sm);
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.pr-file:hover {
  background: var(--ink-100);
  color: var(--text-hi);
}
.pr-file[data-on='true'] {
  background: var(--ink-300);
  color: var(--text-hi);
}

.pr-file-icon {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  color: var(--text-lo);
}
.pr-file-icon[data-kind='ADDED'] {
  color: var(--live);
}
.pr-file-icon[data-kind='DELETED'] {
  color: var(--danger);
}

.pr-file-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pr-file-stat {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
}

.pr-review-form {
  flex: 1;
  min-height: 0;
  display: grid;
  align-content: start;
  gap: 8px;
  padding: 10px;
}

/* ---- the full-page pull request browser --------------------------------- *
 *
 * The dock's Work tab and this page render the same rows from the same fetch;
 * everything below is the difference a full stage makes. The list keeps the
 * dock's row, because a pull request should not look like two different things
 * in two places, and spends the extra width on a preview beside it instead.
 */

.pr-page {
  height: 100%;
  min-height: 0;
}

/*
 * Wider than the 210px `.panel-split` gives a dock sidebar. A pull request
 * row carries a ref, a title, a state and an author, and at 210px the title
 * is ellipsed to nothing — which is the one part you pick a row by.
 */
.pr-page-split {
  grid-template-columns: minmax(320px, 30%) 1fr;
}

.pr-page-side {
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-right: 1px solid var(--line-100);
}

.pr-page-head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
  padding: 10px;
  border-bottom: 1px solid var(--line-100);
}
/* The same field as everywhere else, at the height a toolbar wants. */
.pr-page-head .field {
  flex: 1;
  min-width: 0;
  height: 28px;
  padding: 0 9px;
  gap: 7px;
}
.pr-page-head .field input {
  font-size: var(--fs-micro);
}

.pr-page-count {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  padding: 8px 6px 4px 10px;
}

/* ---- a row you can pick ------------------------------------------------- */

.pr-row {
  padding: 0 4px 0 0;
  align-items: stretch;
}
.pr-row[data-on='true'] {
  border-color: var(--accent-edge);
  background: var(--accent-wash);
}

/*
 * The clickable body of the row. Carries the padding `.wk-row` would normally
 * own, so the hit area reaches the edges of the row rather than stopping
 * short of them.
 */
.pr-pick {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  flex: 1;
  min-width: 0;
  padding: 8px 4px 8px 10px;
  background: none;
  border: none;
  text-align: left;
}
.pr-pick:focus-visible {
  outline: 2px solid var(--accent-edge);
  outline-offset: -2px;
  border-radius: var(--r-sm);
}
/* Not a link in here — the whole row is the target. */
.pr-row .wk-ref {
  cursor: inherit;
}
.pr-row .wk-ref:hover {
  color: var(--text-lo);
  text-decoration: none;
}

.pr-row .wk-actions {
  align-self: center;
}

/* ---- nothing came back -------------------------------------------------- */

/*
 * Danger rather than the attention colour the dock uses for the same notes.
 * There, a note sits under a list that still has work in it. Here it *is* the
 * list — no remote, no CLI, no folder — and every one of those is something
 * the person has to go and fix before this page shows anything at all.
 */
.pr-fail {
  display: grid;
  gap: 10px;
  justify-items: start;
  margin: 6px 2px;
  padding: 12px;
  border-radius: var(--r-sm);
  border: 1px solid color-mix(in srgb, var(--danger) 38%, transparent);
  background: color-mix(in srgb, var(--danger) 8%, transparent);
}
.pr-fail-line {
  display: flex;
  align-items: flex-start;
  gap: 7px;
  margin: 0;
  color: var(--danger);
  font-size: var(--fs-label);
  line-height: 1.55;
}
.pr-fail-line svg {
  flex: 0 0 auto;
  margin-top: 2px;
}
.pr-fail-line strong {
  font-weight: 600;
}

/* ---- the preview side --------------------------------------------------- */

.pr-page-preview {
  min-width: 0;
}
.pr-page-empty {
  height: 100%;
  align-content: center;
  gap: 10px;
  padding: 40px;
}
.pr-page-empty svg {
  color: var(--text-dim);
}

/* ---- reading one pull request ------------------------------------------- *
 *
 * The right-hand pane in preview mode: what a pull request says, then what it
 * changes. Everything below the header reuses the review panel's own classes
 * (.pr-stat, .pr-files, .pr-file) so the two modes of this pane do not look
 * like two different products.
 */

.pr-preview {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
}

.pr-head {
  flex: 0 0 auto;
  display: grid;
  gap: 8px;
  padding: 12px 12px 10px;
  border-bottom: 1px solid var(--line-100);
}
.pr-head-top {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}
.pr-head-title {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-size: var(--fs-md);
  font-weight: 600;
  line-height: 1.35;
  color: var(--text-hi);
}
.pr-head-meta {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
  font-size: var(--fs-micro);
  color: var(--text-lo);
}
.pr-head-author::before {
  /* "by ada" reads as a sentence where a bare name reads as another label. */
  content: 'by ';
  color: var(--text-dim);
}
.pr-head-branches {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 7px;
  border-radius: 999px;
  border: 1px solid var(--line-200);
  color: var(--text-lo);
}
.pr-head-branches svg {
  color: var(--text-dim);
}

.pr-preview-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 12px;
}

/*
 * The description, in the same type the Pages surface renders a README in.
 * Boxed rather than bare so it reads as "what the author wrote" and not as
 * part of this app's own chrome.
 */
.pr-body-md {
  margin-bottom: 14px;
  padding: 2px 12px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-100);
  background: var(--ink-100);
}
.pr-body-md .fp-markdown {
  padding: 0;
}

/* ---- the changed files -------------------------------------------------- */

.pr-preview .pr-stat {
  margin-bottom: 4px;
}

.pr-file-caret {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  color: var(--text-dim);
  transition: transform var(--dur) var(--ease);
}
.pr-file-caret[data-open='true'] {
  transform: rotate(90deg);
}

/* The path in full, with only the last part in reading colour — a list of
   twelve files in four directories is unreadable without it. */
.pr-file-dir {
  color: var(--text-dim);
}

.pr-file-diff {
  margin: 2px 0 8px 18px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-100);
  overflow: hidden;
}
.pr-file-diff .wk-note {
  align-items: center;
  margin: 8px 10px;
}

/* ---- preview.css ---- */
/*
 * Rich previews: rendered markdown, images, PDFs.
 *
 * The markdown styles exist to make marked's plain output readable — nothing
 * here is decorative for its own sake, since this is meant to read like a
 * document, not like the rest of the app's UI chrome.
 */

.fp-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 100%;
  min-height: 160px;
  padding: 20px;
  color: var(--text-lo);
  font-size: var(--fs-sm);
  text-align: center;
}
.fp-empty[data-error='true'] {
  color: var(--attention);
}

/* ---- markdown ------------------------------------------------------------ */

.fp-markdown {
  max-width: 760px;
  margin: 0 auto;
  padding: 28px 32px 60px;
  color: var(--text-hi);
  font-size: var(--fs-md);
  line-height: 1.65;
}

.fp-markdown h1,
.fp-markdown h2,
.fp-markdown h3,
.fp-markdown h4 {
  margin: 1.4em 0 0.6em;
  color: var(--text-hi);
  font-weight: 600;
  line-height: 1.3;
}
.fp-markdown h1 {
  padding-bottom: 0.3em;
  border-bottom: 1px solid var(--line-100);
  font-size: var(--fs-xl);
}
.fp-markdown h2 {
  padding-bottom: 0.25em;
  border-bottom: 1px solid var(--line-100);
  font-size: var(--fs-lg);
}
.fp-markdown h3 {
  font-size: var(--fs-md);
}
.fp-markdown p:first-child,
.fp-markdown h1:first-child,
.fp-markdown h2:first-child {
  margin-top: 0;
}

.fp-markdown p {
  margin: 0.9em 0;
}

.fp-markdown a {
  color: var(--accent);
  text-decoration: none;
}
.fp-markdown a:hover {
  text-decoration: underline;
}

.fp-markdown code {
  padding: 2px 5px;
  border-radius: var(--r-sm);
  background: var(--ink-300);
  color: var(--text-hi);
  font-family: var(--font-mono);
  font-size: 0.88em;
}
.fp-markdown pre {
  padding: 14px 16px;
  margin: 1em 0;
  border-radius: var(--r-md);
  border: 1px solid var(--line-100);
  background: var(--ink-100);
  overflow-x: auto;
}
.fp-markdown pre code {
  padding: 0;
  background: none;
  font-size: var(--fs-sm);
  line-height: 1.6;
}

.fp-markdown blockquote {
  margin: 1em 0;
  padding: 2px 16px;
  border-left: 3px solid var(--line-300);
  color: var(--text-mid);
}

.fp-markdown ul,
.fp-markdown ol {
  margin: 0.8em 0;
  padding-left: 1.6em;
}
.fp-markdown li {
  margin: 0.3em 0;
}
.fp-markdown li input[type='checkbox'] {
  margin-right: 6px;
  accent-color: var(--accent);
}

.fp-markdown table {
  width: 100%;
  margin: 1em 0;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}
.fp-markdown th,
.fp-markdown td {
  padding: 7px 10px;
  border: 1px solid var(--line-100);
  text-align: left;
}
.fp-markdown th {
  background: var(--ink-100);
  font-weight: 600;
}

.fp-markdown img {
  max-width: 100%;
  border-radius: var(--r-sm);
}

.fp-markdown hr {
  margin: 1.6em 0;
  border: none;
  border-top: 1px solid var(--line-100);
}

/* ---- images ---------------------------------------------------------- */

.fp-image-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  padding: 20px;
  overflow: auto;
}
.fp-image {
  max-width: 100%;
  max-height: 100%;
  border-radius: var(--r-sm);
  object-fit: contain;
}

/* ---- pdf --------------------------------------------------------------- */

.fp-pdf {
  width: 100%;
  height: 100%;
  border: none;
  background: var(--ink-100);
}

/* ---- pages.css ---- */
/*
 * Pages — the repository's own markdown, read as documents.
 *
 * Almost nothing new. The shell is the dock panel layout every other
 * side-by-side surface uses (.panel / .panel-bar / .panel-split), the rendered
 * document is the preview body's own styling, and the scroller is the one the
 * preview pane already scrolls with. What is here is the list on the left,
 * which is a row shape the app did not have yet: a document name with the
 * folder it came from underneath it.
 */

.pages-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 4px 6px 7px;
}

/*
 * Secondary text here is `--text-lo`, not `--text-dim`.
 *
 * `--text-dim` is the dimmest step the app derives, and measured across all 20
 * themes it clears WCAG's 3:1 floor in none of them — 1.62 at worst, 2.84 at
 * best. That is fine for a glyph sitting beside a label it merely decorates,
 * and not fine for anything you actually read. Everything below that carries a
 * value — a line number, a path, a count — sits a step brighter.
 */

.pages-count {
  color: var(--text-lo);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
}

.pages-row {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px 8px;
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  color: var(--text-mid);
  text-align: left;
  cursor: pointer;
}
.pages-row:hover {
  background: var(--ink-200);
  color: var(--text-hi);
}
.pages-row:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--accent-wash);
}
/* The one being read. Held in the accent rather than a hover shade, so it
   still reads as chosen once the pointer has gone somewhere else. */
.pages-row[data-on='true'] {
  background: var(--accent-wash);
  color: var(--text-hi);
}
.pages-row svg {
  flex: 0 0 auto;
  color: var(--text-dim);
}
.pages-row[data-on='true'] svg {
  color: var(--accent);
}

.pages-row-body {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.pages-name {
  font-size: var(--fs-sm);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Where the document came from. Two files called README are only telling you
   apart by this line, so it is present whenever the file is not at the top. */
.pages-dir {
  color: var(--text-lo);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---- search.css ---- */
/*
 * Find in files.
 *
 * The shell is the panel every other full-surface page uses; what is new is the
 * result list, which is two row shapes stacked — a file heading, then the lines
 * found in it. The lines are monospaced and never wrap: a matching line is code
 * being scanned down a column, and wrapping turns that column into prose.
 */

.search-page .panel-bar {
  gap: 10px;
}

/*
 * Secondary text here is `--text-lo`, not `--text-dim`.
 *
 * `--text-dim` is the dimmest step the app derives, and measured across all 20
 * themes it clears WCAG's 3:1 floor in none of them — 1.62 at worst, 2.84 at
 * best. That is fine for a glyph sitting beside a label it merely decorates,
 * and not fine for anything you actually read. Everything below that carries a
 * value — a line number, a path, a count — sits a step brighter.
 */

.sr-clear {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  padding: 0;
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  color: var(--text-lo);
  cursor: pointer;
}
.sr-clear:hover {
  background: var(--ink-200);
  color: var(--text-hi);
}

.sr-count {
  flex: 0 0 auto;
  color: var(--text-lo);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  white-space: nowrap;
}

.sr-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

.sr-list {
  padding: 6px;
}
/* A search is running and these are the previous one's answers. Dimmed rather
   than cleared, because blanking the list on every keystroke is the flicker
   this avoids — the old answer is still the best one available. */
.sr-list[data-stale='true'] {
  opacity: 0.55;
}

.sr-file {
  margin-bottom: 10px;
}

.sr-file-head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 6px;
  color: var(--text-mid);
  /* Held in place while its lines scroll past, so you never lose track of
     which file you are reading matches from. */
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--ink-000);
}
.sr-file-head svg {
  flex: 0 0 auto;
  color: var(--text-dim);
}

.sr-file-name {
  font-size: var(--fs-sm);
  white-space: nowrap;
}

/* The path, which is how two files of the same name are told apart. Truncated
   from the left: the end of a path says more than its beginning. */
.sr-file-dir {
  flex: 1;
  min-width: 0;
  color: var(--text-lo);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  direction: rtl;
  text-align: left;
}

.sr-file-count {
  flex: 0 0 auto;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--ink-200);
  color: var(--text-lo);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
}

.sr-hit {
  display: flex;
  align-items: baseline;
  gap: 8px;
  width: 100%;
  padding: 2px 6px;
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  color: var(--text-mid);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  text-align: left;
  cursor: pointer;
}
.sr-hit:hover {
  background: var(--ink-200);
  color: var(--text-hi);
}
.sr-hit:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--accent-wash);
}

/* Right-aligned in a fixed column so the line text starts on one edge however
   many digits the numbers happen to have. */
.sr-no {
  flex: 0 0 auto;
  width: 40px;
  color: var(--text-lo);
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* One line, never wrapped, clipped where it runs out. The main process already
   windowed anything long around its match, so what arrives here is the part
   worth reading. */
.sr-line {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: pre;
}

.sr-mark {
  border-radius: 2px;
  background: var(--accent-wash);
  color: var(--text-hi);
}

.sr-capped {
  margin: 2px 6px 6px;
}

/* ---- automations.css ---- */
/*
 * Automations page.
 *
 * Only what the shared classes do not already give. The rows are `.wk-row`
 * from the tasks panel and the shell is `.panel` / `.panel-bar`, so what is
 * left here is the create form and the few row details that are this page's
 * own.
 */

.automations {
  min-width: 0;
}

.auto-bar-spacer {
  flex: 1;
}

.auto-count {
  font-size: var(--fs-micro);
  color: var(--text-dim);
  white-space: nowrap;
}

.auto-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 8px;
}

/* ---- the create form --------------------------------------------------- */

.auto-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px;
  margin-bottom: 10px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-200);
  background: var(--ink-100);
}

.auto-form-head,
.auto-form-foot {
  display: flex;
  align-items: center;
  gap: 8px;
}
.auto-form-head .eyebrow {
  flex: 1;
}

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

.auto-label {
  font-size: var(--fs-micro);
  color: var(--text-dim);
}

/*
 * Auto-fit rather than fixed columns: the time field only exists while the
 * trigger is `daily`, and a fixed three-column grid would leave a hole on
 * the other two.
 */
.auto-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px;
}

.auto-prompt {
  width: 100%;
  min-height: 72px;
  resize: vertical;
}

.auto-folder {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.auto-folder .wk-input {
  flex: 1;
  min-width: 0;
}

.auto-hint {
  font-size: var(--fs-micro);
  color: var(--text-dim);
}

/* ---- rows -------------------------------------------------------------- */

/* The folder an automation runs in, which is half of what identifies it. */
.auto-cwd {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 220px;
}

/* ---- roster.css ---- */
/*
 * The agent roster: the agents inside a workspace, under its row in the rail.
 *
 * Indented to start under the workspace's name rather than its glyph, so the
 * rail reads as one hierarchy — project, workspace, the agents in it — instead
 * of three lists that happen to be stacked.
 *
 * Nothing here uses `--text-dim`. It derives to under 3:1 against its own
 * background in every theme we ship, and these rows are small text carrying
 * the only live status the rail has. `--text-lo` is the quietest token that
 * still clears the floor.
 */

.ros {
  margin: 1px 0 3px 22px;
  border-radius: var(--r-md);
  border: 1px solid transparent;
}

/* Open, it is a card: the rows belong to each other and not to the rail. */
.ros[data-open='true'] {
  border-color: var(--line-100);
  background: var(--ink-100);
  padding: 2px;
}

.ros[data-nested='true'] {
  margin-left: 34px;
}

.ros-head {
  display: flex;
  align-items: center;
  gap: 7px;
  width: 100%;
  height: 24px;
  padding: 0 6px;
  border-radius: var(--r-sm);
  color: var(--text-lo);
  font-size: var(--fs-micro);
  text-align: left;
  transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
}

.ros-head:hover {
  color: var(--text-hi);
  background: var(--ink-300);
}

.ros-title {
  flex: 1;
  min-width: 0;
  font-variant-numeric: tabular-nums;
}

/* Shut, the marks overlap slightly — a stack of agents, not a row of icons. */
.ros-marks {
  display: flex;
  align-items: center;
}

.ros-mini {
  display: inline-grid;
  place-items: center;
  margin-right: -4px;
  padding: 1px;
  border-radius: 999px;
  background: var(--ink-200);
}

.ros-mini:last-child {
  margin-right: 3px;
}

.ros-chev {
  display: inline-grid;
  place-items: center;
  flex: 0 0 auto;
  opacity: 0.7;
}

.ros-list {
  display: flex;
  flex-direction: column;
  margin: 1px 0 0;
  padding: 0;
  list-style: none;
}

.ros-row {
  display: flex;
  align-items: center;
  gap: 7px;
  width: 100%;
  height: 24px;
  padding: 0 6px;
  border-radius: var(--r-sm);
  color: var(--text-mid);
  font-size: var(--fs-micro);
  text-align: left;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}

.ros-row:hover {
  background: var(--ink-300);
  color: var(--text-hi);
}

.ros-mark {
  display: inline-grid;
  place-items: center;
  flex: 0 0 auto;
}

.ros-name {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-hi);
}

/* The state pushes the clock to the right edge and takes the slack itself. */
.ros-state {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-lo);
}

.ros-row[data-state='attention'] .ros-state {
  color: var(--attention);
}

.ros-row[data-state='working'] .ros-state {
  color: var(--live);
}

.ros-row[data-state='exited'] .ros-state {
  color: var(--danger);
}

.ros-when {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--text-lo);
}

/* ---- the state dot ------------------------------------------------------
 * One character's worth of status, in the two places that show it: the head
 * of each row, and the collapsed chip, where it stands for the loudest agent
 * in there.
 */

.ros-dot {
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: var(--text-lo);
}

.ros-dot[data-state='idle'] {
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--text-lo);
}

.ros-dot[data-state='exited'] {
  background: var(--danger);
}

.ros-dot[data-state='attention'] {
  background: var(--attention);
}

.ros-dot[data-state='working'] {
  background: var(--live);
  animation: ros-pulse 1.8s var(--ease) infinite;
}

@keyframes ros-pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.35;
  }
}

/* The dot is a colour and a shape as well as a blink, so stilling it loses
   nothing — the same reason the pane glyph's pulse is stilled here too. */
[data-reduce-motion='true'] .ros-dot[data-state='working'] {
  animation: none;
}
