:root {
  color-scheme: light;
  --ink: #1c1917;
  --muted: #57534e;
  --muted-2: #706a64; /* captions/meta that are read as real content — 5.1:1 on --paper, passes 4.5:1 AA (was #a8a29e at 2.4:1, HN2) */
  --muted-3: #8c8681; /* decorative-only: disabled controls, placeholders, separators, unlabeled state dots — exempt from text contrast, kept ≥3:1 non-text minimum */
  --paper: #fafaf9;
  --panel: #ffffff;
  --panel-strong: #f5f5f4;
  --line: #e7e5e4;
  --line-strong: #d6d3d1;
  --red: #c62828;
  --red-deep: #a61f1f;
  --red-tint: #fdeaea;
  --steel: #57534e;
  --teal: #0f766e;
  --teal-tint: #e6f4f2;
  --amber: #d97706;
  --amber-text: #b45309; /* TEXT ONLY: 5.0:1 on white, 4.6:1 on --amber-tint. Never a border/background/icon -- those stay on --amber. */
  --amber-tint: #fdf3e3;
  --stone-tint: #f5f5f4;
  --shadow: 0 1px 3px rgba(28, 25, 23, 0.06);
  --shadow-float: 0 16px 40px rgba(28, 25, 23, 0.14);
  --font-sans: "Google Sans", "Noto Sans Thai", "Roboto", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: var(--font-sans);
  --background: var(--paper);
  --surface: var(--panel);
  --border: var(--line);
  --secondary: var(--muted);
  --misumi-red: var(--red);
  --radius-card: 8px;
  --radius-panel: 8px;
  --radius-control: 8px;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  min-height: 100vh;
  color: var(--ink);
  background: var(--paper);
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.55;
  /* Tabular figures keep numeric columns (scores, QA counts, queue tiles)
     aligned instead of drifting per-digit with proportional numerals (HN6).
     This only changes digit glyph width -- it has no effect on non-numeric
     text, Thai or English, so it is safe to set app-wide rather than
     enumerate every table/stat selector. */
  font-variant-numeric: tabular-nums;
}

button,
input,
textarea,
select {
  font: inherit;
}

button {
  min-height: 40px;
  border: 0;
  border-radius: 8px;
  padding: 0 16px;
  color: white;
  background: var(--red);
  cursor: pointer;
  font-weight: 600;
  font-size: 13.5px;
  /* A button label breaking into a staircase of 2-3 lines reads as a bug even
     when the button still works (doc 45 #9 -- seen repeatedly: "Create
     Project", "Add run plan", "Start with Copilot"). Fixing this once at the
     element level is more durable than chasing each instance; a button whose
     label genuinely needs to wrap can opt back in with a modifier class. */
  white-space: nowrap;
}

button:hover {
  background: var(--red-deep);
}

button:disabled {
  cursor: not-allowed;
  background: var(--line-strong);
}

button[aria-busy="true"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.loading-spinner {
  width: 16px;
  height: 16px;
  flex: 0 0 16px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 999px;
  animation: busy-spin 0.72s linear infinite;
}

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

.app-busy-indicator {
  position: fixed;
  top: 14px;
  left: 50%;
  z-index: 60;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 38px;
  max-width: min(520px, calc(100vw - 32px));
  transform: translateX(-50%);
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  padding: 0 14px;
  color: var(--ink);
  background: var(--panel);
  box-shadow: var(--shadow-float);
  font-size: 13px;
  font-weight: 600;
}

.loading-state {
  display: flex;
  align-items: center;
  gap: 12px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--amber);
  border-radius: 8px;
  padding: 14px;
  color: var(--steel);
  background: rgba(217, 119, 6, 0.06);
}

.loading-state b,
.loading-state span {
  display: block;
  line-height: 1.45;
}

.loading-state span {
  color: var(--muted);
  font-size: 13px;
}

button.secondary {
  color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--line-strong);
}

button.secondary:hover {
  color: var(--ink);
  background: var(--panel-strong);
}

button.ghost {
  color: var(--muted);
  background: transparent;
  border: 1px solid transparent;
}

button.ghost:hover {
  color: var(--ink);
  background: var(--panel-strong);
}

button.tiny-inline {
  width: auto;
  min-height: 0;
  margin-left: 8px;
  padding: 4px 8px;
  font-size: 12px;
}

input:not([type="checkbox"]):not([type="radio"]):not(.sr-only),
textarea,
select {
  width: 100%;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--panel);
  color: var(--ink);
  outline: none;
}

input:not([type="checkbox"]):not([type="radio"]):not(.sr-only),
select {
  min-height: 40px;
  padding: 0 12px;
}

textarea {
  min-height: 190px;
  resize: vertical;
  padding: 14px;
  line-height: 1.55;
}

/* Checkboxes/radios are not text inputs — the bare `input` rules above set
   box metrics meant for text fields (width:100%, min-height:40-42px) and
   were leaking onto every checkbox in the app (owner-reported, 2026-08-08:
   53 checkboxes on Projects computed 26x42px inside 28x28px label boxes).
   Give them their own deliberate, small size here, early in the cascade, so
   component-level rules further down (.project-select-control,
   .project-team-checkbox, .bp-checkline, agent-picker) can still opt into a
   different size without fighting source order. */
input[type="checkbox"],
input[type="radio"] {
  width: 16px;
  height: 16px;
  min-height: 0;
  margin: 0;
  padding: 0;
  accent-color: var(--red);
}

input:focus,
textarea:focus,
select:focus {
  border-color: var(--red);
  box-shadow: 0 0 0 3px rgba(198, 40, 40, 0.12);
}

.login-shell {
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px 20px;
  background: var(--paper);
}

.login-brand {
  position: absolute;
  top: 22px;
  left: 26px;
  display: flex;
  align-items: center;
  gap: 9px;
  font-weight: 600;
  font-size: 13px;
}

.login-env {
  position: absolute;
  bottom: 18px;
  right: 26px;
  color: var(--muted-2);
  font-size: 11px;
}

.login-card {
  width: min(380px, 100%);
  padding: 34px 30px 26px;
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  background: var(--panel);
  box-shadow: var(--shadow);
  display: grid;
  gap: 16px;
}

.login-logo {
  width: 40px;
  height: 40px;
  border-radius: 10px;
}

.login-card h2,
.topbar h2,
.panel h3,
.side h1 {
  margin: 0;
  letter-spacing: 0;
}

.login-card h2 {
  font-size: 18px;
}

.login-sub {
  margin: 4px 0 0;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.6;
}

.login-foot {
  margin: 0;
  border-top: 1px solid var(--line);
  padding-top: 14px;
  color: var(--muted-2);
  font-size: 12px;
  text-align: center;
  line-height: 1.6;
}

.login-card label {
  display: grid;
  gap: 6px;
  color: var(--muted);
  font-weight: 500;
  font-size: 12px;
}

.form-error {
  min-height: 20px;
  margin: 0;
  color: var(--red);
}

.run-config-status {
  margin: 12px 0 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 10px 12px;
  color: var(--steel);
  background: rgba(68, 64, 60, 0.06);
  font-size: 13px;
  font-weight: 800;
  line-height: 1.5;
}

.run-config-status.error {
  border-color: rgba(198, 40, 40, 0.35);
  color: var(--red);
  background: rgba(198, 40, 40, 0.06);
}

.run-config-status.warn {
  border-color: rgba(217, 119, 6, 0.38);
  color: var(--amber-text);
  background: rgba(217, 119, 6, 0.08);
}

.dashboard {
  min-height: 100vh;
  display: grid;
  grid-template-columns: 224px minmax(0, 1fr);
}

.side {
  position: sticky;
  top: 0;
  height: 100vh;
  padding: 16px 12px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  color: var(--ink);
  background: var(--panel);
  border-right: 1px solid var(--line);
}

.mark {
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: 7px;
  color: white;
  background: var(--red);
  font-weight: 700;
  font-size: 11px;
  flex: 0 0 auto;
}

.side-brand {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 2px 6px;
  font-weight: 600;
  font-size: 13.5px;
}

.side nav {
  display: grid;
  gap: 2px;
}

.nav-group-label {
  margin: 12px 0 2px;
  padding: 0 10px;
  color: var(--muted-2);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
}

.side a {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--muted);
  text-decoration: none;
  border-radius: 7px;
  padding: 8px 10px;
  font-size: 13.5px;
  line-height: 1.5;
}

.side a svg {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  fill: none;
}

.side a:hover {
  color: var(--ink);
  background: var(--panel-strong);
}

.side a.active {
  color: var(--ink);
  background: var(--panel-strong);
  font-weight: 600;
}

.side a.active svg {
  color: var(--red);
}

.session-box {
  margin-top: auto;
  display: grid;
  gap: 2px;
  border-top: 1px solid var(--line);
  padding: 12px 6px 0;
}

.session-box span {
  color: var(--ink);
  font-size: 12px;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.session-box b {
  color: var(--muted-2);
  font-size: 11px;
  font-weight: 500;
}

.session-box button {
  margin-top: 8px;
  min-height: 32px;
  font-size: 12.5px;
}

/* EN | ไทย segmented switch (sidebar account box and Settings > Account). Two
   buttons, aria-pressed marks the language on screen; the pressed one is ink on
   a stone fill, not red (red stays on the one primary action). */
.lang-switch {
  display: inline-flex;
  align-self: start;
  justify-self: start;
  margin-top: 8px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--panel);
  overflow: hidden;
}

.lang-switch .lang-switch-btn {
  min-width: 44px;
  min-height: 32px;
  margin: 0;
  padding: 4px 12px;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.5;
  box-shadow: none;
}

.lang-switch .lang-switch-btn + .lang-switch-btn {
  border-left: 1px solid var(--line-strong);
}

.lang-switch .lang-switch-btn:hover {
  background: var(--panel-strong);
  color: var(--ink);
}

.lang-switch .lang-switch-btn[aria-pressed="true"] {
  background: var(--panel-strong);
  color: var(--ink);
  font-weight: 600;
}

.lang-switch .lang-switch-btn:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: -2px;
}

#accountLanguage .lang-switch {
  margin: 0 0 10px;
}

/* Shown when the Thai table could not be loaded and the page fell back to English. */
.language-notice {
  position: fixed;
  left: 50%;
  bottom: 16px;
  z-index: 60;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 12px;
  max-width: min(560px, calc(100vw - 24px));
  padding: 10px 12px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--panel);
  box-shadow: var(--shadow-float);
  color: var(--ink);
  font-size: 13px;
  line-height: 1.5;
}

.language-notice button {
  flex: 0 0 auto;
  min-height: 32px;
}

/* Thai-safe line-height (Decision 275): Thai stacks tone marks and vowels above
   and below the line, so these rules, which sit below 1.5 for Latin text, are
   raised when the page language is Thai. Icon-only buttons (line-height 1) are
   deliberately left alone. */
:lang(th) .loading-state b,
:lang(th) .loading-state span,
:lang(th) .ops-card span,
:lang(th) pre,
:lang(th) .agent-card p,
:lang(th) .run-mode-option b,
:lang(th) .audit-main p,
:lang(th) .flow-callout span,
:lang(th) .empty-state span,
:lang(th) .pending-file-row b,
:lang(th) .chat-drop-zone b,
:lang(th) .chat-drop-zone span,
:lang(th) .copilot-file-card p,
:lang(th) .copilot-review-summary span,
:lang(th) .copilot-column-item p,
:lang(th) .copilot-column-item small,
:lang(th) .copilot-action-card code,
:lang(th) .copilot-result span,
:lang(th) .run-step small,
:lang(th) .project-run-stamp,
:lang(th) .review-disclosure summary b,
:lang(th) .live-progress-meta,
:lang(th) .project-live-progress b,
:lang(th) .project-next-step b,
:lang(th) .project-action-strip b,
:lang(th) .pipeline-next b,
:lang(th) .review-checklist p b,
:lang(th) .field-card span,
:lang(th) .field-card small,
:lang(th) .topbar h2,
:lang(th) .panel h3,
:lang(th) .login-card h2,
:lang(th) .pill,
:lang(th) .skill-chip,
:lang(th) .dataset-profile-pill,
:lang(th) .agent-card-kind,
:lang(th) .bp-param-chip-remove,
:lang(th) .bp-node-head b {
  line-height: 1.5;
}

.workbench {
  min-width: 0;
  padding: 24px;
  display: grid;
  gap: 18px;
}

.topbar,
.panel {
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
}

.topbar {
  padding: 14px 18px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.topbar h2 {
  font-size: 18px;
  font-weight: 600;
}

.panel h3 {
  font-size: 14px;
  font-weight: 600;
}

.pill {
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 4px 10px;
  color: var(--muted);
  background: var(--panel);
  font-size: 11.5px;
  font-weight: 500;
}

.grid-secondary {
  display: grid;
  grid-template-columns: minmax(360px, 0.95fr) minmax(360px, 1.05fr);
  gap: 20px;
  align-items: start;
}

.workspace-setup-panel {
  margin-bottom: 20px;
}

.setup-grid,
.ops-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(180px, 1fr));
  gap: 12px;
}

.ops-card {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 12px;
  background: rgba(255, 255, 255, 0.78);
  display: grid;
  gap: 5px;
}

.ops-card b {
  color: var(--ink);
}

.ops-card span {
  color: var(--muted);
  font-size: 13px;
  line-height: 1.45;
}

/* Admin-only build/version info nested in the Runtime ops-card (Decision:
   Wave 1 build visibility). Hidden entirely for non-admins because the API
   omits the runtime block for them -- there is no empty state to style. */
.build-info {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 2px;
}

.build-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.build-chip {
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 2px 8px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--muted);
  background: var(--panel);
  line-height: 1.5;
}

.build-sha-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  padding: 3px 8px;
  background: var(--panel);
  color: var(--ink);
  font-size: 12px;
  line-height: 1.5;
  cursor: pointer;
}

.build-sha-btn:hover,
.build-sha-btn:focus-visible {
  border-color: var(--red);
  color: var(--red-deep);
}

.build-sha-btn code {
  background: transparent;
  padding: 0;
  font-size: 12px;
}

.build-sha-btn svg {
  width: 13px;
  height: 13px;
  flex: 0 0 auto;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  fill: none;
}

.build-sha-btn.copied {
  border-color: var(--teal);
  color: var(--teal);
}

.build-sha-btn.copy-failed {
  border-color: var(--red);
  color: var(--red);
}

.build-sha-copied {
  font-size: 11px;
  font-weight: 600;
}

.build-time,
.build-branch {
  margin: 0;
  color: var(--muted-2);
  font-size: 11.5px;
  line-height: 1.5;
}

.build-unknown {
  margin: 0;
  color: var(--amber-text);
  background: var(--amber-tint);
  border-radius: 6px;
  padding: 6px 8px;
  font-size: 12px;
  font-weight: 500;
  line-height: 1.5;
}

.panel {
  padding: 18px;
  min-width: 0;
}

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}

.eyebrow {
  margin: 0 0 4px;
  color: var(--muted-2);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.05em;
}

.button-row,
.inline-form {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin-top: 12px;
}

.inline-form input {
  min-width: 0;
  flex: 1 1 220px;
}

.inline-form select {
  width: 130px;
}

.project-edit-form {
  flex-wrap: wrap;
}

.muted {
  color: var(--muted);
  line-height: 1.5;
}

.stage-list {
  display: grid;
  gap: 8px;
  margin-bottom: 12px;
}

.stage {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 12px;
  background: var(--panel);
}

.stage b {
  display: block;
  margin-bottom: 6px;
}

.stage span {
  color: var(--muted);
  font-size: 13px;
}

pre {
  max-height: 430px;
  overflow: auto;
  margin: 0;
  border-radius: 8px;
  padding: 14px;
  color: #fafaf9;
  background: #1c1917;
  line-height: 1.45;
}

.agent-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.agent-card {
  min-height: 138px;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 12px;
  background: var(--panel);
}

.agent-card.runtime-skill-card {
  background: #fafaf9;
}

.agent-card-kind {
  display: inline-flex;
  margin-bottom: 8px;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 2px 7px;
  color: var(--muted);
  font-size: 11px;
  font-weight: 800;
  line-height: 1.5;
}

.agent-card b {
  display: block;
}

.agent-card p {
  margin: 8px 0;
  color: var(--muted);
  line-height: 1.35;
}

.agent-card small {
  color: var(--teal);
  font-weight: 800;
}

.table-wrap {
  overflow: auto;
  margin-top: 14px;
}

table {
  width: 100%;
  min-width: 520px;
  border-collapse: collapse;
}

th,
td {
  border-bottom: 1px solid var(--line);
  padding: 10px 8px;
  text-align: left;
  vertical-align: top;
}

th {
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  text-transform: none;
}

.temp-pass {
  margin-top: 12px;
  border: 1px solid rgba(15, 118, 110, 0.25);
  border-radius: 6px;
  padding: 12px;
  color: #075e57;
  background: rgba(15, 118, 110, 0.08);
  font-weight: 800;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.blueprint-list,
.run-list {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 10px;
}

.run-list > * {
  min-width: 0;
}

.blueprint-card,
.run-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  /* Without this, the default grid `stretch` makes the second column (the
     pill/badge) span the full row height — on #history that rendered as a
     64-276px vertical capsule the height of the whole card (owner-reported,
     2026-08-08). The badge should size to its own content. */
  align-items: start;
  gap: 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 14px;
  background: var(--panel);
}

.blueprint-card h4,
.run-card h4 {
  margin: 0 0 6px;
  min-width: 0;
  overflow-wrap: anywhere;
}

.blueprint-card p,
.run-card p {
  margin: 0;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.blueprint-library-section {
  display: grid;
  gap: 10px;
}

.blueprint-library-section + .blueprint-library-section {
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}

.blueprint-section-head,
.blueprint-card-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.blueprint-section-head h4 {
  margin: 0;
  font-size: 14px;
}

.blueprint-section-head > span,
.blueprint-card-side {
  color: var(--muted);
  font-size: 12px;
}

.blueprint-catalog-card {
  grid-template-columns: minmax(0, 1fr) minmax(180px, 0.45fr);
}

.pill.success {
  color: var(--teal);
  background: var(--teal-tint);
  border-color: transparent;
}

.pill.warning {
  color: var(--amber-text);
  background: var(--amber-tint);
  border-color: transparent;
}

.pill.danger {
  color: var(--red-deep);
  background: var(--red-tint);
  border-color: transparent;
}

/* Decision 84: parse_input override is a knowingly Hard-Rule-#2-adjacent
   owner-accepted risk exception -- this needs to read as visibly stronger
   than the generic override pill so a Manager can't stumble into it. */
.bp-hard-rule-warning {
  margin: 4px 0 8px;
  padding: 8px 10px;
  border: 1px solid var(--red);
  border-radius: 8px;
  background: var(--red-tint);
  color: var(--red-deep);
  font-size: 12px;
  line-height: 1.5;
}
/* Can hold more than one warning at a time (Hard Rule #2 override and a
   duplicated capability are independent and can both apply). */
.bp-hard-rule-warning p { margin: 0; }
.bp-hard-rule-warning p + p { margin-top: 6px; }

/* Per-stage runnable verdict. Semantic status colours only: teal = the stage
   runs the text as shown, amber = it runs but not the way the editor implies,
   red = the saved text would not reach the model at all. */
.bp-stage-check {
  margin-top: 10px;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel-strong);
  font-size: 12px;
  line-height: 1.6;
}

.bp-stage-check-verdict {
  margin: 0;
  font-weight: 600;
}

.bp-stage-check[data-verdict="ok"] { border-color: var(--teal); background: var(--teal-tint); }
.bp-stage-check[data-verdict="ok"] .bp-stage-check-verdict { color: var(--teal); }
.bp-stage-check[data-verdict="warn"] { border-color: var(--amber); background: var(--amber-tint); }
.bp-stage-check[data-verdict="warn"] .bp-stage-check-verdict { color: var(--amber-text); }
.bp-stage-check[data-verdict="block"] { border-color: var(--red); background: var(--red-tint); }
.bp-stage-check[data-verdict="block"] .bp-stage-check-verdict { color: var(--red-deep); }

.bp-stage-check-issues {
  margin: 8px 0 0;
  padding-left: 18px;
}

.bp-stage-check-issues:empty { display: none; }
.bp-stage-check-issues li + li { margin-top: 6px; }
.bp-stage-check-issues li[data-level="block"] { color: var(--red-deep); }
.bp-stage-check-issues li[data-level="warn"] { color: var(--amber-text); }

/* Per-stage trial run. */
.bp-stage-trial {
  padding: 12px 0;
  border-top: 1px solid var(--line);
}

.bp-trial-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 8px;
}

.bp-trial-controls select {
  flex: 1 1 120px;
  min-width: 0;
}

.bp-trial-controls button {
  flex: 0 0 auto;
}

.link-btn {
  padding: 0;
  border: 0;
  background: none;
  color: var(--red);
  font: inherit;
  text-decoration: underline;
  cursor: pointer;
}

/* Parameter surface for stages whose behavior is policy, not a prompt. */
.bp-stage-params {
  --bp-param-measure: 520px;
  margin-bottom: 14px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line);
}

.bp-param-list {
  margin-top: 8px;
}

.bp-param {
  padding: 8px 0;
  border-bottom: 1px solid var(--line);
}

.bp-param:last-child { border-bottom: 0; }

.bp-param-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.bp-param-name {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink);
  font-family: var(--font-mono);
}

.bp-param-default {
  font-size: 11px;
  color: var(--muted-2);
  white-space: nowrap;
}

.bp-param-help {
  margin: 2px 0 6px;
  font-size: 12px;
  line-height: 1.6;
  color: var(--muted);
}

/* A locale code is 2-8 characters. Letting the field, its label row, and its
   help text each run the full width of a 1000px column reads as broken, so the
   three share one form measure. The row divider stays full width so the list
   still reads as a list. */
.bp-param-head,
.bp-param-help,
.bp-param input[type="text"],
.bp-param input[type="number"],
.bp-param select {
  max-width: var(--bp-param-measure);
}

.bp-param input[type="text"],
.bp-param input[type="number"],
.bp-param select {
  width: 100%;
}

.bp-param-unbound {
  margin: 8px 0 0;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel-strong);
  font-size: 12px;
  line-height: 1.6;
  color: var(--muted);
}

/* Prose here explains a policy scope rather than labelling a control, so it
   gets a reading measure instead of the column's full width. */
.bp-stage-params > p.muted,
.bp-param-unbound {
  max-width: 72ch;
}

/* AI prompt editing. Deliberately a review step: the draft is shown as edits
   with reasons and never written into the stage textarea until accepted. */
.bp-prompt-ai {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}

.bp-prompt-draft {
  margin-top: 10px;
  padding: 10px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--panel-strong);
  font-size: 12px;
  line-height: 1.6;
}

/* Doc 78 R7: rule proposals that came with a drafted prompt. Amber = "needs
   your attention", not an error; no red (the editor already has its primary). */
.bp-prompt-rules {
  margin-top: 10px;
  padding: 10px;
  border: 1px solid var(--line-strong);
  border-left: 3px solid var(--amber);
  border-radius: 8px;
  background: var(--amber-tint);
  font-size: 12px;
  line-height: 1.6;
}

.bp-prompt-rules p {
  margin: 0 0 6px;
}

.bp-prompt-rules-notice {
  font-weight: 600;
  color: var(--ink);
}

.bp-prompt-draft-head {
  margin: 0 0 8px;
  font-weight: 600;
  color: var(--ink);
}

.bp-prompt-edit {
  margin-bottom: 10px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line);
}

.bp-prompt-edit:last-child {
  margin-bottom: 0;
  padding-bottom: 0;
  border-bottom: 0;
}

.bp-prompt-edit-reason {
  margin: 0 0 6px;
  color: var(--muted);
}

.bp-prompt-edit del,
.bp-prompt-edit ins {
  display: block;
  padding: 6px 8px;
  border-radius: 6px;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.6;
  white-space: pre-wrap;
  word-break: break-word;
  text-decoration: none;
}

.bp-prompt-edit del {
  background: var(--red-tint);
  color: var(--red-deep);
}

.bp-prompt-edit ins {
  margin-top: 4px;
  background: var(--teal-tint);
  color: var(--teal);
}

.bp-stage-check-prompt {
  margin-top: 8px;
}

.bp-stage-check-prompt summary {
  cursor: pointer;
  color: var(--muted);
}

.bp-stage-check-prompt pre {
  margin: 8px 0 0;
  padding: 8px;
  max-height: 260px;
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.6;
  white-space: pre-wrap;
  word-break: break-word;
}

.blueprint-card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  margin-top: 8px;
  font-size: 12px;
  color: var(--muted);
}

.blueprint-card-meta b {
  color: var(--ink);
  font-weight: 600;
  margin-right: 4px;
}

.blueprint-card-detail {
  margin-top: 8px !important;
  font-size: 12px;
}

.blueprint-card-detail b {
  color: var(--ink);
  font-weight: 600;
  margin-right: 4px;
}

.blueprint-card-side {
  align-self: start;
  line-height: 1.5;
}

.blueprint-card-side .secondary {
  margin-top: 10px;
}

.blueprint-capability-chain {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
}

.capability-pill {
  font-size: 11px;
}

.capability-arrow {
  color: var(--muted-3);
  font-size: 11px;
}

.run-card-details {
  grid-column: 1 / -1;
}

.run-card-details > summary {
  cursor: pointer;
  list-style: none;
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  margin-top: 4px;
}

.run-card-details > summary::-webkit-details-marker {
  display: none;
}

.run-card-details > summary::after {
  content: " ▸";
}

.run-card-details[open] > summary::after {
  content: " ▾";
}

.run-card-details > summary:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px;
  border-radius: 4px;
}

.run-card-details > *:not(summary) {
  margin-top: 8px;
}

.run-steps {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: repeat(5, minmax(90px, 1fr));
  gap: 8px;
  margin-top: 4px;
}

.run-step {
  border: 1px solid rgba(15, 118, 110, 0.24);
  border-radius: 6px;
  padding: 8px;
  color: #075e57;
  background: rgba(15, 118, 110, 0.08);
  font-size: 12px;
  font-weight: 800;
}

.upload-row {
  display: flex;
  gap: 10px;
  align-items: center;
  margin-top: 12px;
}

.upload-row input[type="file"]:not(.sr-only) {
  padding: 8px 12px;
  background: var(--panel);
}

.upload-row input[type="file"]::file-selector-button {
  min-height: 26px;
  margin-right: 12px;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 0 12px;
  color: var(--steel);
  background: transparent;
  font-weight: 700;
  cursor: pointer;
}

.mapping-box {
  margin-top: 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 14px;
  background: var(--panel);
}

.dataset-profile-card {
  margin-top: 10px;
  border: 1px solid rgba(47, 95, 159, 0.22);
  border-radius: 8px;
  padding: 12px;
  background: rgba(47, 95, 159, 0.05);
}

.dataset-profile-card h4 {
  margin: 0 0 8px;
  font-size: 13px;
}

.dataset-profile-card dl {
  margin: 0;
  display: grid;
  grid-template-columns: 128px minmax(0, 1fr);
  gap: 6px 10px;
  font-size: 13px;
}

.dataset-profile-card dt {
  color: var(--steel);
  font-weight: 900;
}

.dataset-profile-card dd {
  margin: 0;
  overflow-wrap: anywhere;
}

.dataset-profile-pill {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  border-radius: 999px;
  padding: 0 9px;
  background: var(--panel-strong);
  color: var(--steel);
  font-size: 12px;
  font-weight: 800;
}

.mapping-title {
  margin: 0 0 10px;
  font-size: 12px;
  font-weight: 700;
  color: var(--muted);
}

.mapping-title .muted {
  text-transform: none;
  font-weight: 600;
}

.column-role-list {
  display: grid;
  gap: 6px;
}

.column-role-row {
  display: grid;
  grid-template-columns: minmax(160px, 1.4fr) minmax(90px, 0.6fr) minmax(180px, 1fr) auto auto;
  align-items: center;
  gap: 10px;
  padding: 6px 8px;
  border: 1px solid var(--line);
  border-radius: 6px;
  font-size: 13px;
}

/* A column that feeds a source field: shown, not edited here (doc 85 P5). */
.column-role-row.is-source {
  background: var(--paper);
}

.column-role-sample {
  display: block;
  font-size: 11px;
  font-weight: 400;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

/* Head of the mapping editor (doc 85 P5): how an unmarked column reads in this
   file, the row key picker, the two quick actions, notices. */
.mapping-head {
  display: grid;
  gap: 10px;
  margin-bottom: 4px;
}

.mapping-head p {
  margin: 0;
}

.mapping-head-note,
.mapping-head-confirm {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--paper);
  font-size: 13px;
  line-height: 1.5;
}

.mapping-head-note p,
.mapping-head-confirm p {
  flex: 1 1 260px;
}

.mapping-head-confirm {
  border-color: var(--amber);
  background: var(--amber-tint);
}

.mapping-row-key {
  margin-top: 0;
  max-width: 460px;
}

.mapping-row-key select {
  min-height: 36px;
  font-size: 13px;
}

.mapping-row-key-help {
  font-weight: 400;
  line-height: 1.5;
}

.mapping-quick {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
  font-size: 12px;
  line-height: 1.5;
}

.mapping-count-line {
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
}

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

/* Reference role picked but not yet saved because the locale is still
   unresolved -- see pendingReferenceRoles in app.js. Amber is this app's
   semantic pending/warn color; the row border makes the state visible at a
   glance even in a long column list where #uploadStatus has scrolled away. */
.column-role-row.is-pending-locale {
  border-color: var(--amber, #d97706);
  background: var(--amber-tint, #fdf3e3);
}

.column-role-needs-locale {
  display: inline-flex;
  align-items: center;
  padding: 3px 8px;
  border-radius: 999px;
  border: 1px solid rgba(217, 119, 6, 0.32);
  background: #fff;
  color: var(--amber-text);
  font-size: 11px;
  font-weight: 700;
  line-height: 1.5;
  white-space: normal;
}

/* A role the server suggested from the header for a file that predates
   output-role seeding (upload.suggestedColumnRoles): in the draft, not yet
   saved. Same amber pending language as .is-pending-locale -- the operator is
   being asked to confirm, and until Save the run writes nowhere these rows
   claim. */
.column-role-row.is-suggested {
  border-color: var(--amber, #d97706);
  border-style: dashed;
}

.column-role-suggested {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: 999px;
  border: 1px solid rgba(217, 119, 6, 0.32);
  color: var(--amber-text);
  font-size: 10px;
  font-weight: 700;
  line-height: 1.5;
  white-space: nowrap;
}

.column-role-suggested-note {
  margin: 0 0 8px;
}

.column-role-name {
  overflow-wrap: anywhere;
}

.column-role-name b {
  margin-right: 6px;
  color: var(--muted);
}

.column-role-detected {
  font-size: 11px;
  color: var(--muted);
}

.column-role-row select {
  min-height: 34px;
  font-size: 12px;
}

.column-role-detail {
  display: flex;
  align-items: center;
  gap: 8px;
}

.column-role-detail[hidden] {
  display: none;
}

/* Baseline locale is a single per-file choice above the column list
   (Decision 4), not a checkbox on every reference row -- see
   #baselineLocaleSelect / renderBaselineLocaleControls() in app.js. */
.baseline-locale-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  margin-bottom: 10px;
}

.baseline-locale-label {
  margin-top: 0;
  min-width: 200px;
}

.baseline-locale-detected {
  padding-bottom: 8px;
  font-size: 12px;
}

/* Decision 184: output language is a per-run override next to baseline
   locale, never confused with it -- baseline locale is "which locale's
   uploaded WYSIWYG is the template", output language is "what language the
   generated text ships in". See #outputLanguageSelect / #baselineLocaleHint. */
.output-language-label {
  margin-top: 0;
  min-width: 200px;
}

.baseline-locale-hint {
  margin: -2px 0 10px;
  font-size: 12px;
}

/* #mappingArea (index.html) wraps Column Mapping + Column Roles + this bar
   together, and nothing else -- it is a plain block box with no overflow of
   its own, so it does not create a scroll container that would trap the
   sticky bar below. It exists only so the bar's containing block ends right
   after itself instead of at the bottom of #uploadPreview. */
.mapping-area {
  display: block;
}

/* Column Mapping + Column Roles are a local draft now (edit, then press
   "Save mapping" once) -- this bar is the commit point, reusing .step-footer's
   layout for the buttons and .pill for the unsaved-changes indicator.
   Sticky (not fixed, no JS scroll listener) so Save/Discard stay reachable
   on a real file with 100+ column-role rows without scrolling past all of
   them first -- same technique .side (the app nav) already uses. It floats
   only while #mappingArea is still below the viewport bottom; once that
   wrapper's own end (this bar's normal position) comes into view the bar
   settles into place, so it never overlaps the preview table's Show more/
   Show all controls or the outer step footer that follow it in #uploadPreview. */
.mapping-actions {
  position: sticky;
  bottom: 0;
  z-index: 2;
  margin-top: 14px;
  padding-bottom: 12px;
  background: var(--panel);
}

.mapping-dirty-indicator {
  white-space: nowrap;
}

.mapping-actions-hint {
  font-size: 12px;
}

.mapping-actions-hint.warn {
  color: var(--amber-text);
  font-weight: 700;
}

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

.settings-label {
  display: grid;
  gap: 6px;
  margin-top: 12px;
  font-size: 12px;
  font-weight: 700;
  color: var(--muted);
}

.run-mode-field {
  grid-column: 1 / -1;
}

.run-mode-picker {
  display: grid;
  grid-template-columns: repeat(5, minmax(112px, 1fr));
  gap: 8px;
}

.run-mode-option {
  display: grid;
  gap: 2px;
  min-height: 62px;
  align-content: center;
  justify-items: start;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 10px 12px;
  background: var(--panel);
  color: var(--ink);
  text-align: left;
}

.run-mode-option b {
  font-size: 13px;
  line-height: 1.2;
}

.run-mode-option span {
  color: var(--muted);
  font-size: 12px;
  font-weight: 700;
}

.run-mode-option.active {
  border-color: var(--red);
  box-shadow: none;
}

.run-mode-option.active b {
  color: var(--red);
}

.run-mode-option:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px;
}

.run-mode-field small {
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
}

.manual-mapping-review {
  margin-top: 16px;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 14px;
  background: var(--panel);
}

.browser-preflight {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-top: 12px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
}

.browser-preflight p {
  margin: 4px 0 0;
  max-width: 760px;
}

@media (max-width: 640px) {
  .browser-preflight {
    align-items: flex-start;
    flex-direction: column;
  }
}

.manual-mapping-summary {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.manual-mapping-group {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 12px;
  background: rgba(255, 255, 255, 0.38);
}

.manual-mapping-reference {
  grid-column: 1 / -1;
  background: var(--teal-tint);
  border-color: color-mix(in srgb, var(--teal) 28%, var(--line));
}

.manual-mapping-group b {
  display: block;
  margin-bottom: 8px;
  color: var(--ink);
  font-size: 13px;
}

.manual-mapping-list {
  display: grid;
  gap: 6px;
}

.manual-mapping-row {
  display: grid;
  grid-template-columns: minmax(112px, 0.44fr) minmax(0, 1fr);
  gap: 8px;
  align-items: baseline;
  font-size: 13px;
}

.manual-mapping-row span:first-child {
  color: var(--muted);
  font-weight: 800;
}

.manual-mapping-row span:last-child {
  overflow-wrap: anywhere;
}

.manual-mapping-row.missing span:last-child {
  color: var(--red);
  font-weight: 800;
}

.manual-mapping-warning {
  grid-column: 1 / -1;
  border: 1px solid rgba(217, 119, 6, 0.28);
  border-radius: 8px;
  padding: 10px 12px;
  color: #7a4b08;
  background: rgba(217, 119, 6, 0.1);
  font-size: 13px;
  font-weight: 700;
}

.manual-mapping-confirm {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  margin-top: 12px;
  color: var(--ink);
  font-size: 13px;
  font-weight: 800;
  line-height: 1.5;
}

.manual-mapping-confirm input {
  width: 18px;
  height: 18px;
  margin-top: 1px;
  accent-color: var(--red);
  flex: 0 0 auto;
}

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

@media (max-width: 1040px) {
  .run-mode-picker {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .manual-mapping-summary {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 680px) {
  .run-mode-picker {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .run-mode-option {
    min-height: 58px;
  }
}

.stack-form {
  display: grid;
  gap: 12px;
}

.preview-controls {
  display: flex;
  gap: 10px;
  align-items: center;
  margin-top: 12px;
}

.preview-controls span {
  margin-right: auto;
  font-size: 13px;
}

.export-box {
  margin-top: 14px;
  border: 1px solid rgba(15, 118, 110, 0.25);
  border-radius: 8px;
  padding: 14px;
  background: rgba(15, 118, 110, 0.06);
}

.export-box p {
  margin: 0;
  color: #075e57;
  font-weight: 700;
}

#batchPicker select {
  max-width: 320px;
}

.download-btn {
  display: inline-flex;
  align-items: center;
  min-height: 42px;
  border-radius: 8px;
  padding: 0 16px;
  color: white;
  background: var(--red);
  font-weight: 700;
  text-decoration: none;
}

.download-btn:hover {
  background: var(--red-deep);
}

.download-btn.secondary-link {
  color: var(--ink);
  background: transparent;
  border: 1px solid var(--line);
}

.code-cell {
  font-family: var(--font-mono);
  font-size: 13px;
  white-space: nowrap;
}

.run-export-links {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  min-width: 0;
}

/* Downloads are utilities, not the primary action of the row — brand red is
   reserved for the one CTA per view (Check rows / Retry / Resume), so these
   read as quiet secondary links: ink text, underline only on hover.
   Padding brings the clickable box to >=24px tall (WCAG 2.5.8) at the system
   floor 13px type — the old 12.5px/no-padding link was text-height only. */
.run-export-links a {
  display: inline-block;
  color: var(--ink);
  font-weight: 600;
  font-size: 13px;
  line-height: 1.55;
  text-decoration: none;
  padding: 3px 2px 4px;
  border-bottom: 1px solid var(--line-strong);
}

.run-export-links a:hover {
  color: var(--red-deep);
  border-bottom-color: currentColor;
}

/* export-bar UX review: the QA-pass count moved out of every link label into
   one line at the start of the bar, and the all-rows-vs-reviewer-decision
   distinction moved out of title= tooltips into this visible line. Scoped to
   the bar itself (not `.run-card`) so it reads the same in the three places
   runExportLinks() renders: the History run card, the Projects file-task
   preview, and the Projects run-history list — only the first of those is
   inside `.run-card`. */
.run-export-links .run-execution-note {
  flex-basis: 100%;
  margin: 2px 0 0;
  color: var(--muted);
  font-size: 11.5px;
  font-weight: 500;
  line-height: 1.5;
}

/* Owner-approved export-bar restructure: Check rows / QA pass / All rows
   (CSV) are the only three items visible on load — everything else (every
   other format, every reviewer-scoped export) collapses behind this
   disclosure, closed by default in every context. `flex: 1 1 100%` matches
   `.run-execution-note` above so it always starts its own row, whether the
   flex parent is `.run-export-links` (History/Projects run cards) or
   `.button-row` (Manual Run's #exportLinks box) — both are `display: flex;
   flex-wrap: wrap`, so this is not scoped to either parent class. */
.run-export-more {
  flex: 1 1 100%;
  margin-top: 4px;
}

/* `<summary>` must read as an affordance, not body text: same quiet
   underline-on-hover treatment as `.run-export-links a`, plus the
   open/closed caret used by `.run-node-log > summary` above. Padding keeps
   the hit target >=24px tall at the 13px floor (WCAG 2.5.8), same rationale
   as `.run-export-links a`. Default focus ring on `summary` is untouched —
   see the global `summary:focus-visible` rule. */
.run-export-more > summary {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding: 3px 2px 4px;
  color: var(--ink);
  font-weight: 600;
  font-size: 13px;
  line-height: 1.55;
  cursor: pointer;
  list-style: none;
  border-bottom: 1px solid var(--line-strong);
}

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

.run-export-more > summary::after {
  content: " ▸";
  color: var(--muted);
}

.run-export-more[open] > summary::after {
  content: " ▾";
}

.run-export-more > summary:hover {
  color: var(--red-deep);
  border-bottom-color: currentColor;
}

/* Owner-approved export-bar restructure (2026-08-27): the fixed grid of
   format x scope links (grouped by file type) became one Rows <select> x one
   Format <select> x one `<a download>` whose href/title are recomputed on
   `change` (delegated in app.js, see updateExportPickerDownload). Self-
   contained styling, not scoped to `.run-export-links`, because
   exportPickerHtml() in run-render.js renders inside both `.run-export-links`
   (History/Projects) and `.button-row` (Manual Run's #exportLinks). */
.run-export-picker {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 10px 16px;
  margin-top: 10px;
}

.run-export-empty-note {
  flex-basis: 100%;
  margin: 2px 0 0;
  color: var(--amber-text);
  font-size: 11.5px;
  font-weight: 500;
  line-height: 1.5;
}

.run-export-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.run-export-field .field-label {
  margin: 0;
}

/* min-width only — height stays the app-default 40px touch target set
   globally for select/input (see the base `select` rule near the top of this
   file). Shrinking below that default was the earlier draft of this rule. */
.run-export-field select {
  min-width: 190px;
}

.run-export-more .run-execution-note {
  flex-basis: 100%;
  margin: 0;
  color: var(--muted);
  font-size: 11.5px;
  font-weight: 500;
  line-height: 1.5;
}

/* The explanatory all-rows-vs-reviewer-decision line (run-render.js only —
   Manual Run's export box never had it) sits directly under `<details>`,
   outside any `.run-export-group`, so it needs its own top margin instead of
   the group's. */
.run-export-more > p.run-execution-note {
  margin-top: 12px;
}

/* Task/Run IDs, executor notes, evidence lines, and the skill trail are
   informational metadata, not warnings — amber-as-default made every run
   entry in History read like an error console (doc 45 finding #2). Amber is
   reserved for `.review-mini` below, the one note that is a genuine
   "do this before you rerun/export" callout. */
.run-card .run-execution-note {
  margin-top: 6px;
  color: var(--muted);
  font-size: 11.5px;
  overflow-wrap: anywhere;
  font-weight: 500;
  line-height: 1.5;
}

.run-card .run-execution-note.skill-summary {
  color: var(--muted);
}

.run-card .run-execution-note.review-mini {
  color: var(--amber-text);
  font-weight: 700;
}

.run-node-log {
  margin-top: 8px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
}

.run-node-log > summary {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
  padding: 8px 10px;
  cursor: pointer;
  list-style: none;
  line-height: 1.5;
}

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

.run-node-log > summary b {
  font-size: 12px;
  color: var(--ink);
}

.run-node-log > summary b::after {
  content: " ▸";
  color: var(--muted);
}

.run-node-log[open] > summary b::after {
  content: " ▾";
}

.run-node-log > summary span {
  font-size: 11px;
  font-weight: 500;
  color: var(--muted);
}

.run-node-log-list {
  display: grid;
  gap: 8px;
  margin: 0;
  padding: 0 10px 10px;
  list-style: none;
}

.run-node-log-entry {
  position: relative;
  display: grid;
  gap: 2px;
  padding-left: 14px;
}

/* Status reads as a dot rather than a filled badge: a run has 8-10 of these
   lines and tinted pills on every one of them would out-shout the message. */
.run-node-log-entry::before {
  content: "";
  position: absolute;
  left: 0;
  top: 7px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--teal);
}

.run-node-log-entry[data-tone="warn"]::before {
  background: var(--amber);
}

.run-node-log-entry[data-tone="error"]::before {
  background: var(--red);
}

.run-node-log-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
}

.run-node-log-stage {
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
  color: var(--ink);
}

.run-node-log-time {
  font-size: 11px;
  line-height: 1.5;
  color: var(--muted-2);
}

.run-node-log-message {
  margin: 0;
  font-size: 12px;
  font-weight: 400;
  line-height: 1.6;
  color: var(--muted);
}

.compact-row {
  margin-top: 0;
}

.compact-row select {
  min-width: 150px;
}

.audit-list {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 10px;
  margin-top: 14px;
}

.audit-list > * {
  min-width: 0;
}

.audit-entry {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 12px;
  background: var(--panel);
}

.audit-entry.warn {
  border-color: rgba(217, 119, 6, 0.35);
  background: rgba(217, 119, 6, 0.06);
}

.audit-entry.error,
.audit-entry.failed {
  border-color: rgba(198, 40, 40, 0.35);
  background: rgba(198, 40, 40, 0.06);
}

.audit-main {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 12px;
  align-items: start;
}

.audit-main b,
.audit-main p {
  margin: 0;
  /* Event names are underscore_joined tokens with no natural break point
     ("workspace_run_concurrency_updated") -- without this a long name has no
     word boundary to wrap at and spills straight over the timestamp column
     instead of wrapping (scanner-found, HN-adjacent: 24/80 entries
     overlapping at 375px, worst case 137px). */
  overflow-wrap: anywhere;
}

.audit-main p {
  margin-top: 4px;
  color: var(--muted);
  line-height: 1.45;
}

.audit-main time {
  color: var(--muted);
  font-size: 12px;
  white-space: nowrap;
}

/* At narrow widths a 3-column grid squeezes the name column to ~68px while
   the time column claims its own full-width space -- a long event name has
   nowhere to go but on top of the timestamp (scanner-found: 24/80 entries
   overlapping at 375px). Stack: level chip + time share a compact meta row,
   the name/message block gets its own full-width row below, matching the
   same "stack the card head" treatment already used for file-task rows. */
@media (max-width: 680px) {
  .audit-main {
    grid-template-columns: auto 1fr;
    grid-template-areas:
      "level time"
      "body body";
    row-gap: 4px;
  }

  .audit-main .audit-level {
    grid-area: level;
  }

  .audit-main time {
    grid-area: time;
    justify-self: end;
  }

  .audit-main > div {
    grid-area: body;
  }
}

.audit-level {
  min-width: 54px;
  border-radius: 999px;
  padding: 4px 8px;
  color: white;
  background: var(--steel);
  text-align: center;
  font-size: 11px;
  font-weight: 900;
  text-transform: uppercase;
}

.audit-entry.warn .audit-level {
  background: var(--amber);
}

.audit-entry.error .audit-level,
.audit-entry.failed .audit-level {
  background: var(--red);
}

.audit-entry pre {
  max-height: 210px;
  margin-top: 10px;
  font-size: 12px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.audit-trace {
  overflow-wrap: anywhere;
}

.changelog-list {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 14px;
  margin-top: 14px;
}

.changelog-entry {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 14px;
  background: var(--panel);
}

.changelog-entry-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 12px;
}

.changelog-date {
  order: -1;
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
}

.changelog-title {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.changelog-items {
  margin: 10px 0 0;
  padding-left: 18px;
  display: grid;
  gap: 6px;
}

.changelog-items li {
  color: var(--muted);
  font-size: 13px;
  line-height: 1.6;
  overflow-wrap: anywhere;
}

[hidden] {
  display: none !important;
}

/* ---------- views ---------- */

.view {
  display: grid;
  gap: 20px;
}

.inline-link {
  color: var(--muted);
  font-weight: 500;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.inline-link:hover {
  color: var(--ink);
}

.flow-callout,
.empty-state {
  border: 1px solid var(--line);
  border-left: 3px solid var(--teal);
  border-radius: 8px;
  padding: 12px 14px;
  background: rgba(15, 118, 110, 0.06);
}

.flow-callout {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 14px;
}

.flow-callout b,
.flow-callout span,
.empty-state b,
.empty-state span {
  display: block;
}

.flow-callout span,
.empty-state span {
  color: var(--muted);
  font-size: 13px;
  line-height: 1.45;
}

.empty-state {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
}

.empty-state span {
  flex: 1 1 320px;
}

/* ---------- copilot view ---------- */

@keyframes chatMessageIn {
  from {
    opacity: 0;
    transform: translateY(6px) scale(0.98);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* The waiting animation: three bouncing dots, the way a chat client shows the
   other side typing. This is the original typing-dots row, restored on
   2026-10-05 at the owner's request after the vendored canvas orb replaced it
   in c94979e2c. Pure CSS and a display toggle -- nothing mounts or tears down,
   and a hidden element's animation costs nothing. */
.typing-dots {
  display: none;
  align-items: center;
  gap: 4px;
  height: 14px;
}

.typing-dots span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--muted-2);
  animation: typingBounce 1.1s ease-in-out infinite;
}

.typing-dots span:nth-child(2) {
  animation-delay: 0.15s;
}

.typing-dots span:nth-child(3) {
  animation-delay: 0.3s;
}

@keyframes typingBounce {
  0%,
  60%,
  100% {
    transform: translateY(0);
    opacity: 0.5;
  }
  30% {
    transform: translateY(-4px);
    opacity: 1;
  }
}

/* Sits before the AI-draft status line and floats beside it; the status text is
   rewritten mid-flight, so the dots cannot live inside that element. The float
   keeps them on the first line when a Thai status wraps to two. Declared after
   .typing-dots so its display wins -- this variant is mounted on demand, not
   toggled. */
.typing-dots-inline {
  display: inline-flex;
  float: left;
  margin: 0 8px 2px 0;
}

/* Still legible as "waiting" when the person has asked for less motion; the
   status text next to the dots is what actually carries the meaning. */
@media (prefers-reduced-motion: reduce) {
  .typing-dots span {
    animation: none;
    opacity: 0.65;
  }
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.chat-drop-zone {
  min-height: 104px;
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  border: 1px dashed var(--line-strong);
  border-radius: 12px;
  padding: 14px;
  background: var(--paper);
  color: var(--ink);
  cursor: pointer;
  transition: border-color 140ms ease, background-color 140ms ease;
}

.chat-drop-zone:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px;
}

.chat-drop-zone.is-dragging {
  border-color: var(--teal);
  background-color: rgba(15, 118, 110, 0.07);
}

.chat-drop-zone.has-file {
  border-style: solid;
  border-color: rgba(15, 118, 110, 0.36);
  background-color: rgba(15, 118, 110, 0.045);
}

.chat-drop-zone.has-error {
  border-color: rgba(198, 40, 40, 0.48);
  background-color: rgba(198, 40, 40, 0.045);
}

.manual-drop-zone {
  margin: 12px 0;
}

/* The size-limit line under a drop zone / next to a file input -- the
   design-system caption scale (11px), muted, with its own compact spacing so
   it reads as a hint rather than another status line. */
.upload-limit-hint {
  display: block;
  margin-top: 2px;
  font-size: 11px;
  line-height: 1.5;
  color: var(--muted);
}

/* What is staged but not yet uploaded. Several drops accumulate here, so this
   is also the only place a file can be taken back out before it reaches a
   project. */
.pending-file-list {
  margin: 0 0 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  overflow: hidden;
}

.pending-file-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
}

.pending-file-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 7px 12px;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
}

.pending-file-row:last-child {
  border-bottom: 0;
}

.pending-file-row span {
  color: var(--muted);
  white-space: nowrap;
}

.pending-file-row b {
  font-weight: 500;
  overflow-wrap: anywhere;
  line-height: 1.45;
}

.pending-file-more {
  padding: 7px 12px;
  color: var(--muted);
  font-size: 13px;
}

.pending-file-list button {
  padding: 3px 10px;
  font-size: 12px;
}

.drop-zone-mark {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 1px solid rgba(68, 64, 60, 0.18);
  border-radius: 8px;
  color: var(--steel);
  background: var(--panel);
}

.drop-zone-mark svg {
  width: 22px;
  height: 22px;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.chat-drop-zone b,
.chat-drop-zone span {
  display: block;
  line-height: 1.45;
}

.chat-drop-zone b {
  font-size: 14px;
  font-weight: 700;
}

.chat-drop-zone span {
  margin-top: 3px;
  color: var(--muted);
  font-size: 13px;
  overflow-wrap: anywhere;
}

.chat-drop-zone button {
  white-space: nowrap;
}

.upload-row.compact {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
}

.copilot-file-card {
  border: 1px solid rgba(15, 118, 110, 0.22);
  border-radius: 8px;
  padding: 12px;
  background: rgba(15, 118, 110, 0.05);
}

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

.copilot-file-card-head b,
.copilot-file-card-head span {
  overflow-wrap: anywhere;
}

.copilot-file-card p {
  margin: 8px 0;
  color: var(--muted);
  line-height: 1.45;
}

.copilot-review-summary {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  margin: 10px 0 12px;
}

.copilot-review-summary span {
  display: grid;
  gap: 3px;
  min-width: 0;
  border: 1px solid rgba(68, 64, 60, 0.14);
  border-radius: 8px;
  padding: 9px 10px;
  color: var(--ink);
  background: var(--panel);
  font-size: 13px;
  line-height: 1.45;
  overflow-wrap: anywhere;
}

.copilot-review-summary b {
  color: var(--steel);
  font-size: 11px;
  font-weight: 900;
}

.copilot-review-details {
  margin-top: 8px;
  border: 1px solid rgba(68, 64, 60, 0.16);
  border-radius: 8px;
  padding: 10px 12px;
  background: rgba(255, 255, 255, 0.72);
}

.copilot-review-details summary {
  cursor: pointer;
  color: var(--steel);
  font-size: 13px;
  font-weight: 900;
}

.copilot-review-details[open] summary {
  margin-bottom: 10px;
}

.copilot-recommendations {
  margin: 10px 0 12px;
  border: 1px solid rgba(68, 64, 60, 0.16);
  border-radius: 8px;
  padding: 10px 12px;
  background: rgba(255, 255, 255, 0.78);
}

.copilot-recommendations b {
  display: block;
  margin-bottom: 6px;
}

.copilot-recommendations ul,
.copilot-action-summary {
  margin: 0;
  padding-left: 18px;
  display: grid;
  gap: 6px;
}

.copilot-recommendations li,
.copilot-action-summary li {
  line-height: 1.5;
}

.copilot-column-plan {
  margin: 10px 0 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 10px 12px;
  background: rgba(255, 255, 255, 0.72);
}

.copilot-column-plan > b {
  display: block;
  margin-bottom: 8px;
}

.copilot-column-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

.copilot-column-item {
  border: 1px solid rgba(68, 64, 60, 0.12);
  border-radius: 8px;
  padding: 9px;
  background: var(--panel);
  display: grid;
  gap: 7px;
}

.copilot-column-item span,
.copilot-column-item b,
.copilot-column-item small,
.copilot-column-item label {
  overflow-wrap: anywhere;
}

.copilot-column-item label {
  display: grid;
  gap: 5px;
  color: var(--muted);
  font-size: 12px;
  font-weight: 800;
}

.copilot-column-item select,
.copilot-column-item textarea {
  width: 100%;
  min-width: 0;
}

.copilot-column-item textarea {
  min-height: 58px;
  resize: vertical;
}

.copilot-column-item p {
  margin: 0;
  color: var(--muted);
  line-height: 1.45;
}

.copilot-column-item small {
  color: var(--muted);
  line-height: 1.4;
}

.copilot-file-card dl {
  margin: 0;
  display: grid;
  grid-template-columns: 120px minmax(0, 1fr);
  gap: 6px 10px;
  font-size: 13px;
}

.copilot-file-card dt {
  color: var(--steel);
  font-weight: 900;
}

.copilot-file-card dd {
  margin: 0;
  overflow-wrap: anywhere;
}

.copilot-reply {
  border: 1px solid rgba(15, 118, 110, 0.25);
  border-radius: 8px;
  padding: 14px;
  color: #075e57;
  background: rgba(15, 118, 110, 0.05);
  line-height: 1.55;
  font-weight: 600;
  white-space: pre-line;
}

.copilot-actions {
  display: grid;
  gap: 10px;
  margin-top: 14px;
}

.copilot-action-card {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 14px;
  background: var(--panel);
  display: grid;
  gap: 10px;
}

.copilot-action-head {
  display: flex;
  gap: 10px;
  align-items: center;
}

.copilot-index {
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: var(--red-deep);
  background: rgba(198, 40, 40, 0.08);
  font-weight: 800;
  flex: none;
}

.copilot-action-card b,
.copilot-action-card small {
  display: block;
}

.copilot-action-card small {
  margin-top: 2px;
  color: var(--muted);
  font-weight: 700;
}

.copilot-action-card p {
  margin: 0;
  color: var(--muted);
  line-height: 1.5;
}

.copilot-action-summary {
  color: var(--ink);
  font-size: 13px;
}

.copilot-technical {
  display: grid;
  gap: 8px;
}

.copilot-not-applied,
.copilot-action-target {
  display: grid;
  gap: 2px;
  margin-top: 8px;
  padding: 6px 10px;
  border: 1px solid var(--line, #e7e5e4);
  border-radius: 6px;
  background: var(--surface-muted, #fafaf9);
  color: var(--ink, #1c1917);
  font-size: 12px;
  line-height: 1.6;
  overflow-wrap: anywhere;
}

.copilot-not-applied {
  border-left: 3px solid var(--accent, #c62828);
}

.copilot-action-target small {
  color: var(--muted, #57534e);
}

.copilot-technical summary {
  cursor: pointer;
  color: var(--muted);
  font-size: 12px;
  font-weight: 800;
}

.copilot-action-card code {
  display: block;
  overflow-wrap: anywhere;
  border-radius: 6px;
  padding: 10px;
  color: #eff8f4;
  background: #17201d;
  line-height: 1.45;
}

/* U-P4/U-P5: before/after policy diff and the discarded-stage-override
   warning on a Copilot plan action card. Stacked field/value rows (not a
   fixed-column table) so long Thai labels and values wrap instead of
   overflowing at mobile widths. No colour beyond the shared amber warning
   token -- the before/after values themselves stay neutral so the diff card
   does not read as red-heavy. */
.copilot-policy-diff {
  display: grid;
  gap: 10px;
  margin: 2px 0 4px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
}

.copilot-policy-diff > b {
  display: block;
  color: var(--muted);
  font-size: 12px;
  font-weight: 800;
}

.copilot-policy-diff-section {
  display: grid;
  gap: 2px;
}

.copilot-policy-diff-section > b {
  display: block;
  margin-bottom: 2px;
  color: var(--ink);
  font-size: 13px;
  font-weight: 650;
}

.copilot-policy-diff-row {
  display: grid;
  gap: 3px;
  padding: 6px 0;
  border-top: 1px dashed var(--line);
}

.copilot-policy-diff-section > .copilot-policy-diff-row:first-of-type {
  border-top: 0;
}

.copilot-policy-diff-label {
  color: var(--muted);
  font-size: 12px;
  font-weight: 650;
  line-height: 1.5;
}

.copilot-policy-diff-values {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  color: var(--ink);
  font-size: 13px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.copilot-policy-diff-before {
  color: var(--muted);
  text-decoration: line-through;
  text-decoration-color: var(--line-strong);
}

.copilot-policy-diff-arrow {
  flex: 0 0 auto;
  color: var(--muted-2);
}

.copilot-policy-diff-after {
  color: var(--ink);
  font-weight: 650;
}

.copilot-policy-diff-value {
  display: inline;
}

.copilot-policy-diff-value summary {
  display: inline;
  cursor: pointer;
  color: inherit;
  font-weight: inherit;
}

.copilot-policy-diff-value[open] summary {
  display: block;
}

.copilot-policy-diff-value code {
  display: block;
  margin-top: 4px;
  overflow-wrap: anywhere;
  border-radius: 6px;
  padding: 8px 10px;
  color: var(--ink);
  background: var(--panel-strong);
  line-height: 1.5;
}

.copilot-policy-diff-more {
  margin-top: 2px;
}

.copilot-action-warning {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--amber);
  border-radius: 8px;
  background: var(--amber-tint);
}

.copilot-action-warning-icon {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: #ffffff;
  background: var(--amber);
  font-size: 12px;
  font-weight: 800;
  line-height: 1;
}

.copilot-action-warning b {
  display: block;
  color: var(--ink);
  font-size: 13px;
  font-weight: 650;
  line-height: 1.5;
}

.copilot-action-warning small {
  display: block;
  margin-top: 2px;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
}

.copilot-results {
  margin-top: 14px;
  display: grid;
  gap: 8px;
}

.copilot-result {
  border-radius: 8px;
  padding: 10px 12px;
  display: grid;
  gap: 4px;
}

.copilot-result.ok {
  color: #075e57;
  background: rgba(15, 118, 110, 0.09);
}

.copilot-result.fail {
  color: var(--red-deep);
  background: rgba(198, 40, 40, 0.09);
}

.copilot-result span {
  line-height: 1.45;
}

.copilot-result .copilot-result-notice {
  display: block;
  margin-top: 4px;
  color: var(--amber-text);
}

.copilot-next-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 6px;
}

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

.stepper {
  list-style: none;
  margin: 0;
  padding: 14px 18px;
  display: flex;
  gap: 8px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.94);
}

.stepper li {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--muted);
  font-weight: 700;
  font-size: 13px;
}

.stepper li:not(:last-child)::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
  margin: 0 4px;
}

.step-dot {
  width: 28px;
  height: 28px;
  flex: none;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--panel);
  color: var(--muted);
  font-size: 13px;
}

.stepper li.active .step-dot {
  border-color: var(--red);
  background: var(--red);
  color: white;
}

.stepper li.active {
  color: var(--ink);
}

.stepper li.done .step-dot {
  border-color: var(--teal);
  background: rgba(15, 118, 110, 0.1);
  color: var(--teal);
}

.stepper li.done {
  color: var(--teal);
}

.stepper li.clickable {
  cursor: pointer;
}

.stepper li.clickable:hover .step-label {
  text-decoration: underline;
}

.step-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  margin-top: 18px;
  border-top: 1px solid var(--line);
  padding-top: 14px;
}

.step-footer .muted {
  margin-right: auto;
  font-size: 13px;
}

/* ---------- blueprint picker (step 2) ---------- */

.bp-options {
  display: grid;
  gap: 10px;
  margin: 14px 0;
}

.bp-option {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 14px;
  background: var(--panel);
  cursor: pointer;
}

.bp-option.selected {
  border-color: var(--red);
  box-shadow: 0 0 0 3px rgba(198, 40, 40, 0.12);
}

.bp-option input {
  width: auto;
  min-height: 0;
  margin-top: 3px;
  accent-color: var(--red);
}

.bp-option-body b {
  display: block;
  margin-bottom: 4px;
}

.bp-option-body span {
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
}

/* ---------- run progress (step 3) ---------- */

.progress-track {
  height: 10px;
  margin-top: 4px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  overflow: hidden;
}

/* Default (amber) matches an in-progress run; JS adds .teal/.red once the
   run's actual status is known so "completed" never renders as a solid red
   bar (doc 45 P2 — a completed run reading as failure). */
.progress-fill {
  width: 0%;
  height: 100%;
  background: var(--amber);
  transition: width 0.4s ease, background 0.2s ease;
}

.progress-fill.teal { background: var(--teal); }
.progress-fill.amber { background: var(--amber); }
.progress-fill.red { background: var(--red); }

.run-step {
  border-color: var(--line);
  color: var(--muted);
  background: var(--panel);
}

.run-step small {
  display: block;
  margin-top: 4px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  line-height: 1.2;
  overflow-wrap: anywhere;
}

.run-step.done {
  border-color: rgba(15, 118, 110, 0.24);
  color: #075e57;
  background: rgba(15, 118, 110, 0.08);
}

.run-step.active {
  border-color: rgba(217, 119, 6, 0.35);
  color: #8a5708;
  background: rgba(217, 119, 6, 0.1);
}

.run-step.paused {
  border-color: rgba(217, 119, 6, 0.45);
  color: #8a5708;
  background: rgba(217, 119, 6, 0.14);
}

@media (max-width: 1040px) {
  .dashboard,
  .login-shell,
  .grid-secondary,
  .setup-grid,
  .ops-grid {
    grid-template-columns: 1fr;
  }

  .side {
    position: static;
    height: auto;
  }
}

@media (max-width: 680px) {
.workbench,
.side {
  padding: 16px;
}

  .topbar,
  .panel-head,
  .button-row,
  .inline-form,
  .flow-callout {
    align-items: stretch;
    flex-direction: column;
  }

  /* `.inline-form input { flex: 1 1 220px }` is written for the row direction
     above this breakpoint. Once the line above turns the form into a column,
     that same rule means "grow vertically, from a 220px basis" — which is why
     every inline form's text inputs rendered as ~220px-tall boxes on a phone.
     In a column the controls keep their natural height. */
  .inline-form input,
  .inline-form select,
  .inline-form button {
    flex: 0 0 auto;
  }

  .agent-grid,
  .run-steps,
  .copilot-review-summary,
  .copilot-column-grid {
    grid-template-columns: 1fr;
  }

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

  .chat-drop-zone {
    grid-template-columns: 36px minmax(0, 1fr);
  }

  .chat-drop-zone button {
    grid-column: 1 / -1;
    width: 100%;
  }

  /* Both steppers (Manual Run's #stepper and the project's #projectStepper) are
     ONE row of dots on a phone, with only the active step's name written out
     (doc 80 B4). The old column spent ~170px on four labels. The other names
     stay in the accessibility tree: see the clip rule below. */
  .stepper {
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: center;
    gap: 4px;
    padding: 8px 12px;
  }

  .stepper li {
    flex: 1 1 0;
    min-width: 0;
    min-height: 24px;
    gap: 6px;
  }

  .stepper li.active {
    flex: 0 1 auto;
  }

  /* The rule between two dots shrinks to a short connector instead of vanishing,
     so the dots still read as a sequence. */
  .stepper li:not(:last-child)::after {
    flex: 1 1 6px;
    min-width: 6px;
    margin: 0;
  }

  .stepper li:not(.active) .step-label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }

  .stepper .step-dot {
    width: 24px;
    height: 24px;
  }

  .step-footer {
    flex-direction: column;
    align-items: stretch;
  }

  .step-footer .muted {
    margin-right: 0;
  }
}

/* ---------- projects view ---------- */

.project-list,
.pipeline-list {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
  margin-top: 16px;
}

.project-list > *,
.pipeline-list > * {
  min-width: 0;
}

.project-card,
.pipeline-card {
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  padding: 16px 18px;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
}

.project-card {
  cursor: pointer;
}

.project-bulk-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 12px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-left: 4px solid var(--steel);
  border-radius: 8px;
  background: rgba(68, 64, 60, 0.06);
}

.project-bulk-bar b,
.project-bulk-bar span {
  display: block;
}

.project-bulk-bar span {
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
}

.project-bulk-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: flex-end;
}

.project-bulk-actions button {
  min-height: 34px;
  padding: 0 12px;
  font-size: 12px;
}

.project-select-control {
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
  cursor: pointer;
}

.project-select-control input {
  margin: 0;
  accent-color: var(--red);
}

.project-select-control:has(input:disabled) {
  opacity: 0.45;
  cursor: not-allowed;
}

.project-card:hover {
  border-color: var(--steel);
}

.project-card-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.project-card-actions button {
  min-height: 34px;
  padding: 0 12px;
  font-size: 12px;
}

.project-run-stamp {
  margin: 0;
  color: var(--steel);
  font-size: 12px;
  overflow-wrap: anywhere;
  font-weight: 800;
  line-height: 1.45;
}

/* ---------- project detail tabs (also the Settings tabs) ---------- */

/* Tab row: one line that scrolls sideways on a narrow screen instead of
   wrapping, and never widens the page. The panel's own bottom rule is the
   baseline the selected tab's red underline sits on. */
.project-tabs,
.settings-tabs {
  display: flex;
  flex-wrap: nowrap;
  gap: 4px;
  margin: 16px 0 14px;
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
  overflow-y: hidden;
  max-width: 100%;
  scrollbar-width: thin;
}

.project-tab,
.settings-tab {
  flex: 0 0 auto;
  margin: 0 0 -1px;
  padding: 8px 14px;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  background: transparent;
  color: var(--muted);
  font-size: 13px;
  font-weight: 500;
  line-height: 1.5;
  text-transform: none;
  letter-spacing: 0;
  white-space: nowrap;
  box-shadow: none;
  /* Snap, do not fade: a fading border makes the previous tab look underlined
     for a moment after the switch. */
  transition: color 120ms ease;
  cursor: pointer;
}

/* Higher specificity than the global button:hover lift and shadow. */
.project-tabs .project-tab:hover,
.project-tabs .project-tab:active,
.settings-tabs .settings-tab:hover,
.settings-tabs .settings-tab:active {
  color: var(--ink);
  background: transparent;
  box-shadow: none;
  transform: none;
}

.project-tab[aria-selected="true"],
.settings-tab[aria-selected="true"] {
  color: var(--ink);
  font-weight: 600;
  border-bottom-color: var(--red);
}

.project-tab:focus-visible,
.settings-tab:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: -5px;
  border-radius: 6px;
}

.project-tabpanel[hidden],
.settings-tabpanel[hidden] {
  display: none;
}

/* Settings: a tab holding one panel reads as a column, not a stretched card
   (it used to sit in half of a two-column grid). People & teams and Advanced
   keep their two-column grid, so they are not capped. The shared organization
   Save footer lines up with that column and carries the panel-footer rule. */
.settings-tabpanel > .panel,
.settings-org-save {
  max-width: 920px;
}

/* In the wider column the 140px minimum would give five squeezed columns whose
   select text is clipped; 220px keeps the research / evaluator grids to 3-4. */
.settings-tabpanel > .panel .criteria-grid {
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}

.settings-org-save {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

.settings-org-save[hidden] {
  display: none;
}

/* The page (window) is the scroller, so a field focused with Tab is scrolled
   only to the viewport edge -- right under the sticky Save bar. Reserve the
   bar's height (12px gap + padding + button row + a note line) at the bottom of
   the page's scrollport while Settings is open. Measured in Chromium: Tab focus
   honours scroll-padding on the scroller; scroll-margin on the field does not.
   At phone width the button row and notes wrap, so the bar is taller. */
html:has(#view-system:not([hidden])) {
  scroll-padding-bottom: 112px;
}

@media (max-width: 600px) {
  html:has(#view-system:not([hidden])) {
    scroll-padding-bottom: 168px;
  }
}

.project-tab-section {
  display: grid;
  gap: 12px;
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}

.project-tab-section:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

.project-edit-form + .project-tab-section {
  margin-top: 18px;
}

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

.project-tab-section-head > span:first-child {
  display: grid;
  gap: 3px;
  min-width: 0;
}

.project-tab-section-head b {
  font-size: 14px;
  font-weight: 600;
  line-height: 1.5;
}

.project-tab-section-head small {
  color: var(--muted);
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.project-tab-section > .muted,
.project-tab-section > p {
  margin: 0;
}

/* Files tab: drag state for the whole project screen, plus the upload bar. */
#projectDetailPanel.is-file-dragging {
  outline: 2px dashed var(--teal);
  outline-offset: -6px;
}

#projectDetailPanel.is-file-dragging #bulkDropZone {
  border-color: var(--teal);
  background-color: var(--teal-tint);
}

.project-bulk-upload .manual-drop-zone {
  margin: 0;
}

.bulk-plan-hint {
  margin: 0;
  font-size: 12px;
  line-height: 1.5;
}

.bulk-plan-ask {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 16px;
  padding: 10px 12px;
  border: 1px solid var(--amber);
  border-radius: 10px;
  background: var(--amber-tint);
}

.bulk-plan-ask[hidden] {
  display: none;
}

.bulk-plan-ask > div:first-child {
  display: grid;
  gap: 2px;
  min-width: 0;
  flex: 1 1 260px;
}

.bulk-plan-ask b {
  font-size: 13px;
  line-height: 1.5;
}

.bulk-plan-ask span {
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.bulk-plan-ask-error {
  flex: 1 0 100%;
  margin: 0;
  color: var(--red);
  font-size: 12px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.bulk-plan-ask-error[hidden] {
  display: none;
}

.bulk-plan-ask-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.bulk-plan-ask-controls select {
  min-width: 200px;
  max-width: 100%;
}

.bulk-upload-progress {
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  overflow: hidden;
}

.bulk-upload-row {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) auto minmax(0, 1fr) auto;
  gap: 4px 12px;
  align-items: center;
  padding: 8px 12px;
  border-top: 1px solid var(--line);
  font-size: 12px;
  line-height: 1.5;
}

.bulk-upload-row:first-child {
  border-top: 0;
}

.bulk-upload-row b {
  min-width: 0;
  overflow-wrap: anywhere;
  font-weight: 500;
}

.bulk-upload-state {
  font-weight: 600;
  color: var(--muted);
}

.bulk-upload-row.done .bulk-upload-state {
  color: var(--teal);
}

.bulk-upload-row.failed .bulk-upload-state {
  color: var(--red);
}

.bulk-upload-note {
  min-width: 0;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.bulk-upload-options {
  border-top: 1px solid var(--line);
  padding-top: 10px;
}

.bulk-upload-options summary {
  cursor: pointer;
  width: fit-content;
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
}

.bulk-upload-options summary:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 3px;
  border-radius: 6px;
}

.bulk-upload-options[open] > *:not(summary) {
  margin-top: 12px;
}

.bulk-upload-options > .muted {
  margin-bottom: 0;
  font-size: 12px;
  line-height: 1.5;
}

.bulk-manual-toggle {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 12px;
  line-height: 1.5;
}

.bulk-manual-toggle input {
  margin-top: 3px;
  flex: 0 0 auto;
}

.bulk-manual-toggle span {
  font-weight: 600;
}

.bulk-manual-help {
  margin: 4px 0 0 24px;
}

.bulk-upload-row:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: -2px;
}

.bulk-upload-options select:disabled,
.bulk-upload-options button:disabled {
  opacity: 0.55;
}

/* Settings tab: the detail form keeps its row layout, with a visible label over
   each control (the aria-labels and ids are unchanged). */
.project-edit-form {
  align-items: flex-end;
}

.project-edit-form .settings-label {
  flex: 1 1 220px;
  min-width: 0;
}

.project-edit-form .settings-label input,
.project-edit-form .settings-label select {
  width: 100%;
}

@media (max-width: 680px) {
  /* 44px touch targets for everything a thumb has to hit on this screen. */
  .project-tab,
  .settings-tab {
    min-height: 44px;
    padding: 10px 14px;
  }

  /* Stays a list-item so the disclosure marker keeps showing; the padding
     (10 + 24 line + 10) makes it a 44px target. */
  .bulk-upload-options summary {
    display: list-item;
    padding: 10px 12px 10px 0;
    line-height: 24px;
  }

  /* Settings form: one column, each label over a full-width control. The
     row layout's flex-basis is a width there, so reset it or it becomes a height. */
  .project-edit-form {
    flex-direction: column;
    align-items: stretch;
  }

  .project-edit-form .settings-label {
    flex: 0 0 auto;
    width: 100%;
  }

  .project-edit-form button[type="submit"] {
    align-self: flex-start;
  }

  .bulk-manual-toggle {
    align-items: center;
    min-height: 44px;
  }

  .bulk-manual-toggle input {
    width: 22px;
    height: 22px;
    margin-top: 0;
  }

  .bulk-upload-row button,
  .bulk-upload-progress .pending-file-head button,
  .pending-file-list button,
  .bulk-plan-ask-controls button,
  .bulk-plan-ask-controls select,
  .bulk-upload-options select,
  .bulk-upload-options button {
    min-height: 44px;
  }

  .bulk-upload-row {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .bulk-upload-note {
    grid-column: 1 / -1;
  }

  .bulk-plan-ask-controls select {
    flex: 1 1 100%;
  }
}

.project-next-step {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  margin: 12px 0 18px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-left: 4px solid var(--amber);
  border-radius: 8px;
  background: rgba(217, 119, 6, 0.06);
}

.project-next-step.teal {
  border-left-color: var(--teal);
  background: rgba(15, 118, 110, 0.07);
}

.project-next-step.red {
  border-left-color: var(--red);
  background: rgba(198, 40, 40, 0.06);
}

.project-next-more,
.review-guidance-more,
.file-task-run-details {
  min-width: 0;
}

.project-next-more > summary,
.review-guidance-more > summary,
.file-task-run-details > summary {
  cursor: pointer;
  color: var(--ink);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
}

.project-next-actions > .project-next-more[open] {
  flex-basis: 100%;
}

.project-next-more > .project-next-actions {
  margin-top: 8px;
  justify-content: flex-start;
}

/* Collapsible teaching content merged into #projectNextStep (Decision 149):
   the "why review" / "how to pass QA 95" explainer only opens when the
   operator wants it, so it does not compete with the primary next action. */
.review-disclosure {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--line-strong);
}

.review-disclosure summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  cursor: pointer;
  list-style: none;
  color: var(--ink);
}

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

.review-disclosure summary b {
  display: block;
  line-height: 1.4;
}

.review-disclosure summary small {
  display: block;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
}

.review-disclosure summary::after {
  content: "▸";
  flex: 0 0 auto;
  color: var(--muted);
  font-size: 12px;
}

.review-disclosure[open] summary::after {
  content: "▾";
}

.review-disclosure > *:not(summary) {
  margin-top: 10px;
}

.project-action-strip {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  margin: 10px 0 2px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-left: 4px solid var(--amber);
  border-radius: 8px;
  background: rgba(217, 119, 6, 0.06);
}

.project-action-strip.teal {
  border-left-color: var(--teal);
  background: rgba(15, 118, 110, 0.07);
}

.project-action-strip.red {
  border-left-color: var(--red);
  background: rgba(198, 40, 40, 0.06);
}

.project-live-progress {
  display: grid;
  gap: 8px;
  margin: 10px 0 14px;
  padding: 10px 12px;
  border: 1px solid rgba(68, 64, 60, 0.16);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.78);
}

.project-live-progress.compact {
  margin: 4px 0;
  padding: 9px 10px;
}

.live-progress-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: start;
}

.live-progress-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 14px;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.45;
}

.live-progress-meta span:first-child {
  font-family: var(--font-sans);
  color: var(--ink);
}

.project-review-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
}

.project-next-step b,
.project-action-strip b,
.project-live-progress b,
.pipeline-next b {
  display: block;
  color: var(--ink);
  line-height: 1.4;
}

.project-next-step span,
.project-action-strip span,
.project-live-progress span,
.pipeline-next span {
  display: block;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
}

.review-checklist {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
}

.review-why {
  padding: 10px 12px;
  border: 1px solid rgba(217, 119, 6, 0.24);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.76);
}

.review-why span {
  display: block;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
}

.qa95-playbook {
  padding: 10px 12px;
  /* Was a 4px side-stripe -- the only callout in the app using that shape
     (HN7); every other tint callout (.review-guidance, .project-next-step,
     etc.) is a 1px border all around with a tinted fill. Matched here so the
     callout family reads as one language. */
  border: 1px solid rgba(15, 118, 110, 0.20);
  border-radius: 8px;
  background: var(--teal-tint);
}

.qa95-playbook p {
  margin: 4px 0 0;
  color: var(--muted);
  line-height: 1.5;
}

.qa95-playbook.compact {
  margin-top: 10px;
}

.review-checklist p {
  margin: 0;
  padding: 10px;
  border: 1px solid rgba(68, 64, 60, 0.12);
  border-radius: 8px;
  background: var(--panel);
}

.review-checklist p b {
  display: block;
  color: var(--ink);
  line-height: 1.4;
}

.review-checklist p span {
  display: block;
  margin-top: 2px;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
}

#projectInlineReviewHost .review-panel {
  margin-top: 12px;
}

/* Kebab / overflow menu: a row-level "more actions" disclosure used on the
   file-task row and the run-plan card (doc 43 §1.3, §3). Mixed content
   (selects + buttons), so it is a labelled popover, not a strict ARIA menu. */
.kebab-menu {
  position: relative;
  display: inline-flex;
}

.kebab-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 34px;
  width: 34px;
  padding: 0;
  color: var(--muted);
  background: var(--panel);
  border: 1px solid var(--line-strong);
}

.kebab-trigger:hover,
.kebab-trigger[aria-expanded="true"] {
  color: var(--ink);
  background: var(--panel-strong);
}

.kebab-trigger svg {
  width: 16px;
  height: 16px;
}

.kebab-panel {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 40;
  display: grid;
  gap: 6px;
  min-width: 220px;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  box-shadow: var(--shadow-float);
}

.kebab-panel[hidden] {
  display: none;
}

.kebab-item-btn {
  display: block;
  width: 100%;
  min-height: 36px;
  padding: 0 10px;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-radius: 6px;
  text-align: left;
  font-size: 13px;
  font-weight: 500;
  line-height: 1.5;
}

.kebab-item-btn:hover {
  color: var(--ink);
  background: var(--panel-strong);
}

.kebab-item-btn.danger {
  color: var(--red-deep);
}

.kebab-item-btn.danger:hover {
  color: var(--red-deep);
  background: var(--red-tint);
}

.kebab-item-btn:disabled {
  color: var(--muted);
  background: transparent;
  cursor: not-allowed;
}

.project-next-actions {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: flex-end;
  align-items: center;
  min-width: 0;
}

.project-next-actions button,
.project-next-actions .download-btn {
  min-height: 34px;
  padding: 0 12px;
  font-size: 12px;
}

.download-btn.disabled,
.download-btn[aria-disabled="true"] {
  color: var(--muted);
  background: transparent;
  border-color: var(--line);
  pointer-events: none;
  opacity: 0.58;
}

@media (max-width: 680px) {
  .kebab-panel {
    right: auto;
    left: 0;
  }

  .project-next-step,
  .project-action-strip,
  .live-progress-head,
  .project-review-head,
  .project-review-head.project-review-head-wide,
  .project-run-row,
  .review-checklist {
    grid-template-columns: 1fr;
  }

  .project-next-actions {
    justify-content: flex-start;
  }
}

.project-card-head,
.pipeline-card-head {
  display: flex;
  align-items: center;
  gap: 10px;
  row-gap: 6px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}

.field-list {
  display: grid;
  gap: 8px;
  margin-top: 12px;
}

.field-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(160px, 0.45fr);
  gap: 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 12px;
  background: var(--panel);
}

.field-card b,
.field-card span,
.field-card small {
  display: block;
}

.field-card span,
.field-card small {
  color: var(--muted);
  font-size: 12px;
  line-height: 1.45;
}

.project-card-head h4,
.pipeline-card-head b {
  margin: 0;
  flex: 1;
  min-width: 0;
  overflow-wrap: anywhere;
}

.status-pill {
  font-size: 11px;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 999px;
  white-space: nowrap;
}

.status-pill.completed { color: var(--teal); background: rgba(15, 118, 110, 0.12); }
.status-pill.queued { color: var(--steel); background: rgba(68, 64, 60, 0.1); }
.status-pill.processing { color: var(--amber-text); background: rgba(217, 119, 6, 0.12); }
.status-pill.paused { color: var(--amber-text); background: rgba(217, 119, 6, 0.14); }
.status-pill.failed { color: var(--red); background: rgba(198, 40, 40, 0.12); }
.status-pill.cancelled { color: var(--muted); background: rgba(100, 113, 109, 0.12); }
.status-pill.uploaded { color: var(--steel); background: rgba(68, 64, 60, 0.08); }
.status-pill.idle { color: var(--muted); background: rgba(100, 113, 109, 0.1); }

.project-file-tasks,
.project-run-history,
.project-bulk-upload {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
  margin: 14px 0;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
}

.project-bulk-upload > div:first-child b,
.project-bulk-upload > div:first-child span {
  display: block;
}

.project-bulk-upload > div:first-child span,
.file-task-row span {
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
}

.project-bulk-upload > .muted {
  margin: -4px 0 0;
  font-size: 12px;
  line-height: 1.5;
}

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

.project-run-history-list {
  display: grid;
  gap: 8px;
  margin-top: 12px;
}

details.project-run-history > summary {
  cursor: pointer;
  list-style: none;
}

details.project-run-history > summary::-webkit-details-marker {
  display: none;
}

details.project-run-history > summary > div > b::after {
  content: " ▸";
  color: var(--muted);
  font-size: 12px;
}

details.project-run-history[open] > summary > div > b::after {
  content: " ▾";
}

.file-task-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 10px;
  padding: 10px;
  border: 1px solid rgba(68, 64, 60, 0.12);
  border-radius: 8px;
  min-width: 0;
}

/* The head row is now identity only -- filename and status. Actions moved to
   their own full-width row below it (`.file-task-actions`) once the kebab was
   removed: the blueprint picker that gates Run test had been hidden inside it,
   so the run flow read as "the button is greyed out for no reason". Keeping
   the actions on the head row instead would reintroduce the horizontal
   overflow measured in doc 46 finding #4 (1176px row inside a 1058px
   viewport), because a picker plus five controls cannot share a line with the
   filename at laptop width. */
.file-task-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

/* The run flow reads left-to-right (blueprint -> rows -> Run test -> Run full)
   and everything else is pushed to the far side. Delete sits at the extreme
   right, furthest from Run test, because both are now one click with no menu
   in between; `deleteProjectFile` still confirms before it deletes. */
.file-task-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 12px;
  margin-top: 10px;
  min-width: 0;
}

.file-task-actions-run,
.file-task-actions-side {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.file-task-actions button,
.file-task-actions .download-btn {
  min-height: 34px;
  padding: 0 12px;
  font-size: 12px;
}

/* Label beside its control, not above it: this is a toolbar row, so an
   above-label would push the run flow to twice the height of the buttons it
   sits next to. */
.task-inline-field {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  font-size: 12px;
  color: var(--muted);
  line-height: 1.5;
}

.task-inline-field select {
  min-width: 0;
  max-width: 240px;
}

.file-task-row b,
.file-task-row span {
  display: block;
}

.file-task-run-preview {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
  padding-top: 10px;
  border-top: 1px dashed rgba(68, 64, 60, 0.16);
  min-width: 0;
}

.file-task-run-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 12px;
  min-width: 0;
}

.file-task-run-meta > .mini-track,
.file-task-run-meta > .file-task-run-alert,
.file-task-run-meta > .file-task-run-details[open] {
  flex-basis: 100%;
}

.file-task-run-meta span,
.file-task-run-meta small {
  display: block;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
}

.file-task-run-alert {
  color: var(--red) !important;
  font-weight: 600;
}

.file-task-run-details > div {
  display: grid;
  gap: 3px;
  margin-top: 6px;
}

.file-task-run-preview .run-export-links {
  margin: 0;
}

/* Mobile file-task row, designed as a deliberate stack, not a collapsed
   desktop grid. Placed after the unconditional `.file-task-head` rule above
   so it actually wins the cascade at this width (the old shared 680px rule
   sat earlier in the file and equal-specificity source order let the
   2-column desktop rule silently override it back — that was the cause of
   the filename/status/"main file" pill overlap in doc 45 finding #1). DOM
   order already matches the desired stack: filename+pill, then status pill,
   then the actions row, so this only needs to change the axis. */
@media (max-width: 680px) {
  .file-task-head {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
  }

  .file-task-head > div:first-child {
    min-width: 0;
  }

  .file-task-head .status-pill {
    align-self: flex-start;
  }

  /* At this width the two action groups have already wrapped onto separate
     lines, so space-between would strand Delete alone on the right of its
     own line. Left-align both and let them read as one continuous list. */
  .file-task-actions {
    justify-content: flex-start;
  }
}

.file-task-review-host:empty {
  display: none;
}

.file-task-review-host .review-panel {
  margin-top: 2px;
  padding: 12px 0 0;
  border: 0;
  border-top: 1px dashed rgba(68, 64, 60, 0.18);
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}

.file-task-review-host .panel-head {
  gap: 12px;
  align-items: flex-start;
}

.file-task-review-host .row-review-table-wrap {
  max-height: min(560px, 72vh);
}

.project-run-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(260px, 0.6fr);
  align-items: center;
  gap: 12px;
  padding: 10px;
  border: 1px solid rgba(68, 64, 60, 0.12);
  border-radius: 8px;
}

.project-run-row-main {
  min-width: 0;
}

.project-run-row b,
.project-run-row span,
.project-run-row small {
  display: block;
}

.project-run-row span,
.project-run-row small {
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
}

.project-run-row-actions {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.project-run-row-actions .run-export-links {
  margin: 0;
}

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

.manual-upload-project {
  display: block;
  max-width: 460px;
  margin-top: 12px;
}

.mini-track {
  height: 8px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: #fffdf7;
  overflow: hidden;
}

.mini-fill {
  height: 100%;
  width: 0%;
  transition: width 0.4s ease;
}

.mini-fill.teal { background: var(--teal); }
.mini-fill.amber { background: var(--amber); }
.mini-fill.red { background: var(--red); }

.criteria-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 12px;
}

.criteria-grid input {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 8px 10px;
  font: inherit;
  background: var(--panel);
  color: var(--ink);
  width: 100%;
}

.settings-label.full-width {
  display: block;
  margin-top: 10px;
}

.settings-label.full-width textarea {
  width: 100%;
  min-height: 86px;
}

.criteria-grid input:focus {
  outline: 2px solid var(--red);
  outline-offset: 1px;
}

/* Read-only fact for an operator who cannot edit run concurrency — a plain
   value, not a disabled input, so it does not read as a broken control. */
.concurrency-readonly-value {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
  color: var(--ink);
}

.field-status-error {
  color: var(--red);
}

button.ghost.danger {
  color: var(--red);
  border-color: rgba(198, 40, 40, 0.4);
}

/* ---------- run config (step 2) ---------- */

.run-config-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 12px;
  margin-top: 8px;
}

.run-config-grid select {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 9px 10px;
  font: inherit;
  background: var(--panel);
  color: var(--ink);
}

/* ---------- AI draft blueprint (step 1) ---------- */

.draft-blueprint {
  margin-top: 16px;
  border: 1px dashed var(--line);
  border-radius: 10px;
  padding: 14px 16px;
  background: var(--panel);
  display: grid;
  gap: 8px;
}

.manual-workflow-builder {
  margin-top: 16px;
}

.manual-workflow-builder textarea {
  min-height: 110px;
  resize: vertical;
}

.manual-workflow-draft {
  display: grid;
  gap: 4px;
  padding-top: 4px;
  line-height: 1.55;
}

/* ---------- score distribution (step 4) ---------- */

.dist-bars {
  display: grid;
  gap: 6px;
  margin: 8px 0 16px;
}

.dist-row {
  display: grid;
  grid-template-columns: 64px 1fr 48px;
  align-items: center;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: 12px;
}

.dist-label { color: var(--muted); }
.dist-count { text-align: right; }

.dist-track {
  display: block;
  height: 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  overflow: hidden;
}

.dist-fill {
  display: block;
  height: 100%;
}

.dist-fill.teal { background: var(--teal); }
.dist-fill.amber { background: var(--amber); }
.dist-fill.red { background: var(--red); }

/* ---------- pipeline builder (node canvas) ---------- */

.bp-builder {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.bp-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}

.bp-title-group { display: flex; flex-direction: column; gap: 4px; flex: 1 1 auto; min-width: 0; }

.bp-name-input {
  width: 100%;
  min-width: 180px;
  max-width: 480px;
  font-size: 18px;
  font-weight: 700;
  color: var(--ink);
  border: 1px solid transparent;
  background: transparent;
  padding: 4px 8px;
  margin-left: -8px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.bp-name-input:hover:not(:disabled) { border-color: var(--line); }
.bp-name-input:focus { border-color: var(--red); background: var(--panel); }
.bp-name-input:disabled { color: var(--muted); background: transparent; }

.bp-toolbar-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.bp-status { margin: 0; }

.bp-policy-panel {
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  background: var(--panel);
  padding: 10px 14px;
}
.bp-policy-panel summary {
  cursor: pointer;
  margin: 0;
  padding: 2px 0;
}
.bp-policy-panel textarea {
  width: 100%;
  margin: 8px 0;
  font-family: var(--font-mono);
  font-size: 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-control);
  padding: 8px 10px;
  resize: vertical;
}
.bp-policy-panel textarea:disabled { background: var(--panel-strong); color: var(--muted-3); }
.bp-policy-panel p.muted { margin: 4px 0; font-size: 12px; }
.bp-policy-panel p.muted.small { font-size: 11px; }
.bp-policy-summary {
  list-style: none;
  margin: 8px 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.bp-policy-summary li {
  font-size: 12px;
  color: var(--ink);
  padding: 4px 8px;
  border-radius: 6px;
  background: var(--red-tint);
  width: fit-content;
}
.bp-policy-summary li.bp-policy-summary-default { background: transparent; color: var(--muted); padding: 0; }
.bp-policy-summary li.bp-policy-summary-error { background: transparent; color: var(--red); padding: 0; }
.bp-policy-raw summary { cursor: pointer; margin: 4px 0; }
.bp-policy-draft-row {
  display: flex;
  gap: 8px;
  margin: 8px 0 0;
}
.bp-policy-draft-row input[type="text"] {
  flex: 1;
  font-size: 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-control);
  padding: 7px 10px;
}
.bp-policy-draft-row input[type="text"]:disabled { background: var(--panel-strong); color: var(--muted-3); }
.bp-policy-draft-row button { white-space: nowrap; }
.bp-policy-toggle-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 10px 0 0;
  flex-wrap: wrap;
}
.bp-policy-toggle-row .field-label { margin: 0; white-space: nowrap; }
.bp-policy-toggle-row select {
  flex: 1;
  min-width: 220px;
  font-size: 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-control);
  padding: 6px 10px;
}
.bp-policy-toggle-row input[type="number"] {
  width: 120px;
  font-size: 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-control);
  padding: 6px 10px;
}
.bp-policy-toggle-row select:disabled,
.bp-policy-toggle-row input[type="number"]:disabled { background: var(--panel-strong); color: var(--muted-3); }

/* HTML archive evidence source: one row per locale archive, plus the shared
   toggles below it (which reuse .bp-policy-toggle-row above). */
.bp-policy-archive { margin: 14px 0 0; padding: 12px 0 0; border-top: 1px solid var(--line); }
.bp-policy-archive-rows { display: flex; flex-direction: column; gap: 6px; margin: 8px 0; }
.bp-policy-archive-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.bp-policy-archive-row input[type="text"],
.bp-policy-archive-row input[type="url"] {
  font-size: 12px;
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  padding: 5px 8px;
  background: var(--panel);
  color: var(--ink);
}
/* `width: auto` is load-bearing: the global input rule sets width:100%, which
   makes every field claim the full row and wrap the three controls onto three
   lines instead of one. */
.bp-policy-archive-row .bp-archive-locale { width: 84px; flex: 0 0 84px; text-transform: uppercase; }
.bp-policy-archive-row .bp-archive-url { width: auto; flex: 1 1 220px; min-width: 220px; }
/* Reuses the app-wide .bp-checkline pattern (checkbox + span), just pinned to
   auto width so it sits between the URL field and the remove button instead
   of stretching to fill the row. */
.bp-policy-archive-row .bp-archive-reference-check { flex: 0 0 auto; white-space: nowrap; }
.bp-policy-archive-row .bp-archive-remove { flex: 0 0 auto; font-size: 12px; padding: 5px 10px; }
.bp-policy-archive-row input:disabled { background: var(--panel-strong); color: var(--muted-3); }
.bp-policy-archive-row .bp-archive-reference-check:has(input:disabled) { color: var(--muted); cursor: not-allowed; }
.bp-policy-archive .bp-policy-toggle-row input[type="text"] {
  flex: 0 0 200px;
  width: 200px;
  font-size: 12px;
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  padding: 5px 8px;
  background: var(--panel);
  color: var(--ink);
}
.bp-policy-archive .bp-policy-toggle-row input[type="text"]:disabled { background: var(--panel-strong); color: var(--muted-3); }
/* Three class/attribute selectors, deliberately: the global
   `input:not([type=checkbox]):not([type=radio]):not(.sr-only)` rule near the
   top of this file sets `width: 100%` at specificity (0,3,1), which outranks
   `.bp-policy-toggle-row input[type="number"]`'s 120px at (0,2,1). Without
   matching that weight the two cap fields stretch to the full row and wrap
   onto their own lines. */
.bp-policy-archive .bp-policy-toggle-row input[type="number"] {
  flex: 0 0 130px;
  width: 130px;
  min-width: 130px;
}
.bp-stage-capability-hint { margin: -4px 0 4px; }

.bp-review-checklist {
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  background: var(--panel);
  padding: 10px 14px;
  margin: 10px 0;
}
.bp-review-checklist summary { cursor: pointer; margin: 0; padding: 2px 0; }
.bp-review-checklist ul {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.bp-review-checklist li {
  font-size: 12px;
  color: var(--ink);
  padding: 6px 10px;
  border-radius: 6px;
  background: var(--panel-strong);
}
.bp-review-checklist li b { color: var(--red); }
.bp-review-checklist li.bp-review-policy-line { background: var(--red-tint); }

/* Canvas on top, node inspector as a full-width panel beneath it. It used to
   be a 300px right rail, which was right when a stage's Tasks field held a
   short checklist. "Load default prompt" (Decision 98) puts the real prompt in
   that same field -- 22,218 characters over 64 lines for content_generation --
   and a 300px column reflows that into ~490 visual lines of ribbon. Full width
   is the only way the field is reviewable. */
.bp-stage {
  display: flex;
  flex-direction: column;
  gap: 14px;
  align-items: stretch;
}

.bp-canvas {
  position: relative;
  flex: 1;
  min-height: 220px;
  max-height: 60vh;
  height: auto;
  overflow-x: scroll;
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: 12px;
  background-color: var(--paper);
  background-image:
    linear-gradient(to right, rgba(28, 25, 23, 0.05) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(28, 25, 23, 0.05) 1px, transparent 1px);
  background-size: 24px 24px;
  scrollbar-color: var(--line-strong) transparent;
  scrollbar-width: thin;
}

.bp-canvas::-webkit-scrollbar { height: 10px; }
.bp-canvas::-webkit-scrollbar-track { background: transparent; }
.bp-canvas::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 6px; }

.bp-canvas-hint {
  font-size: 12px;
  margin: 0 0 6px;
}

.bp-canvas:focus-visible { outline: 2px solid var(--red); outline-offset: -2px; }

.bp-edges {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
  overflow: visible;
}

.bp-edge {
  fill: none;
  stroke: var(--muted);
  stroke-width: 2;
  opacity: 0.65;
}

.bp-edge.done { stroke: var(--teal); opacity: 1; }

.bp-nodes { position: relative; }

.bp-node {
  position: absolute;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  cursor: pointer;
  user-select: none;
  touch-action: none;
  box-sizing: border-box;
  transition: border-color 0.15s, outline-color 0.15s, box-shadow 0.15s;
}

.bp-node:hover { border-color: var(--steel); box-shadow: var(--shadow); }
.bp-node:active { cursor: grabbing; }
.bp-node.selected {
  border-color: var(--red);
  outline: 3px solid rgba(198, 40, 40, 0.12);
}

.bp-node-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--line);
  font-size: 14px;
  color: var(--ink);
}

.bp-node-head b { line-height: 1.4; }

.bp-node-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--line);
  flex: 0 0 auto;
}

.bp-node.parallel .bp-node-dot { background: var(--steel); }
.bp-node.done .bp-node-dot { background: var(--teal); }
.bp-node.active .bp-node-dot { background: var(--amber); }

.bp-node-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 12px;
}

.bp-node-meta { font-size: 12px; color: var(--muted); line-height: 1.5; }

.skill-chip {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  max-width: 100%;
  border: 1px solid rgba(68, 64, 60, 0.22);
  border-radius: 999px;
  padding: 2px 7px;
  background: rgba(68, 64, 60, 0.08);
  color: var(--steel);
  font-size: 11px;
  font-weight: 800;
  line-height: 1.5;
}

.bp-node.done { border-color: var(--teal); }
.bp-node.active {
  border-color: var(--amber);
  outline: 3px solid rgba(217, 119, 6, 0.14);
}

/* run states */
.bp-node.active .bp-node-head { color: var(--amber-text); }

/* inspector */
.bp-inspector {
  flex: 0 0 auto;
  align-self: stretch;
  display: flex;
  flex-direction: column;
  gap: 10px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
  padding: 16px;
  overflow-y: auto;
  max-height: 60vh;
}

/* Short settings keep a readable measure on the left; the prompt field takes
   the rest of the width rather than stretching every select to 1200px. */
.bp-inspector-body {
  display: grid;
  grid-template-columns: minmax(240px, 300px) minmax(0, 1fr);
  gap: 16px 24px;
  align-items: start;
}

/* Params and prompt share one grid child on purpose. As separate children they
   auto-placed as settings/params on row 1 and pushed the prompt back under the
   settings column, and pinning them to column 2 only traded that for a tall gap
   -- row 1's height comes from the settings column, so the prompt could not
   start until the agent list ended. Wrapped, the right side is one continuous
   stack whose height is its own, and a hidden params block collapses out of it. */
.bp-inspector-main {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.bp-inspector-settings,
.bp-inspector-prompt {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}

.bp-inspector-prompt textarea {
  width: 100%;
  resize: vertical;
}

.bp-inspector-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.bp-inspector-head h4 { margin: 0; color: var(--ink); }

.bp-skill-preview {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 10px;
  background: #fafaf9;
}

.bp-skill-preview b,
.bp-skill-preview small {
  display: block;
}

.bp-skill-preview b {
  font-size: 13px;
  color: var(--ink);
}

.bp-skill-preview small {
  margin-top: 2px;
  color: var(--muted);
  line-height: 1.5;
}

.icon-btn {
  min-height: 28px;
  width: 28px;
  padding: 0;
  font-size: 20px;
  line-height: 1;
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 6px;
}
.icon-btn:hover { background: #fff7f0; color: var(--red-deep); }

.field-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  margin: 4px 0 0;
}

.bp-inspector textarea { min-height: 120px; }

.bp-checkline {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--ink);
  line-height: 1.5;
  /* The checkbox itself is 16px, but the whole label is the click target --
     below 24px it misses the WCAG 2.2 AA (2.5.8) minimum target size. */
  min-height: 24px;
}
.bp-checkline input { width: auto; min-height: auto; accent-color: var(--red); }
/* `parallel` is persisted and drawn on the node, but processFileRun's stage
   loop is strictly sequential, so the control is shown read-only rather than
   offering a switch that changes nothing. */
.bp-checkline-disabled { color: var(--muted); cursor: not-allowed; }
.bp-parallel-note { margin: -4px 0 4px; }

.bp-run-settings-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px 14px;
  margin: 8px 0;
}
.bp-export-formats { display: flex; flex-wrap: wrap; gap: 8px 18px; margin: 4px 0 6px; }

.run-research-source-toggle {
  align-items: flex-start;
  margin-top: 12px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
}
.run-research-source-toggle input { margin-top: 3px; }
.run-research-source-toggle span { display: grid; gap: 2px; }
.run-research-source-toggle small { color: var(--muted); font-size: 12px; font-weight: 400; }
/* MR-4: the technical detail under a Step 2 switch, shown to an admin or an organization Manager only. */
.mr4-note { padding-left: 8px; border-left: 2px solid var(--line); line-height: 1.5; }

/* Decision 184: a project/run output language wins over this org-level
   toggle, so the checkbox needs a note saying so rather than looking like
   the only lever -- same nested span/small layout as
   .run-research-source-toggle just above. */
.research-localize-toggle { align-items: flex-start; }
.research-localize-toggle span { display: grid; gap: 2px; }
.research-localize-toggle small { color: var(--muted); font-size: 12px; font-weight: 400; line-height: 1.5; }

.bp-agent-picker {
  display: flex;
  flex-direction: column;
  gap: 6px;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 8px 10px;
  background: var(--panel);
}

.bp-agent-option {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--ink);
  line-height: 1.5;
  min-height: 24px;
}
.bp-agent-option input { width: auto; min-height: auto; accent-color: var(--red); }

/* The inspector is a stretch-aligned flex column, so these two used to stack
   with the destructive action spanning the full panel width directly under the
   additive one. Row layout with the delete pushed to the far edge keeps the
   irreversible action deliberate rather than the biggest target on screen. */
.bp-inspector-actions {
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
}
/* .danger-ghost is width:100% globally (it is a full-width action elsewhere),
   which as a flex item resolves flex-basis to the whole row. Overridden only
   inside this bar so the shared class is untouched. */
.bp-inspector-actions button { flex: 0 0 auto; }
.bp-inspector-actions .danger-ghost { width: auto; }
.bp-prompt-actions { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 2px; }
.bp-prompt-actions button { padding: 4px 10px; font-size: 0.82rem; }

.danger-ghost {
  background: transparent;
  color: var(--red);
  border: 1px solid var(--line);
  width: 100%;
}
.danger-ghost:hover { background: #fff1f1; color: var(--red-deep); }

.bp-empty {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  color: var(--muted);
}

/* command modal */
.bp-modal {
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 0;
  background: var(--panel);
  color: var(--ink);
  box-shadow: 0 18px 50px rgba(28, 25, 23, 0.12);
  max-width: 560px;
  width: calc(100% - 48px);
}
.bp-modal::backdrop { background: rgba(28, 25, 23, 0.4); }
.bp-modal-body { padding: 20px; display: flex; flex-direction: column; gap: 14px; }
.bp-modal-body textarea { min-height: 150px; }
.bp-modal-actions { justify-content: flex-end; }
/* App confirm / text dialog (app-dialog.js): the message keeps its own line breaks (the full-run question lists files) and long file names wrap. */
.app-dialog .app-dialog-message { margin: 0; white-space: pre-line; overflow-wrap: anywhere; line-height: 1.6; }
.app-dialog .app-dialog-field { display: flex; flex-direction: column; gap: 6px; }
.app-dialog .bp-modal-body textarea { min-height: 84px; resize: vertical; }
/* Confirm button: neutral questions use the ink surface; a destructive one (data-tone="danger", set by askConfirm) is the solid MISUMI red, white text 5.6:1, with its own action label. Both keep a visible focus ring. */
.app-dialog #appDialogConfirm { background: var(--ink); color: #fff; }
.app-dialog #appDialogConfirm:hover { background: #44403c; }
.app-dialog[data-tone="danger"] #appDialogConfirm { background: var(--red); }
.app-dialog[data-tone="danger"] #appDialogConfirm:hover { background: var(--red-deep); }
.app-dialog #appDialogConfirm:focus-visible,
.app-dialog #appDialogCancel:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.app-dialog #appDialogConfirm,
.app-dialog #appDialogCancel { line-height: 1.5; white-space: normal; }
.dup-preview-list { margin: 4px 0 0; padding-left: 18px; line-height: 1.6; }
.dup-preview-list code { overflow-wrap: anywhere; }

/* Project > Runs > "Resume all (N)" and its confirm dialog. */
.project-resume-all { display: flex; justify-content: flex-end; margin: 0 0 10px; }
.resume-all-list { margin: 6px 0 0; padding-left: 18px; line-height: 1.6; }
.resume-all-list li { overflow-wrap: anywhere; }
.resume-all-skipped { margin-top: 12px; }
.resume-all-heading { margin: 0; font-weight: 600; }
.resume-all-differs { margin: 0 0 8px; color: var(--amber-text); }

@media (max-width: 900px) {
  .bp-inspector { flex-basis: auto; max-height: none; }
  .bp-inspector-body { grid-template-columns: minmax(0, 1fr); }
}

/* the banner and the chat stream share the panel's middle grid row; the
   wrapper keeps the stretch on the stream so a visible banner stays
   content-height instead of claiming the row */
/* run-from-project flow */
.run-context-banner {
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--teal);
  border-radius: 8px;
  background: rgba(15, 118, 110, 0.07);
  color: var(--ink);
  font-size: 14px;
  line-height: 1.5;
}

.pipeline-card-actions {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-left: auto;
  min-width: 0;
  max-width: 100%;
}

.pipeline-card-actions .kebab-trigger,
.pipeline-card-actions .kebab-item-btn { padding: 0; }

.pipeline-card-actions .kebab-trigger { width: 34px; }

.pipeline-card-actions .kebab-item-btn { padding: 0 10px; text-align: left; }

.pipeline-card-actions button { min-height: 34px; padding: 0 14px; }

.pipeline-next {
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: rgba(217, 213, 201, 0.18);
}

.pipeline-name-input {
  min-width: 220px;
  flex: 1;
}

.pipeline-description-input {
  min-width: 260px;
  flex: 1.4;
}

.pipeline-blueprint-select {
  width: 190px;
}

.pipeline-run-mode-select {
  width: 150px;
}

.task-run-rows-select {
  width: 100px;
  min-height: 34px;
  font-size: 12px;
}

/* Wider than the rows select: these carry names, not numbers. The plan select
   only appears when one blueprint has several plans in the project. */
.task-run-blueprint-select {
  width: 220px;
  min-height: 34px;
  font-size: 12px;
}

.task-run-plan-select {
  width: 160px;
  min-height: 34px;
  font-size: 12px;
}

/* Decision 184 follow-up: the "run a file already in this project" path
   (#manualExistingBox) needs its own visible output-language control --
   #outputLanguageSelect lives inside the Column Roles box, which only
   renders for a fresh upload, so it is invisible on this path. Same sizing
   family as the blueprint/rows selects beside it. */
.task-run-output-language-select {
  width: 190px;
  min-height: 34px;
  font-size: 12px;
}

/* per-provider API key settings */
.keys-eyebrow { margin-top: 16px; }
.keys-grid { display: flex; flex-direction: column; gap: 12px; }

.key-row {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 10px 12px;
  background: var(--panel);
}
.key-row-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 6px;
}
.key-row-head b { font-size: 14px; }
.key-status { font-size: 12px; }
.key-row-input { display: flex; gap: 8px; align-items: center; }
.key-row-input input { flex: 1; }
.key-row-input button { min-height: 38px; padding: 0 12px; flex: 0 0 auto; }

/* Organization key row optional label — always saved together with a new
   key (see server.js: an empty apiKey clears the whole key, label included),
   so it sits directly under the key input rather than reading as independent. */
.key-row-label { margin-top: 8px; }
.key-row-label input { width: 100%; }
.key-row-label small { display: block; margin-top: 4px; }
.key-row-label-readonly { margin: 6px 0 0; font-size: 12px; }

/* Daily usage limit rows (t48) -- same key-row shell, red-tint treatment
   once a provider is at/over its limit for the day. */
.key-row.provider-limit-exceeded {
  border-color: var(--red);
  background: var(--red-tint);
}
.provider-limit-warning {
  margin: 8px 0 0;
  font-size: 12px;
}
#orgProviderLimitsContainer .key-row-input input[type="number"] {
  width: 140px;
  flex: 0 0 auto;
}

/* Codex Local sign-in (Settings > System AI Configuration, admin-only) */
#codexAuthSection .settings-label { margin-top: 10px; }
.codex-auth-login-panel {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}
.codex-auth-code-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 6px 0;
}
.codex-auth-code {
  font-family: var(--font-mono);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.08em;
  padding: 6px 12px;
  background: var(--stone-tint);
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  user-select: all;
}

/* row review */
.review-panel { margin-top: 18px; }
.html-preview-panel {
  margin: 14px 0;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--paper);
}
.html-preview-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
}
.html-preview-head h4 { margin: 2px 0 4px; font-size: 15px; }
.html-preview-head .muted { margin: 0; }
.html-preview-summary {
  display: grid;
  gap: 3px;
  margin: 12px 0;
  padding: 10px 12px;
  border-left: 3px solid var(--amber);
  background: var(--amber-tint);
  color: var(--muted);
}
.html-preview-summary:empty { display: none; }
.html-preview-summary b { color: var(--ink); }
.html-preview-outputs {
  margin: 12px 0;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
}
.html-preview-outputs .html-preview-label { margin-bottom: 10px; }
.preview-output-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.preview-output-fields > div { min-width: 0; padding: 9px 10px; border: 1px solid var(--line); border-radius: 6px; background: var(--paper); }
.preview-output-fields b, .preview-output-fields span { display: block; }
.preview-output-fields b { margin-bottom: 4px; color: var(--muted); font-size: 11px; font-weight: 600; }
.preview-output-fields span { overflow-wrap: anywhere; font-size: 13px; line-height: 1.55; }
.html-preview-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(280px, .8fr);
  gap: 12px;
}
.html-preview-frame-wrap,
.html-preview-qa {
  min-width: 0;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
}
.html-preview-label {
  margin: 0 0 8px;
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
}
#htmlPreviewFrame {
  display: block;
  width: 100%;
  min-height: 560px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: #fff;
}
.preview-score-line { display: flex; align-items: center; flex-wrap: wrap; gap: 7px; }
.preview-score { font-size: 18px; font-weight: 700; }
.preview-score.pass { color: var(--teal); }
.preview-score.review { color: var(--amber-text); }
.preview-score.fail { color: var(--red); }
.preview-score-arrow,
.preview-score-note,
.preview-score-delta { color: var(--muted); }
.preview-score-delta.down { color: var(--red); }
.preview-score-delta.up { color: var(--teal); }
.preview-score-note { margin: 8px 0; font-size: 12px; line-height: 1.55; }
.preview-qa-counts { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 12px; }
.preview-qa-section { margin-top: 12px; }
.preview-qa-section b { display: block; margin-bottom: 4px; font-size: 12px; }
.preview-qa-section ol,
.preview-qa-section ul,
.preview-qa-issues ul { margin: 0; padding-left: 18px; }
.preview-qa-section li,
.preview-qa-issues li { margin: 7px 0; }
.preview-qa-section span,
.preview-qa-section small { display: block; color: var(--muted); }
.preview-qa-section strong { color: var(--ink); }
.preview-qa-issues { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line); }
.preview-qa-issues summary { color: var(--ink); cursor: pointer; font-size: 12px; font-weight: 600; }
.html-preview-source { margin-top: 12px; }
.html-preview-source summary { cursor: pointer; color: var(--muted); font-size: 12px; font-weight: 600; }
#htmlPreviewSource { width: 100%; min-height: 220px; margin-top: 8px; resize: vertical; font: 12px/1.55 var(--font-sans); }
.row-review-table-wrap {
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
}
.row-review-table {
  width: 100%;
  border-collapse: collapse;
  min-width: 900px;
  font-size: 13px;
}
.row-review-table th,
.row-review-table td {
  border-bottom: 1px solid var(--line);
  padding: 10px 12px;
  text-align: left;
  vertical-align: top;
}
.row-review-table th {
  color: var(--muted);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0;
  background: rgba(217, 213, 201, 0.24);
}
.row-review-table td b,
.row-review-table td span {
  display: block;
}
.row-review-table tr.review {
  background: rgba(217, 119, 6, 0.07);
}
.row-review-table tr.fail {
  background: rgba(198, 40, 40, 0.06);
}
.row-review-empty td {
  padding: 18px 16px;
  color: var(--muted);
}
.row-review-empty b {
  display: block;
  color: var(--ink);
  font-size: 14px;
}
.row-review-empty span {
  display: block;
  margin-top: 4px;
  color: var(--muted);
}
.review-guidance {
  margin: 12px 0;
  padding: 12px;
  border: 1px solid var(--line);
  border-left: 4px solid var(--amber);
  border-radius: 8px;
  background: rgba(217, 119, 6, 0.06);
}
.review-guidance > div:first-child b,
.review-guidance li b,
.review-guidance-actions b,
.review-action-list b {
  color: var(--ink);
}
.review-guidance > div:first-child span,
.review-guidance li span {
  display: block;
  color: var(--muted);
}
.review-guidance ul,
.review-guidance ol {
  margin: 10px 0 0;
  padding-left: 20px;
}
.review-guidance li {
  margin: 6px 0;
}
.review-guidance-grid,
.review-guidance-actions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 8px;
  margin-top: 10px;
}
.review-guidance-grid p,
.review-guidance-actions p {
  margin: 0;
  padding: 8px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
  color: var(--muted);
}
.review-guidance-grid b,
.review-guidance-actions b {
  display: block;
  margin-bottom: 2px;
}
.review-guidance-more {
  margin-top: 10px;
}
.review-guidance-more ol {
  margin-bottom: 0;
}
.review-mini {
  border-left: 3px solid var(--amber);
  padding-left: 8px;
}
.qa-chip {
  display: inline-block;
  border-radius: 999px;
  padding: 3px 8px;
  font-size: 11px;
  font-weight: 800;
}
.qa-chip.pass { color: #075e57; background: rgba(15, 118, 110, 0.12); }
.qa-chip.review { color: #8a5708; background: rgba(217, 119, 6, 0.14); }
.qa-chip.fail { color: var(--red); background: rgba(198, 40, 40, 0.12); }
.decision-chip {
  display: inline-block;
  border-radius: 999px;
  padding: 3px 8px;
  font-size: 11px;
  font-weight: 800;
  background: rgba(100, 113, 109, 0.12);
  color: var(--muted);
}
.decision-chip.approved { color: #075e57; background: rgba(15, 118, 110, 0.12); }
.decision-chip.rejected { color: var(--red); background: rgba(198, 40, 40, 0.12); }
/* Decision 171 (#05 Missing Information Queue): input_completeness is a
   pre-generation gap check, not a QA score, so it gets its own amber-family
   chip/block rather than reusing .qa-chip -- same semantic color (amber =
   pending/warn) but a distinct shape and label so it never reads as "content
   failed QA". Renders only when a row has findings; complete/never-run rows
   render nothing. */
.completeness-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: 5px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  line-height: 1.5;
  color: #8a5708;
  background: rgba(217, 119, 6, 0.14);
}
.completeness-chip svg {
  width: 12px;
  height: 12px;
  flex: none;
}
.completeness-block {
  margin-bottom: 10px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--amber);
  border-radius: 8px;
  background: var(--amber-tint);
}
.completeness-block b {
  display: block;
  color: var(--ink);
  margin-bottom: 2px;
}
.completeness-block > span {
  display: block;
  margin-bottom: 6px;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.55;
}
.completeness-block ul {
  margin: 0;
  padding-left: 18px;
}
.completeness-block li {
  margin: 4px 0;
}
.completeness-block li strong {
  display: block;
  color: var(--ink);
  font-size: 12px;
}
.completeness-block li span {
  display: block;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
}
.bp-governance,
.runtime-skill-manager {
  margin-top: 14px;
  border-top: 1px solid var(--line);
  padding-top: 14px;
}
.bp-decision-list {
  display: grid;
  gap: 8px;
  margin: 10px 0;
}
.bp-decision-record {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 8px;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
}
.bp-decision-record p,
.bp-decision-record small { margin: 3px 0 0; color: var(--muted); }
.bp-decision-form {
  display: grid;
  grid-template-columns: minmax(150px, 1fr) minmax(220px, 2fr) auto auto;
  gap: 8px;
  align-items: start;
}
.bp-decision-form textarea { min-height: 38px; }
@media (max-width: 760px) {
  .bp-decision-form { grid-template-columns: 1fr; }
}

/* Cross-organization blueprint request/approve flow (owner ruling
   2026-08-29) -- see loadBlueprintAccessRequests()/renderBlueprint*Requests()
   in app.js. Block layout rather than .blueprint-card's fixed two-column
   grid: a request card needs a full-width reject-reason row underneath its
   header, which a content|auto grid can't fit cleanly. */
.bp-request-list {
  display: grid;
  gap: 10px;
  margin: 8px 0 16px;
}
.bp-request-card {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 12px 14px;
  background: var(--panel);
}
.bp-request-card h4 {
  margin: 0 0 4px;
  overflow-wrap: anywhere;
}
.bp-request-card p {
  margin: 4px 0 0;
  color: var(--muted);
  overflow-wrap: anywhere;
}
.bp-request-card .button-row {
  margin-top: 10px;
}
.bp-request-status {
  font-weight: 600;
}
.bp-request-status.status-pending { color: var(--amber-text); }
.bp-request-status.status-rejected { color: var(--red-deep); }
.bp-request-status.status-approved { color: var(--teal); }
.bp-request-reject-row {
  display: grid;
  gap: 6px;
  margin-top: 10px;
}
.bp-request-reject-row textarea { min-height: 38px; }

/* Blueprint revision history -- read-only timeline, see
   loadBlueprintRevisionHistory/renderBlueprintRevisionDetail in app.js. */
.bp-revision-list {
  display: grid;
  gap: 8px;
  margin: 10px 0;
}
.bp-revision-row {
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
  overflow: hidden;
}
.bp-revision-row-toggle {
  display: grid;
  grid-template-columns: auto minmax(140px, auto) minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px 12px;
  border: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.bp-revision-row-toggle:hover { background: var(--panel-strong); }
.bp-revision-version {
  flex: 0 0 auto;
  padding: 2px 8px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  color: var(--muted);
  font-size: 11.5px;
  font-weight: 650;
}
.bp-revision-meta {
  display: grid;
  gap: 1px;
  min-width: 0;
}
.bp-revision-meta b {
  overflow: hidden;
  color: var(--ink);
  font-size: 13px;
  font-weight: 650;
  line-height: 1.5;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.bp-revision-meta small {
  color: var(--muted-2);
  font-size: 11px;
  line-height: 1.5;
}
.bp-revision-summary {
  overflow: hidden;
  color: var(--muted);
  font-size: 12.5px;
  line-height: 1.5;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.bp-revision-chevron {
  flex: 0 0 auto;
  color: var(--muted-2);
  transition: transform 0.15s ease;
}
.bp-revision-row-toggle[aria-expanded="true"] .bp-revision-chevron { transform: rotate(180deg); }
.bp-revision-detail {
  padding: 0 12px 12px;
  border-top: 1px solid var(--line);
}
.bp-revision-reason {
  display: grid;
  gap: 8px;
  justify-items: start;
  padding: 10px 12px;
  margin-top: 10px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--muted-2);
  border-radius: 8px;
  background: var(--panel-strong);
}
.bp-revision-reason b {
  color: var(--ink);
  font-size: 13px;
  font-weight: 650;
  line-height: 1.5;
}
.bp-revision-diff { margin-top: 10px; }
.bp-revision-diff-section + .bp-revision-diff-section,
.bp-revision-diff .copilot-policy-diff-section + .copilot-policy-diff-section {
  margin-top: 10px;
}
.bp-revision-stage-diff {
  display: grid;
  gap: 4px;
  padding: 8px 0;
  border-top: 1px dashed var(--line);
}
.bp-revision-stage-diff > b {
  color: var(--ink);
  font-size: 12.5px;
  font-weight: 650;
  line-height: 1.5;
}
.bp-revision-prose-row { display: grid; gap: 6px; }
.bp-revision-line-diff {
  display: grid;
  gap: 0;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 6px;
}
.bp-revision-line-diff-row {
  display: grid;
  grid-template-columns: 18px minmax(0, 1fr);
  gap: 8px;
  padding: 2px 8px;
  color: var(--ink);
  font-size: 12.5px;
  line-height: 1.6;
}
.bp-revision-line-diff-row.add { background: var(--teal-tint); }
.bp-revision-line-diff-row.remove { background: var(--red-tint); color: var(--muted); text-decoration: line-through; text-decoration-color: var(--line-strong); }
.bp-revision-line-diff-row.same { background: var(--panel); color: var(--muted); }
.bp-revision-line-diff-marker {
  color: var(--muted-2);
  font-weight: 700;
  text-decoration: none;
}
.bp-revision-line-diff-text { overflow-wrap: anywhere; }
.bp-revision-line-diff-block {
  margin: 0;
  padding: 8px 10px;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
  border-radius: 6px;
  font: inherit;
  line-height: 1.6;
}
.bp-revision-line-diff-block.add { background: var(--teal-tint); }
.bp-revision-line-diff-block.remove { background: var(--red-tint); color: var(--muted); }
@media (max-width: 760px) {
  .bp-revision-row-toggle {
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas:
      "version chevron"
      "meta meta"
      "summary summary";
  }
  .bp-revision-version { grid-area: version; }
  .bp-revision-chevron { grid-area: chevron; justify-self: end; }
  .bp-revision-meta { grid-area: meta; }
  .bp-revision-summary { grid-area: summary; white-space: normal; }
}

.row-review-table small {
  display: block;
  margin-top: 4px;
  color: var(--muted);
}
.review-action-list p {
  margin: 0 0 8px;
}
.review-action-list span {
  color: var(--ink);
}
.review-action-list small {
  color: var(--muted);
}
.review-raw-note {
  padding-top: 4px;
  border-top: 1px solid var(--line);
}
.review-actions {
  min-width: 190px;
}
.review-actions .tiny {
  min-height: 28px;
  padding: 0 8px;
  margin: 0 4px 4px 0;
  font-size: 12px;
}
@media (max-width: 900px) {
  .html-preview-layout { grid-template-columns: 1fr; }
  #htmlPreviewFrame { min-height: 430px; }
}
@media (max-width: 620px) {
  .html-preview-head { display: grid; }
}

.team-editor,
.organization-list {
  display: grid;
  gap: 10px;
}

.organization-list {
  gap: 14px;
}

/* The users table gained a third action (Disable) and sits in the narrow
   secondary column, so its cells were wrapping into stacked buttons and a role
   select with no width. The table already scrolls inside .table-wrap — give it
   room to and let the scroll do its job rather than folding. */
#usersTable td:last-child {
  white-space: nowrap;
}

#usersTable td:last-child button + button {
  margin-left: 6px;
}

#usersTable select[data-user-role] {
  min-width: 96px;
}

#users .table-wrap table {
  /* Five columns and three actions do not fit the narrow secondary column at
     any width; the table scrolls inside .table-wrap instead of folding its
     buttons into a stack. */
  min-width: 780px;
}

.org-panel-note {
  margin: 10px 0 0;
  max-width: 760px;
  font-size: 12px;
}

/* One org is one card, and its member rows live inside it. They used to be
   siblings in a flat list, which read as unrelated blocks the moment a second
   organization existed. */
.org-card {
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
  overflow: hidden;
}

.org-card-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px;
  align-items: baseline;
  padding: 12px;
  border-bottom: 1px solid var(--line);
  background: var(--paper);
}

.org-card-head b {
  display: block;
  overflow-wrap: anywhere;
}

.org-card-head span,
.org-card-head small {
  display: block;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
}

.org-card-members {
  gap: 0;
  padding: 0 12px;
}

.org-card-members .team-row:last-of-type {
  border-bottom: 0;
}

/* Email and pill stack instead of sharing one line: side by side in this narrow
   column the pill squeezed the address until it broke mid-word
   ("admin@misumi / .local"). */
.org-card-members .team-row > span:first-child {
  flex-direction: column;
  align-items: flex-start;
  gap: 5px;
}

.org-member-email {
  overflow-wrap: anywhere;
}

.tiny-pill {
  flex: 0 0 auto;
  padding: 2px 8px;
  font-size: 11px;
  line-height: 1.5;
  white-space: nowrap;
}

/* Email | role | remove. The base .team-row is two columns; the role select
   gives up its 170px cap so the third column has somewhere to come from in a
   ~460px panel. */
.org-card-members .team-row {
  grid-template-columns: minmax(0, 1fr) minmax(110px, 150px) auto;
}

.org-member-remove,
.org-member-locked {
  width: auto;
  min-height: 0;
  padding: 4px 10px;
  font-size: 12px;
  line-height: 1.5;
  white-space: nowrap;
}

/* One red-tint block per member row would make the roster the reddest thing on
   the page, against the three-focal-points rule. The control stays neutral
   until it is the one being reached for, and only then reads as destructive. */
button.ghost.org-member-remove {
  color: var(--muted);
  border-color: var(--line-strong);
}

button.ghost.org-member-remove:hover,
button.ghost.org-member-remove:focus-visible {
  color: var(--red-deep);
  background: var(--red-tint);
  border-color: transparent;
}

/* The cell a Remove button cannot occupy: the creator, or a manager an
   organization manager may not touch. It says which, rather than leaving a
   gap that reads as a rendering bug. */
.org-member-locked {
  align-self: center;
  color: var(--muted-2);
  font-weight: 500;
  cursor: help;
}

/* Not a .team-row: that grid caps its second column at 170px, which crushed the
   two selects and the button this row needs into unreadable stubs. This panel
   also sits in the narrow secondary column (~460px), so the controls stack
   instead of competing for one line — an email address needs the full width. */
.org-add-member {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 8px 10px;
  align-items: center;
  padding: 12px 0;
  border-top: 1px solid var(--line);
}

.org-add-member-label,
.org-add-member select[data-org-add-user] {
  grid-column: 1 / -1;
}

.org-add-member-label {
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
}

.org-add-member select {
  width: 100%;
  min-width: 0;
}

.org-add-member select[data-org-add-role] {
  max-width: 200px;
}

.org-add-member button {
  justify-self: end;
}

#projectTeamEditor,
#projectTeamStatus,
#projectTeamSection > .button-row {
  max-width: 760px;
}

#projectTeamSection .project-team-editor {
  width: min(100%, 760px);
}

.team-row {
  display: grid;
  grid-template-columns: minmax(220px, 1fr) minmax(130px, 170px);
  gap: 12px;
  align-items: center;
  padding: 10px 12px;
  border-bottom: 1px solid var(--line);
}

.team-row span {
  display: flex;
  gap: 8px;
  align-items: center;
  min-width: 0;
  overflow-wrap: anywhere;
}

.team-row select {
  width: 100%;
}

.team-row input[type="checkbox"],
.project-team-checkbox {
  width: 18px;
  height: 18px;
  min-width: 18px;
  min-height: 18px;
  flex: 0 0 18px;
  margin: 0;
  padding: 0;
  accent-color: var(--red);
}

.team-readonly {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.project-team-list {
  width: min(100%, 760px);
  max-width: 760px;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
}

.project-team-head,
.project-team-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(130px, 170px);
  gap: 12px;
  align-items: center;
}

.project-team-head {
  padding: 9px 12px;
  color: var(--muted);
  background: rgba(217, 213, 201, 0.24);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0;
}

.project-team-row {
  padding: 12px;
  border-top: 1px solid var(--line);
}

#projectTeamSection .project-team-head,
#projectTeamSection .project-team-row {
  grid-template-columns: minmax(0, 1fr) 148px;
}

.project-team-user {
  display: flex;
  min-width: 0;
  gap: 10px;
  align-items: center;
}

.project-team-user-text {
  display: grid;
  min-width: 0;
  gap: 2px;
}

.project-team-user-text b,
.project-team-user-text small {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.project-team-user-text b {
  color: var(--ink);
  font-size: 14px;
}

.project-team-user-text small,
.team-readonly-member small {
  color: var(--muted);
  font-size: 12px;
}

.project-team-row select {
  min-width: 0;
}

#projectTeamSection .project-team-row {
  width: 100%;
  min-height: 58px;
}

#projectTeamSection .project-team-user {
  width: auto;
  max-width: 100%;
}

#projectTeamSection .project-team-checkbox {
  appearance: auto;
  width: 18px !important;
  height: 18px !important;
  min-width: 18px !important;
  min-height: 18px !important;
  max-width: 18px;
  max-height: 18px;
}

#projectTeamSection .project-team-role-select {
  width: 100%;
  min-width: 0;
  max-width: 148px;
  justify-self: end;
}

.team-readonly-member {
  display: grid;
  gap: 2px;
  max-width: 100%;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 8px 10px;
  background: rgba(68, 64, 60, 0.04);
}

.team-readonly-member b {
  overflow-wrap: anywhere;
  color: var(--ink);
}

.compact-team {
  margin-bottom: 10px;
}

@media (max-width: 680px) {
  .project-team-head {
    display: none;
  }

  .team-row,
  .project-team-row {
    grid-template-columns: 1fr;
    gap: 10px;
  }

  /* Higher specificity than the rule above, so the three-column org row has to
     be stacked by name or it stays three columns at 375px. */
  .org-card-members .team-row {
    grid-template-columns: 1fr;
  }

  /* Stacked, the button is a row of its own rather than a trailing cell, and a
     28px target next to 40px selects is both small for a thumb and visibly
     out of step with the Add/Transfer buttons below it. */
  .org-member-remove,
  .org-member-locked {
    justify-self: start;
  }

  .org-member-remove {
    min-height: 40px;
    padding: 6px 14px;
  }

  #projectTeamSection .project-team-head,
  #projectTeamSection .project-team-row {
    grid-template-columns: 1fr;
  }

  #projectTeamSection .project-team-role-select {
    max-width: none;
    justify-self: stretch;
  }

  .project-team-user-text b,
  .project-team-user-text small {
    white-space: normal;
  }
}

/* ---------- neutral SaaS style guide pass ---------- */

html {
  background: var(--paper);
}

body {
  color: var(--ink);
  background: var(--paper);
  font-size: 13px;
  line-height: 1.58;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

button,
.download-btn {
  min-height: 42px;
  border-radius: 10px;
  padding: 0 18px;
  font-size: 13px;
  font-weight: 650;
  letter-spacing: 0;
  box-shadow: none;
}

button:focus-visible,
.download-btn:focus-visible,
a:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 3px;
}

button.secondary,
.download-btn.secondary-link {
  color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--line-strong);
}

button.secondary:hover,
.download-btn.secondary-link:hover {
  color: var(--ink);
  background: var(--panel-strong);
  border-color: var(--line-strong);
}

button.ghost,
.icon-btn {
  color: var(--muted);
  background: transparent;
  border-color: transparent;
}

button.ghost:hover,
.icon-btn:hover {
  color: var(--ink);
  background: var(--panel-strong);
}

button.ghost.danger,
.danger-ghost {
  color: var(--red-deep);
  background: var(--red-tint);
  border-color: transparent;
}

button.ghost.danger:hover,
.danger-ghost:hover {
  color: var(--red-deep);
  background: #fbdcdc;
}

/* A disabled danger action (e.g. bulk "Delete"/"Cancel" before anything is
   selected) must not keep reading as a live red focal point — it is not an
   available action yet. Higher specificity than `button.ghost.danger` alone
   so the quiet disabled look wins regardless of source order (doc 45 #18). */
button.ghost.danger:disabled,
.danger-ghost:disabled {
  color: var(--muted-3);
  background: var(--panel-strong);
  border-color: var(--line);
}

button:disabled,
.download-btn.disabled,
.download-btn[aria-disabled="true"] {
  color: var(--muted-3);
  background: var(--panel-strong);
  border-color: var(--line);
  opacity: 1;
}

input:not([type="checkbox"]):not([type="radio"]):not(.sr-only),
textarea,
select {
  min-height: 42px;
  border-color: var(--line-strong);
  border-radius: 10px;
  background: var(--panel);
  color: var(--ink);
  font-size: 13px;
  box-shadow: none;
}

input::placeholder,
textarea::placeholder {
  color: var(--muted-3);
}

input:focus,
textarea:focus,
select:focus,
.bp-name-input:focus {
  border-color: var(--red);
  box-shadow: 0 0 0 4px rgba(198, 40, 40, 0.12);
}

textarea {
  line-height: 1.58;
}

label,
.settings-label,
.field-label,
.login-card label {
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0;
}

.workbench {
  padding: 24px;
  gap: 18px;
}

.topbar,
.panel,
.login-card,
.project-card,
.pipeline-card,
.blueprint-card,
.run-card,
.project-file-tasks,
.project-run-history,
.project-bulk-upload,
.mapping-box,
.manual-mapping-review,
.copilot-file-card,
.copilot-action-card,
.bp-inspector,
.bp-modal,
.key-row,
.review-guidance-grid p,
.review-guidance-actions p,
.project-team-list,
.row-review-table-wrap {
  border-color: var(--line);
  border-radius: 12px;
  background: var(--panel);
  box-shadow: none;
}

.panel,
.topbar {
  box-shadow: none;
}

.panel {
  padding: 20px;
}

.panel-head {
  margin-bottom: 16px;
}

.topbar {
  padding: 14px 18px;
}

.topbar h2,
.login-card h2,
.panel h3 {
  color: var(--ink);
  font-size: 18px;
  font-weight: 650;
  line-height: 1.42;
}

.panel h3,
.agent-card h4,
.project-card-head h4,
.bp-inspector-head h4 {
  font-size: 14px;
  font-weight: 650;
}

/* .muted itself is declared once, early (see the base .muted rule) and must
   not be re-declared here: state classes added at runtime, like
   .field-status-error, share its specificity and win only by source order. */
.login-sub,
.flow-callout span,
.empty-state span,
.ops-card span,
.stage span,
.blueprint-card p,
.run-card p,
.copilot-file-card p,
.copilot-review-details summary,
.copilot-technical summary,
.project-next-step span,
.project-action-strip span,
.project-live-progress span,
.review-disclosure span,
.pipeline-next span,
.row-review-table small {
  color: var(--muted);
}

.eyebrow,
.keys-eyebrow,
.nav-group-label {
  color: var(--muted-2);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.side {
  width: 224px;
  color: var(--ink);
  background: var(--panel);
  border-right-color: var(--line);
}

.side-brand {
  color: var(--ink);
}

.side a {
  border-radius: 10px;
  color: var(--muted);
  font-weight: 500;
}

.side a:hover,
.side a.active {
  color: var(--ink);
  background: var(--panel-strong);
}

.side a.active {
  font-weight: 650;
}

.session-box {
  border-top-color: var(--line);
}

.mark {
  background: var(--red);
}

.pill,
.dataset-profile-pill,
.skill-chip,
.agent-card-kind {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 28px;
  border: 0;
  border-radius: 999px;
  padding: 4px 12px;
  color: var(--muted);
  background: var(--stone-tint);
  font-size: 12px;
  font-weight: 650;
  line-height: 1.4;
}

.status-pill,
.qa-chip,
.decision-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 24px;
  border-radius: 999px;
  padding: 2px 0;
  color: var(--muted);
  background: transparent;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

.status-pill::before,
.qa-chip::before,
.decision-chip::before {
  content: "";
  width: 7px;
  height: 7px;
  flex: 0 0 7px;
  border-radius: 999px;
  background: var(--muted-3);
}

.status-pill.completed,
.qa-chip.pass,
.decision-chip.approved {
  color: var(--teal);
  background: transparent;
}

.status-pill.completed::before,
.qa-chip.pass::before,
.decision-chip.approved::before {
  background: var(--teal);
}

.status-pill.processing,
.status-pill.paused,
.qa-chip.review {
  color: var(--amber-text);
  background: transparent;
}

.status-pill.processing::before,
.status-pill.paused::before,
.qa-chip.review::before {
  background: var(--amber);
}

.status-pill.failed,
.qa-chip.fail,
.decision-chip.rejected {
  color: var(--red-deep);
  background: transparent;
}

.status-pill.failed::before,
.qa-chip.fail::before,
.decision-chip.rejected::before {
  background: var(--red);
}

.status-pill.queued,
.status-pill.uploaded,
.status-pill.idle,
.status-pill.cancelled {
  color: var(--muted);
  background: transparent;
}

.status-pill.queued::before,
.status-pill.uploaded::before,
.status-pill.idle::before,
.status-pill.cancelled::before {
  background: var(--muted-3);
}

.table-wrap,
.row-review-table-wrap,
.project-team-list {
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
}

table,
.row-review-table {
  border-collapse: separate;
  border-spacing: 0;
}

th,
td,
.row-review-table th,
.row-review-table td {
  border-bottom: 1px solid var(--line);
  padding: 12px 16px;
}

th,
.row-review-table th,
.project-team-head {
  position: sticky;
  top: 0;
  z-index: 1;
  color: var(--muted);
  background: var(--panel);
  font-size: 12px;
  font-weight: 650;
  letter-spacing: 0;
  text-transform: none;
}

tr:last-child td,
.row-review-table tr:last-child td {
  border-bottom: 0;
}

.code-cell,
.live-progress-meta span:first-child,
.dist-row,
code,
pre {
  font-family: var(--font-mono);
}

code,
.copilot-action-card code {
  border-radius: 8px;
  color: var(--ink);
  background: var(--panel-strong);
}

pre {
  color: var(--ink);
  background: var(--panel-strong);
}

.progress-track,
.mini-track,
.dist-track {
  height: 7px;
  border: 0;
  background: var(--panel-strong);
}

.progress-fill.teal,
.mini-fill.teal,
.dist-fill.teal {
  background: var(--teal);
}

.progress-fill.amber,
.mini-fill.amber,
.dist-fill.amber {
  background: var(--amber);
}

.progress-fill.red,
.mini-fill.red,
.dist-fill.red {
  background: var(--red);
}

.flow-callout,
.empty-state,
.run-context-banner,
.project-next-step,
.project-action-strip,
.project-live-progress,
.review-guidance,
.pipeline-next,
.export-box,
.temp-pass,
.copilot-reply,
.copilot-result,
.dataset-profile-card,
.manual-mapping-warning,
.audit-entry.warn,
.audit-entry.error,
.audit-entry.failed {
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
}

.flow-callout,
.empty-state,
.run-context-banner,
.project-next-step,
.project-action-strip,
.project-live-progress,
.review-guidance,
.pipeline-next {
  border-left-width: 1px;
}

.project-next-step.teal,
.project-action-strip.teal,
.run-context-banner,
.export-box,
.temp-pass,
.copilot-reply,
.copilot-result.ok {
  border-color: rgba(15, 118, 110, 0.20);
  background: var(--teal-tint);
}

.project-next-step.red,
.project-action-strip.red,
.copilot-result.fail,
.audit-entry.error,
.audit-entry.failed {
  border-color: rgba(198, 40, 40, 0.18);
  background: var(--red-tint);
}

.manual-mapping-warning,
.audit-entry.warn,
.run-context-banner.warn,
.project-next-step:not(.teal):not(.red),
.project-action-strip:not(.teal):not(.red) {
  border-color: rgba(217, 119, 6, 0.20);
  background: var(--amber-tint);
}

/* Registered gap X1: a free-form node wrote a value no export column receives.
   Amber, not red -- the drop is the uploaded-header contract working as
   intended (Hard Rule #2); what the operator has to know is that the value is
   not in the file they are about to download. Same amber-tint token the other
   "worth reading before you act" boxes above use. */
.run-unclaimed-writes {
  margin-top: 8px;
  padding: 8px 10px;
  border: 1px solid rgba(217, 119, 6, 0.20);
  border-radius: 8px;
  background: var(--amber-tint);
  color: var(--ink);
  font-size: 13px;
  line-height: 1.55;
}

.run-context-banner b {
  display: block;
  color: var(--ink);
  font-size: 13px;
}

.run-context-banner p {
  margin: 4px 0 0;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.55;
}

/* #runContextBanner reads as one flowing sentence -- "Run plan X in project Y
   · blueprint Z" -- not the heading-plus-detail shape .run-context-banner b's
   block rule above is written for, so its <b> segments stay inline here. */
#runContextBanner b {
  display: inline;
  font-size: inherit;
}

#runContextBanner .inline-link {
  margin-left: 4px;
  white-space: nowrap;
}

.project-card,
.pipeline-card,
.blueprint-card,
.run-card,
.field-card,
.file-task-row,
.project-run-row,
.agent-card,
.ops-card,
.bp-node,
.bp-option,
.run-mode-option,
.copilot-column-item,
.copilot-review-summary span,
.copilot-review-details,
.copilot-recommendations,
.copilot-column-plan,
.team-readonly-member {
  border-color: var(--line);
  border-radius: 12px;
  background: var(--panel);
}

.project-card:hover,
.pipeline-card:hover,
.bp-node:hover {
  border-color: var(--line-strong);
  background: var(--panel);
}

.project-bulk-bar {
  border-left-width: 1px;
  border-color: var(--line);
  background: var(--panel);
}

.project-select-control,
.mini-track,
.manual-mapping-group,
.review-why,
.qa95-playbook,
.bp-skill-preview,
.team-readonly-member {
  background: var(--panel);
}

.chat-drop-zone,
.bp-canvas {
  background-color: var(--paper);
}

.bp-canvas {
  background-image:
    linear-gradient(to right, rgba(28, 25, 23, 0.035) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(28, 25, 23, 0.035) 1px, transparent 1px);
}

.bp-node.parallel .bp-node-dot,
.audit-level {
  background: var(--muted);
}

.bp-node:hover {
  border-color: var(--line-strong);
}

.bp-node.selected,
.bp-option.selected,
.run-mode-option.active {
  border-color: var(--red);
  outline: 0;
  box-shadow: 0 0 0 4px rgba(198, 40, 40, 0.10);
}

.bp-option.selected {
  background: var(--panel);
}

.run-mode-option.active b {
  color: var(--ink);
}

.stepper {
  border-radius: 12px;
  background: var(--panel);
}

.step-dot {
  background: var(--panel);
}

.stepper li.active .step-dot {
  border-color: var(--red);
  background: var(--red);
}

.run-step,
.run-step.done,
.run-step.active,
.run-step.paused {
  border-color: var(--line);
  background: var(--panel);
}

/* A step not yet reached is neutral, not teal — teal is reserved for
   pass/complete (doc 45 #10 / HN confirms: the base rule used to leave the
   original hardcoded #075e57 teal-ish color in place for every step,
   including ones that had not run yet). */
.run-step {
  color: var(--muted);
}

.run-step.done {
  color: var(--teal);
}

.run-step.active,
.run-step.paused {
  color: var(--amber-text);
}

@media (max-width: 1040px) {
  .side {
    width: auto;
  }
}

/* Neutral SaaS final alignment: keep the style-guide surface clean across pages. */
.login-card,
.panel,
.card,
.project-card,
.run-card,
.pipeline-card,
.agent-card,
.bp-node,
.bp-option,
.run-mode-option,
.project-bulk-bar,
.manual-mapping-group,
.review-guidance-grid p,
.team-readonly-member {
  border-radius: var(--radius-card);
}

input,
select,
textarea,
button,
.button,
.project-select-control,
.criteria-grid input,
.run-config-grid select {
  border-radius: var(--radius-control);
}

@media (max-width: 680px) {
  body {
    font-size: 13px;
  }

  .workbench,
  .side {
    padding: 16px;
  }

  .panel {
    padding: 16px;
  }

  th,
  td,
  .row-review-table th,
  .row-review-table td {
    padding: 10px 12px;
  }
}

/* Final app-header sizing: header rows must follow their content, not viewport height. */
.workbench {
  align-content: start;
  grid-auto-rows: max-content;
}

.topbar {
  align-self: start;
  min-height: 0;
  height: auto;
  padding: 10px 16px;
}

.topbar > div {
  min-height: 0;
}

/* Copilot chat layout/color alignment. */
#view-copilot #copilotProjectSelect,
#view-copilot #copilotPrompt {
  border-color: var(--line-strong);
  background: var(--panel);
}

#view-copilot .copilot-reply {
  border-color: var(--line);
  background: var(--panel-strong);
}

/* Dataset view builder — same card shell as the file/run sections, with a
   compact form grid that stays readable in Thai (labels wrap, never clip). */
.project-view-builder > summary {
  cursor: pointer;
}

.view-builder-body {
  display: grid;
  gap: 12px;
  padding-top: 12px;
}

.view-builder-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 12px;
}

.view-builder-row label,
.view-builder-column {
  display: grid;
  gap: 6px;
  font-size: 13px;
  line-height: 1.6;
}

.view-builder-columns {
  display: grid;
  gap: 8px;
}

/* One block per attached document set. A view can hold several (four locale
   folders becoming four columns), so each set reads as its own unit. */
.view-builder-attachments {
  display: grid;
  gap: 10px;
}

.view-builder-attachment {
  display: grid;
  gap: 10px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel-strong);
}

.view-builder-column {
  grid-template-columns: minmax(150px, 2fr) minmax(120px, 1fr) minmax(110px, 1.4fr) auto;
  align-items: center;
  gap: 8px;
}

.view-builder-report {
  display: grid;
  gap: 4px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel-strong);
}

.view-builder-report span,
.view-builder-report small,
.view-builder-hint {
  color: var(--muted);
  font-size: 12px;
  line-height: 1.7;
}

@media (max-width: 720px) {
  .view-builder-column {
    grid-template-columns: 1fr;
  }

  .view-builder-column [hidden] {
    display: none;
  }
}

/* Duplicate-column notice in the view builder — advisory, never blocking. */
.view-builder-warnings {
  display: grid;
  gap: 4px;
  padding: 10px 12px;
  border: 1px solid var(--warn-border, #e0c88a);
  border-radius: 8px;
  background: var(--warn-bg, #fdf8ec);
  color: var(--warn-text, #6b4e0e);
  font-size: 12px;
  line-height: 1.7;
}

/* Main-file picker in the project's file list: one file is the spreadsheet the
   project is about, the rest are still listed and still runnable. The width is
   capped because a select is as wide as its longest option, and the head row
   gives this column all the space it asks for -- an uncapped one squeezed the
   heading to a single character per line. */
.project-main-file {
  display: grid;
  gap: 4px;
  min-width: 0;
  font-size: 12px;
  color: var(--muted);
}

.project-main-file select {
  width: 100%;
  max-width: 240px;
}

/* A head row whose actions column carries a picker as well as buttons: without
   a floor on the heading, the auto-sized actions column takes the whole row and
   the heading wraps one character per line. */
.project-review-head-wide {
  grid-template-columns: minmax(220px, 1fr) auto;
}

/* The "main file" marker sits inside the file name, so it must not take a line
   of its own the way a standalone pill does. */
.file-task-head b .pill {
  display: inline-block;
  width: auto;
  margin-left: 6px;
  vertical-align: middle;
}

/* Manual Run's "run something already here" path, under the upload row. */
.manual-existing-box {
  display: grid;
  gap: 10px;
  margin-top: 12px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel-strong);
}

/* A run plan still on a superseded built-in: informational, never a warning —
   nothing is broken and nothing changes on its own. */
.pipeline-outdated {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0 0 8px;
}

/* Execution state only: a completed frame does not imply QA approval. */
.file-task-row:has(> .file-task-head > .status-pill.completed) {
  border-color: var(--teal);
  box-shadow: none;
}

.file-task-row:has(> .file-task-head > .status-pill.processing),
.file-task-row:has(> .file-task-head > .status-pill.paused) {
  border-color: var(--amber);
  box-shadow: none;
}

.file-task-row:has(> .file-task-head > .status-pill.failed) {
  border-color: var(--red);
  box-shadow: none;
}

.file-task-head > .status-pill.completed::before {
  content: "✓";
  width: 14px;
  height: auto;
  background: none;
  border-radius: 0;
  font-weight: 700;
}

/* Utility links styled as buttons must not inherit the plain-link padding
   and block display above. Keep all file export controls at toolbar scale. */
.run-export-links {
  align-items: center;
}

.run-export-links a.download-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  align-self: center;
  min-height: 34px;
  padding: 4px 12px;
  line-height: 1.5;
}

/* Keep file identities readable without expanding the page on small screens. */
.file-task-head b,
.project-run-row-main b,
.pipeline-next span {
  overflow-wrap: anywhere;
}

.project-next-step > .review-disclosure {
  grid-column: 1 / -1;
  min-width: 0;
}

.project-review-head-wide {
  grid-template-columns: minmax(0, 1fr);
}

.project-review-head-wide > .project-next-actions {
  justify-content: flex-start;
}

@media (max-width: 1100px) {
  .project-review-head.project-review-head-wide,
  .project-next-step {
    grid-template-columns: minmax(0, 1fr);
  }

  .project-next-step > .project-next-actions {
    justify-content: flex-start;
  }
}

/* App-shell hierarchy — make the operator's next decision readable at a
   glance. Surfaces step from page → workspace chrome → working panel, while
   red remains reserved for the active route and primary/danger actions. */
.dashboard {
  background: var(--paper);
}

.side {
  background: color-mix(in srgb, var(--panel) 94%, var(--paper));
  box-shadow: 1px 0 0 rgba(28, 25, 23, 0.025);
}

.side-brand {
  margin-bottom: 4px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
}

.nav-group-label {
  margin-top: 18px;
  color: var(--muted);
  font-weight: 700;
}

.side a {
  position: relative;
  min-height: 38px;
  transition: color 160ms ease, background-color 160ms ease, transform 160ms ease;
}

.side a.active {
  color: var(--ink);
  background: var(--red-tint);
  box-shadow: none;
}

.side a.active svg {
  color: var(--red);
}

.workbench {
  gap: 20px;
}

.topbar {
  border-color: var(--line-strong);
  box-shadow: var(--shadow);
}

.topbar h2 {
  letter-spacing: -0.01em;
  text-wrap: balance;
}

.panel {
  border-color: var(--line-strong);
  box-shadow: var(--shadow);
}

.panel-head {
  margin-bottom: 16px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
}

.panel-head .pill {
  flex: 0 0 auto;
}

.eyebrow {
  color: var(--muted);
  font-weight: 700;
}

.pill {
  border-color: var(--line);
  color: var(--muted);
  background: var(--panel-strong);
  font-weight: 600;
}

button {
  transition: background-color 160ms ease, color 160ms ease, border-color 160ms ease, box-shadow 160ms ease, transform 160ms ease;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

button:active:not(:disabled) {
  transform: translateY(1px) scale(0.985);
}

input:not([type="checkbox"]):not([type="radio"]):not(.sr-only),
textarea,
select {
  transition: border-color 160ms ease, box-shadow 160ms ease, background-color 160ms ease;
}

.view:not([hidden]) {
  animation: ui-view-enter 200ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
}

/* Ends at none, not translateY(0): with fill-mode both the end frame stays
   applied, and any transform other than none turns every open view into the
   containing block for position: fixed descendants. */
@keyframes ui-view-enter {
  from {
    opacity: 0;
    transform: translateY(4px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@media (hover: hover) and (pointer: fine) {
  .side a:hover {
    transform: translateX(2px);
  }

  button:hover:not(:disabled) {
    box-shadow: 0 2px 5px rgba(28, 25, 23, 0.1);
    transform: translateY(-1px);
  }

  button.ghost:hover,
  button.secondary:hover {
    box-shadow: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .side a,
  button,
  input:not([type="checkbox"]):not([type="radio"]):not(.sr-only),
  textarea,
  select {
    transition: none;
  }

  .view:not([hidden]) {
    animation: none;
  }
}

/* Projects list: sort control sits beside the auto-refresh pill. */
.project-list-tools {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  flex-wrap: wrap;
}

.project-list-tools select {
  min-width: 170px;
  min-height: 36px;
  border-radius: 8px;
}

@media (max-width: 680px) {
  .project-list-tools,
  .project-list-tools select {
    width: 100%;
  }
}

/* Doc 77 P7: Rules panels (node inspector + blueprint policy area).
   Mode is shown as dot + label, never colour alone; the dot colours are the
   semantic status colours (red fail, amber review, neutral warn/off). */
.bp-policy-rules {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}

.bp-rules {
  margin-top: 8px;
  min-width: 0;
}

.bp-rules-preset {
  max-width: 520px;
}

.bp-rules-help,
.bp-rules-warn,
.bp-rules-relaxed {
  margin: 4px 0 8px;
  max-width: 72ch;
  font-size: 12px;
  line-height: 1.6;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.bp-rules-warn {
  padding: 6px 10px;
  border: 1px solid var(--line-strong);
  border-left: 3px solid var(--amber);
  border-radius: var(--radius-control);
  background: var(--amber-tint);
  color: var(--ink);
}

.bp-rules-relaxed-on {
  padding: 2px 0 2px 10px;
  border-left: 3px solid var(--amber);
  color: var(--ink);
}

.bp-rules-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
  margin: 8px 0;
}

.bp-rules-filter {
  flex: 1 1 220px;
  max-width: 320px;
}

.bp-rules-empty {
  margin: 8px 0;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  background: var(--panel-strong);
  font-size: 12px;
  line-height: 1.6;
  color: var(--muted);
}

.bp-rules-error {
  color: var(--red-deep);
}

.bp-rules-status.bp-rules-error {
  padding: 6px 10px;
  border: 1px solid var(--red);
  border-radius: var(--radius-control);
  background: var(--red-tint);
}

.bp-rule-group {
  margin: 6px 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  background: var(--panel);
}

.bp-rule-group > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 10px;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.5;
  color: var(--ink);
  cursor: pointer;
}

.bp-rule-group-count {
  font-size: 11px;
  font-weight: 500;
  color: var(--muted-2);
  white-space: nowrap;
}

.bp-rule-list {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line);
}

.bp-rule {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(150px, 210px);
  gap: 4px 12px;
  align-items: center;
  padding: 8px 10px;
  border-bottom: 1px solid var(--line);
}

.bp-rule:last-child { border-bottom: 0; }

.bp-rule-dirty {
  background: var(--stone-tint);
  box-shadow: inset 3px 0 0 var(--line-strong);
}

.bp-rule-main {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.bp-rule-label {
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink);
  overflow-wrap: anywhere;
}

.bp-rule-id {
  align-self: flex-start;
  padding: 0;
  background: transparent;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.5;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.bp-rule-effective {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 2px 8px;
  font-size: 11px;
  line-height: 1.5;
  color: var(--muted);
}

.bp-rule-mode {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink);
}

.bp-rule-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--muted-3);
}

.bp-rule-mode-fail .bp-rule-dot { background: var(--red); }
.bp-rule-mode-review .bp-rule-dot { background: var(--amber); }
.bp-rule-mode-warn .bp-rule-dot { background: transparent; box-shadow: inset 0 0 0 2px var(--amber); }
.bp-rule-mode-off .bp-rule-dot { background: transparent; box-shadow: inset 0 0 0 1.5px var(--muted-3); }

.bp-rule-unsaved {
  font-weight: 600;
  color: var(--ink);
}

.bp-rule-control .bp-rule-select {
  width: 100%;
}

.bp-rule-lock {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--muted);
}

.bp-rule-ref,
.bp-rule-note {
  grid-column: 1 / -1;
}

.bp-rule-ref {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
}

.bp-rule-ref label {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
}

.bp-rule-ref input {
  flex: 1 1 220px;
  max-width: 360px;
}

.bp-rule-note {
  margin: 0;
  font-size: 11px;
  line-height: 1.6;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.bp-rule-note:empty { display: none; }

/* Doc 77 P9e: values set inside a rule. */
.bp-rule-params {
  grid-column: 1 / -1;
  display: grid;
  gap: 8px;
  padding: 6px 0 2px 10px;
  border-left: 2px solid var(--line);
}

.bp-param {
  display: grid;
  gap: 4px;
}

.bp-param-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
}

.bp-param-label {
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
  color: var(--muted);
}

.bp-param-count {
  font-size: 11px;
  line-height: 1.5;
  color: var(--muted);
}

.bp-param-looser {
  padding: 0 6px;
  border-radius: 999px;
  background: var(--amber-tint);
  font-size: 11px;
  font-weight: 600;
  line-height: 1.6;
  /* --amber (#d97706) on --amber-tint is ~2.9:1 at 11px; this darker amber
     keeps the warning hue and passes WCAG AA 4.5:1 for small text. */
  color: #92400e;
}

.bp-param-add {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}

.bp-param-add input {
  flex: 1 1 160px;
  min-width: 0;
  max-width: 280px;
}

.bp-param-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.bp-param-chips:empty { display: none; }

.bp-param-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  max-width: 100%;
  padding: 0 4px 0 8px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--panel);
  font-size: 12px;
  line-height: 1.6;
  color: var(--ink);
  overflow-wrap: anywhere;
}

.bp-param-chip-remove {
  min-width: 24px;
  min-height: 24px;
  padding: 0 4px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  line-height: 1.4;
}

.bp-param-chip-remove:hover:not(:disabled),
.bp-param-chip-remove:focus-visible { background: var(--red-tint); color: var(--red); }

.bp-param-help,
.bp-param-error {
  margin: 0;
  font-size: 11px;
  line-height: 1.6;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.bp-param-error { color: var(--red); }

.bp-param-limit {
  color: var(--muted);
}

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

/* A direct child of the inspector grid: span both columns rather than
   auto-placing into column 2 under an empty settings column. */
.bp-rules-section {
  grid-column: 1 / -1;
  margin: 14px 0 0;
  padding: 10px 0 0;
  border-top: 1px solid var(--line);
  border-bottom: 0;
}

.bp-rules-section > summary {
  cursor: pointer;
}


/* Doc 78 R5: "Change rules with AI" dialog. Tokens only; semantic colours for
   direction (amber = looser, teal = stricter); Thai-safe line-height. */
.rule-draft-modal {
  max-width: 680px;
  max-height: calc(100vh - 48px);
  overflow-y: auto;
}
.rule-draft-modal .bp-modal-body textarea,
.rule-draft-modal .rd-reason textarea { min-height: 0; }
.rule-draft-modal #ruleDraftInstruction { min-height: 96px; }
.rule-draft-modal p,
.rule-draft-modal label,
.rule-draft-modal li { line-height: 1.6; overflow-wrap: anywhere; }
.bp-rule-draft-row { margin: 8px 0; justify-content: flex-start; }
.rd-counter { margin: 4px 0 0; text-align: right; }
.rd-status { margin: 0; min-height: 1.6em; }
.rd-error {
  margin: 0;
  padding: 8px 10px;
  border: 1px solid var(--red);
  border-radius: 8px;
  background: var(--red-tint);
  color: var(--ink);
  line-height: 1.6;
  overflow-wrap: anywhere;
}
.rd-error[hidden] { display: none; }
.rd-items { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.rd-item {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 10px 12px;
  background: var(--panel);
}
.rd-item-locked { background: var(--paper); }
.rd-item-row { display: flex; align-items: flex-start; gap: 10px; min-height: 44px; }
.rd-item-row input[type="checkbox"] { margin-top: 5px; flex: none; width: 16px; height: 16px; }
.rd-item-label { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; font-size: 13px; color: var(--ink); cursor: pointer; }
.rd-item-name { font-weight: 600; }
.rd-change { color: var(--muted); }
.rd-before { text-decoration: line-through; text-decoration-color: var(--muted-2); }
.rd-after { color: var(--ink); font-weight: 600; }
.rd-badge {
  flex: none;
  font-size: 11px;
  font-weight: 500;
  line-height: 1.5;
  padding: 1px 8px;
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  background: var(--paper);
  color: var(--muted);
}
.rd-badge-relax { background: var(--amber-tint); border-color: var(--amber); color: var(--ink); }
.rd-badge-tighten { background: var(--teal-tint); border-color: var(--teal); color: var(--ink); }
.rd-note { margin: 6px 0 0 26px; }
.rd-reason { margin: 8px 0 0 26px; display: flex; flex-direction: column; gap: 4px; }
.rd-reason[hidden] { display: none; }
.rd-reason-help { margin: 0; font-size: 12px; color: var(--muted); }
.rd-reason-help.rd-reason-invalid { color: var(--red); font-weight: 500; }
.rd-reason textarea[aria-invalid="true"] { border-color: var(--red); }
.rd-empty { margin: 0; }
@media (max-width: 560px) {
  .rd-item-row { flex-wrap: wrap; }
  .rd-note, .rd-reason { margin-left: 0; }
}

.rd-elapsed { margin: 0; }
.rd-elapsed:empty { display: none; }
.rule-draft-modal .bp-modal-actions {
  position: sticky;
  bottom: 0;
  margin: 0 -20px -20px;
  padding: 12px 20px;
  background: var(--panel);
  border-top: 1px solid var(--line);
}

/* ---------- Copilot: one-column AI chat (cp-*) ----------
   Replaces the old two-column chat + "Before running" panel. Neutral stone
   surfaces, ink text. MISUMI red is held to ONE primary per view: the Send
   button, unless an inline Preview plan / Approve plan button is on screen, in
   which case that button is the primary and Send turns neutral.
   Scoped to #view-copilot so nothing here leaks into other screens. */
/* Owner 2026-10-05: back to a centered column (920px) instead of the full
   desktop width; narrower screens still use all the width they have. */
#view-copilot .cp-layout {
  display: block;
  width: 100%;
  max-width: 920px;
  margin: 0 auto;
}

/* Owner 2026-10-04: no card around the chat, composer pinned to the viewport
   bottom. While the Copilot view is open the workbench becomes a viewport-high
   flex column; the view takes whatever is left under the title bar (and the
   Workspace Setup panel / model banner when shown) and the stream is the only
   scrolling region. No 100dvh - N magic number: a taller block above just
   leaves the chat less room. If that room drops under the min-height below,
   the workbench itself scrolls (graceful fallback, window never does). */
.workbench:has(> #view-copilot:not([hidden])) {
  display: flex;
  flex-direction: column;
  align-content: normal;
  height: 100vh;
  height: 100dvh;
  overflow-y: auto;
  padding-bottom: calc(14px + env(safe-area-inset-bottom, 0px));
}

.workbench:has(> #view-copilot:not([hidden])) > * {
  flex: 0 0 auto;
}

/* .topbar carries align-self:start for the grid layout; in this flex column
   that would shrink the page title bar to its content width. */
.workbench:has(> #view-copilot:not([hidden])) > .topbar {
  align-self: stretch;
}

.workbench > #view-copilot:not([hidden]) {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 420px;
}

#view-copilot .cp-layout {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

#view-copilot .cp-panel {
  position: relative;
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 10px;
  min-height: 0;
  padding: 0;
  overflow: hidden;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  background: var(--paper);
}

#view-copilot .cp-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px 12px;
  flex-wrap: wrap;
}

#view-copilot .cp-head h3 {
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
}

#view-copilot .cp-head-tools {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: nowrap;
  min-width: 0;
}

#view-copilot .cp-head-tools select {
  flex: 0 1 260px;
  min-width: 0;
  max-width: 260px;
  min-height: 34px;
  line-height: 1.5;
  border-color: var(--line-strong);
  background: var(--panel);
  text-overflow: ellipsis;
}

#view-copilot .cp-head-tools button {
  white-space: nowrap;
}

#view-copilot .cp-head-tools button {
  min-height: 34px;
}

/* The banner sits outside the scroll area and never shrinks over the stream. */
#view-copilot .cp-panel > .run-context-banner {
  flex: 0 0 auto;
  margin: 0;
}

#view-copilot .cp-stream-wrap {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--line);
}

#view-copilot .cp-stream {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 14px 4px 12px;
}

#view-copilot .cp-stream:focus-visible,
#view-copilot .cp-icon-btn:focus-visible,
#view-copilot .cp-send:focus-visible,
#view-copilot .cp-chip:focus-visible,
#view-copilot .cp-jump:focus-visible,
#view-copilot .cp-inline-actions button:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* Empty state: greeting + suggestion chips, centred in the stream. */
#view-copilot .cp-empty {
  margin: auto;
  max-width: 460px;
  display: grid;
  justify-items: center;
  gap: 8px;
  padding: 24px 8px;
  text-align: center;
}

#view-copilot .cp-empty[hidden] {
  display: none;
}

#view-copilot .cp-empty b {
  font-size: 16px;
  font-weight: 600;
  line-height: 1.6;
}

#view-copilot .cp-empty p {
  margin: 0;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.7;
}

#view-copilot .cp-chips {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  margin-top: 6px;
}

#view-copilot .cp-chip {
  min-height: 36px;
  padding: 0 14px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  color: var(--ink);
  background: var(--panel);
  font-weight: 500;
  line-height: 1.5;
  white-space: normal;
}

#view-copilot .cp-chip:hover {
  background: var(--panel-strong);
}

/* Messages. The person's message stays a bubble on the right. The reply reads
   as prose under a quiet "Copilot" label: a soft borderless surface, no notched
   corner, and no "AI" avatar tile (owner, 2026-10-05). */
#view-copilot .cp-msg {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  min-width: 0;
}

#view-copilot .cp-msg[hidden] {
  display: none;
}

#view-copilot .cp-msg.user {
  justify-content: flex-end;
}

/* The reply stacks instead of sitting beside an avatar: name, then bubble. */
#view-copilot .cp-msg.assistant {
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
}

/* Deliberately quieter than the .cp-kind label ("Plan"/"Result"/"Error") that
   can sit right under it, so the two stacked lines do not compete. */
#view-copilot .cp-name {
  padding-left: 2px;
  color: var(--muted-2);
  font-size: 11px;
  font-weight: 500;
  line-height: 1.5;
}

#view-copilot .cp-bubble {
  min-width: 0;
  max-width: min(100%, 68ch);
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
  color: var(--ink);
  font-size: 13px;
  line-height: 1.65;
  overflow-wrap: anywhere;
}

/* The soft shadow is what makes this a bubble: the stream sits on --paper, so
   a --panel-strong fill without a border would be ~1.05:1 and read as nothing. */
#view-copilot .cp-msg.assistant .cp-bubble {
  padding: 11px 15px;
  border: 0;
  border-radius: 14px;
  background: var(--panel);
  box-shadow: var(--shadow);
}

#view-copilot .cp-msg.user .cp-bubble {
  max-width: min(86%, 60ch);
  border-color: var(--line-strong);
  background: var(--panel-strong);
}

/* Must come after the assistant rule above, which sets border: 0 at the same
   specificity -- the red border is the error signal and has to survive it. */
#view-copilot .cp-msg .cp-bubble.is-error {
  border: 1px solid rgba(198, 40, 40, 0.35);
  background: var(--red-tint);
  box-shadow: none;
}

/* A plan/file card is wider than prose; let the live bubble use the full row.
   The reply column stretches it -- in the old avatar row this was flex: 1. */
#view-copilot #copilotLiveMessage .cp-bubble,
#view-copilot #copilotResultsMessage .cp-bubble {
  align-self: stretch;
  max-width: none;
}

#view-copilot .cp-bubble p {
  margin: 0;
  white-space: pre-wrap;
}

#view-copilot .cp-kind,
#view-copilot .cp-time,
#view-copilot .cp-elapsed {
  color: var(--muted);
  font-size: 11px;
  line-height: 1.5;
}

#view-copilot .cp-kind {
  display: block;
  margin-bottom: 2px;
  font-weight: 500;
}

#view-copilot .cp-time {
  display: block;
  margin-top: 4px;
}

#view-copilot .cp-elapsed {
  display: block;
  margin-top: 4px;
}

#view-copilot .cp-file-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  max-width: 100%;
  font-weight: 500;
}

#view-copilot .cp-file-chip svg {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  color: var(--muted);
}

/* The live bubble: waiting dots + status text, then the card, then controls. */
#view-copilot .cp-thinking {
  display: flex;
  align-items: center;
  gap: 10px;
}

#view-copilot .cp-thinking .copilot-reply {
  flex: 1;
  min-width: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ink);
  font-weight: 400;
  font-size: 13px;
  line-height: 1.65;
}

#view-copilot #copilotLiveMessage[data-live-mode="thinking"] .typing-dots {
  display: inline-flex;
  flex: 0 0 auto;
}

#view-copilot #copilotLiveMessage[data-live-mode="thinking"] .copilot-reply {
  color: var(--muted);
}

#view-copilot #copilotLiveMessage[data-live-mode="error"] .cp-bubble {
  border: 1px solid rgba(198, 40, 40, 0.35);
  background: var(--red-tint);
  box-shadow: none;
}

#view-copilot .cp-bubble .copilot-file-card,
#view-copilot .cp-bubble .copilot-actions,
#view-copilot .cp-bubble .copilot-results {
  margin-top: 10px;
}

#view-copilot .cp-bubble .copilot-actions:empty {
  display: none;
}

/* No card inside the bubble: the bubble is the card. Items are separated by a
   rule instead of a second border. */
#view-copilot .cp-bubble .copilot-action-card,
#view-copilot .cp-bubble .copilot-file-card {
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
}

#view-copilot .cp-bubble .copilot-action-card + .copilot-action-card {
  padding-top: 12px;
  border-top: 1px solid var(--line);
}

#view-copilot .cp-bubble .copilot-not-applied {
  margin-top: 8px;
}

#view-copilot .cp-inline-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}

#view-copilot .cp-inline-actions[hidden] {
  display: none;
}

#view-copilot .cp-inline-actions button {
  min-height: 36px;
  line-height: 1.5;
}

#view-copilot .cp-jump {
  position: absolute;
  left: 50%;
  bottom: 10px;
  transform: translateX(-50%);
  min-height: 32px;
  padding: 0 12px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  color: var(--ink);
  background: var(--panel);
  box-shadow: var(--shadow);
  font-size: 12px;
  font-weight: 500;
  line-height: 1.5;
}

#view-copilot .cp-jump[hidden] {
  display: none;
}

/* Composer pinned to the bottom of the panel. Idle border is neutral. Focus is
   a quiet, even 2px grey edge drawn INSIDE the box (border + inset shadow):
   an outer outline was clipped by the panel's overflow and looked broken and
   lopsided (owner feedback 2026-10-04). Never red, never black. Buttons and
   the select inside keep their own :focus-visible rings. */
#view-copilot .cp-composer {
  flex: 0 0 auto;
  display: grid;
  gap: 8px;
  padding: 10px 12px;
  border: 1px solid var(--line-strong);
  border-radius: 12px;
  background: var(--panel);
  box-shadow: 0 1px 2px rgba(28, 25, 23, 0.04);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

#view-copilot .cp-composer:has(textarea:focus) {
  border-color: var(--muted-2);
  box-shadow: inset 0 0 0 1px var(--muted-2), 0 1px 2px rgba(28, 25, 23, 0.04);
  outline: none;
}

@media (prefers-reduced-motion: reduce) {
  #view-copilot .cp-composer {
    transition: none;
  }
}

#view-copilot .cp-input-row {
  display: flex;
  align-items: flex-end;
  gap: 8px;
}

#view-copilot .cp-input-row textarea {
  flex: 1;
  min-width: 0;
  min-height: 44px;
  max-height: 168px;
  margin: 0;
  padding: 10px 4px;
  border: 0;
  outline: 0;
  box-shadow: none;
  resize: none;
  background: transparent;
  color: var(--ink);
  font-size: 14px;
  line-height: 1.6;
  overflow-y: auto;
}

#view-copilot .cp-input-row textarea::placeholder {
  color: var(--muted);
}

#view-copilot .cp-icon-btn,
#view-copilot .cp-send {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 44px;
  min-width: 44px;
}

#view-copilot .cp-icon-btn {
  padding: 0;
  border: 1px solid transparent;
  color: var(--muted);
  background: transparent;
}

#view-copilot .cp-icon-btn:hover:not(:disabled) {
  color: var(--ink);
  background: var(--panel-strong);
}

#view-copilot .cp-icon-btn svg,
#view-copilot .cp-send svg {
  width: 20px;
  height: 20px;
}

#view-copilot .cp-send {
  padding: 0 14px;
}

/* One red primary per view: while an inline Preview/Approve plan button is on
   screen it owns the red, and Send is neutral. */
#view-copilot .cp-panel:has([data-copilot-inline-preview], [data-copilot-inline-approve], [data-copilot-apply]) .cp-send {
  color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--line-strong);
}

#view-copilot .cp-panel:has([data-copilot-inline-preview], [data-copilot-inline-approve], [data-copilot-apply]) .cp-send:hover:not(:disabled) {
  background: var(--panel-strong);
}

#view-copilot .cp-send:disabled,
#view-copilot .cp-icon-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

#view-copilot .cp-send.is-busy svg {
  animation: cp-pulse 1.2s ease-in-out infinite;
}

@keyframes cp-pulse {
  50% { opacity: 0.35; }
}

/* Staged file chips (rendered by createFileStaging) sit inside the composer. */
#view-copilot .cp-pending {
  margin: 0;
  border-radius: 8px;
  background: var(--panel-strong);
  max-height: 132px;
  overflow-y: auto;
}

#view-copilot .cp-composer-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 12px;
}

#view-copilot .cp-project {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
}

#view-copilot .cp-project select {
  min-width: 0;
  max-width: min(320px, 60vw);
  min-height: 32px;
  padding: 2px 8px;
  border-color: var(--line-strong);
  background: var(--panel);
  font-size: 12px;
  line-height: 1.5;
}

/* Drop overlay over the whole panel. */
#view-copilot .cp-drop-overlay {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: grid;
  place-items: center;
  padding: 24px;
  border: 2px dashed var(--line-strong);
  border-radius: var(--radius-card);
  background: var(--paper);
  color: var(--ink);
  text-align: center;
  pointer-events: none;
}

#view-copilot .cp-drop-overlay[hidden] {
  display: none;
}

#view-copilot .cp-drop-overlay div {
  display: grid;
  gap: 4px;
}

#view-copilot .cp-drop-overlay b {
  font-size: 16px;
  line-height: 1.6;
}

#view-copilot .cp-drop-overlay span {
  color: var(--muted);
  font-size: 13px;
  line-height: 1.6;
}

@media (max-width: 680px) {
  .workbench:has(> #view-copilot:not([hidden])) {
    padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  }

  #view-copilot .cp-msg.user .cp-bubble {
    max-width: 92%;
  }

  #view-copilot .cp-send .cp-send-label {
    display: none;
  }

  #view-copilot .cp-send {
    padding: 0;
  }

  #view-copilot .cp-project select {
    max-width: 100%;
  }
}

/* Phones: header stays on one line (the select truncates, New chat never
   wraps), and every control is a 44px touch target. */
@media (max-width: 480px) {
  #view-copilot .cp-head {
    flex-wrap: nowrap;
  }

  #view-copilot .cp-head h3 {
    flex: 0 0 auto;
  }

  #view-copilot .cp-head-tools {
    flex: 1 1 auto;
    flex-wrap: nowrap;
    justify-content: flex-end;
  }

  #view-copilot .cp-head-tools select {
    flex: 1 1 0;
    min-width: 0;
    max-width: none;
    min-height: 44px;
  }

  #view-copilot .cp-head-tools button {
    flex: 0 0 auto;
    min-height: 44px;
  }

  #view-copilot .cp-chip,
  #view-copilot .cp-inline-actions button,
  #view-copilot .cp-jump {
    min-height: 44px;
  }

  #view-copilot .cp-project select {
    min-height: 44px;
  }
}

@media (prefers-reduced-motion: reduce) {
  #view-copilot .cp-send.is-busy svg {
    animation: none;
  }
}

/* Doc 78 R6: Fix with AI on a flagged row, and the rerun offer after a rule is saved. */
.rule-fix-list { margin-top: 6px; }
.rule-fix-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; margin: 0 0 4px; line-height: 1.5; }
.rule-fix-id { color: var(--muted); font-size: 11px; font-weight: 500; overflow-wrap: anywhere; }
.rule-fix-offer:not(:empty) {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px;
  margin: 8px 0; padding: 8px 12px;
  border: 1px solid var(--line); border-radius: 8px; background: var(--panel);
}
.rule-fix-offer p { margin: 0; line-height: 1.5; overflow-wrap: anywhere; }
.rule-fix-offer-note:empty { display: none; }
.rule-fix-row .ghost { border: 1px solid var(--line-strong); text-align: left; }

/* Copilot file-review card: confirm the saved column mapping. The list shows
   the server's mapping; uploaded headers are dynamic text, so wrap them. */
.copilot-mapping-confirm {
  margin: 10px 0 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 10px 12px;
  background: var(--panel);
  display: grid;
  gap: 8px;
}

.copilot-mapping-confirm > b {
  display: block;
}

.copilot-mapping-confirm p {
  margin: 0;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.6;
  overflow-wrap: anywhere;
}

.copilot-mapping-note.warn {
  border-left: 3px solid var(--amber);
  padding: 4px 8px;
  background: var(--amber-tint);
  color: var(--ink);
}

.copilot-mapping-confirm p.copilot-mapping-unroled:not([data-count="0"]) {
  color: var(--ink);
}

.copilot-mapping-file {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 9px 10px;
  display: grid;
  gap: 6px;
  min-width: 0;
}

.copilot-mapping-file-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
}

.copilot-mapping-file-head b {
  min-width: 0;
  overflow-wrap: anywhere;
  line-height: 1.5;
}

.copilot-mapping-badge {
  font-size: 11px;
  font-weight: 500;
  line-height: 1.5;
  padding: 1px 8px;
  border-radius: 999px;
}

.copilot-mapping-badge[data-state="pending"] {
  border: 1px solid var(--amber);
  background: var(--amber-tint);
  color: var(--ink);
}

.copilot-mapping-badge[data-state="saved"] {
  background: var(--teal-tint);
  color: var(--teal);
}

.copilot-mapping-list {
  display: grid;
  grid-template-columns: minmax(110px, 160px) minmax(0, 1fr);
  gap: 4px 12px;
  margin: 0;
  font-size: 13px;
  line-height: 1.6;
}

.copilot-mapping-list dt {
  color: var(--muted);
  font-weight: 600;
}

.copilot-mapping-list dd {
  margin: 0;
  min-width: 0;
  overflow-wrap: anywhere;
}

.copilot-mapping-list ul {
  margin: 0;
  padding-left: 16px;
}

.copilot-mapping-list .code-cell {
  white-space: normal;
  overflow-wrap: anywhere;
}

.copilot-mapping-result {
  font-size: 13px;
  line-height: 1.6;
  padding: 4px 8px;
  border-left: 3px solid var(--line-strong);
  background: var(--paper);
  color: var(--ink) !important;
}

.copilot-mapping-result[data-copilot-mapping-result="saved"] {
  border-left-color: var(--teal);
  background: var(--teal-tint);
}

.copilot-mapping-result[data-copilot-mapping-result="failed"],
.copilot-mapping-result[data-copilot-mapping-result="locked"] {
  border-left-color: var(--red);
  background: var(--red-tint);
}

.copilot-mapping-result[data-copilot-mapping-result="changed"] {
  border-left-color: var(--amber);
  background: var(--amber-tint);
}

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

@media (max-width: 560px) {
  .copilot-mapping-list {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Doc 85 P7b: the confirm card speaks the column mapping -- the draft count, the fields the project's plans need,
   and the "Use as" rows' real role. All text here is dynamic (uploaded headers, project names), so it wraps. */
.copilot-mapping-confirm p.copilot-mapping-counts {
  color: var(--ink);
  font-weight: 600;
}

.copilot-mapping-needs {
  border-left: 3px solid var(--line-strong);
  padding: 4px 10px;
  display: grid;
  gap: 4px;
  min-width: 0;
}

.copilot-mapping-needs ul {
  margin: 0;
  padding-left: 16px;
  font-size: 13px;
  line-height: 1.6;
  overflow-wrap: anywhere;
}

.copilot-mapping-needs .copilot-need-missing {
  color: var(--red);
  font-weight: 600;
}

.copilot-mapping-list details.copilot-mapping-detail > ul {
  margin-top: 4px;
}

.copilot-real-role {
  display: block;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.copilot-real-role[hidden] {
  display: none;
}

.manual-workflow-notices {
  display: grid;
  gap: 4px;
}

.manual-workflow-notices[hidden] {
  display: none;
}

.copilot-mapping-detail > summary {
  cursor: pointer;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.6;
}

.copilot-mapping-detail[open] > summary {
  margin-bottom: 6px;
}

/* W1: Copilot plan card -- expiry line, report notes, before/after previews.
   Side-by-side from 720px, stacked below so Thai text and long prompts wrap
   instead of overflowing. Changed items use text labels, not colour alone. */
.copilot-plan-expiry {
  margin: 0 0 8px;
  font-size: 12px;
  line-height: 1.5;
}

.copilot-action-card.is-note {
  background: var(--paper);
  border-style: dashed;
}

.copilot-compare {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
}

@media (min-width: 720px) {
  .copilot-compare:not(.is-single) {
    grid-template-columns: 1fr 1fr;
  }
}

.copilot-compare-side {
  min-width: 0;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
  font-size: 13px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.copilot-compare-side p {
  margin: 2px 0;
}

.copilot-compare-title {
  display: block;
  margin-bottom: 4px;
  color: var(--muted);
  font-size: 12px;
  font-weight: 650;
}

.copilot-outline-stages {
  margin: 4px 0 0;
  padding-left: 20px;
}

.copilot-outline-stages small {
  color: var(--muted);
}

.copilot-outline-stages em,
.copilot-compare-side p em {
  padding: 0 5px;
  border-radius: 4px;
  background: var(--amber-tint);
  color: var(--ink);
  font-size: 11px;
  font-style: normal;
  font-weight: 650;
}

.copilot-outline-stages li.is-changed {
  font-weight: 600;
}

.copilot-stage-preview {
  display: grid;
  gap: 6px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
}

.copilot-stage-mode {
  margin: 0;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
}

.copilot-prompt-text {
  margin: 0;
  max-height: 320px;
  overflow: auto;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font: inherit;
  font-size: 12px;
  line-height: 1.6;
}

/* ---------- Project column-mapping modal (owner 2026-10-06) ----------
   A centered dialog over the same mapping editor Manual Run uses. The body
   scrolls, the action bar stays in reach on a file with 100+ columns. */
.project-mapping-modal {
  max-width: min(980px, calc(100vw - 32px));
  width: calc(100vw - 32px);
  max-height: calc(100vh - 32px);
  overflow: hidden;
}
.project-mapping-modal[open] { display: flex; flex-direction: column; }
.project-mapping-body {
  max-height: calc(100vh - 34px);
  overflow: auto;
  gap: 10px;
}
.project-mapping-head h3 { margin: 0; font-size: 16px; line-height: 1.5; }
.project-mapping-file {
  margin: 2px 0 0;
  color: var(--muted);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.6;
  overflow-wrap: anywhere;
}
.project-mapping-modal p,
.project-mapping-modal label,
.project-mapping-modal .column-role-name { line-height: 1.6; overflow-wrap: anywhere; }
.project-mapping-modal .mapping-box:first-child { margin-top: 0; }
.project-mapping-state {
  padding: 14px;
  border: 1px dashed var(--line-strong);
  border-radius: 8px;
  color: var(--muted);
  line-height: 1.6;
}
.project-mapping-state.error {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  border-style: solid;
  border-color: var(--red);
  background: var(--red-tint);
  color: var(--ink);
}
.project-mapping-state[hidden],
.project-mapping-editor[hidden],
.project-mapping-discard[hidden] { display: none; }
.project-mapping-discard {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  padding: 10px 12px;
  border: 1px solid var(--amber);
  border-radius: 8px;
  background: var(--amber-tint);
  line-height: 1.6;
}
.project-mapping-discard span { flex: 1 1 220px; }
.project-mapping-actions {
  position: sticky;
  bottom: -20px;
  z-index: 2;
  flex-wrap: wrap;
  align-items: center;
  margin: 0 -20px -20px;
  padding: 12px 20px;
  border-top: 1px solid var(--line);
  background: var(--panel);
}
.project-mapping-actions .mapping-actions-hint { flex: 1 1 200px; text-align: left; }
.project-mapping-actions .mapping-count-line { flex: 1 1 100%; }

/* "Mapping not saved" on a project file row, with its one-click way in. */
.task-mapping-flag {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 4px;
}
.task-mapping-flag .pill { line-height: 1.5; }

.manual-mapping-save-btn { margin-left: 8px; }
.manual-mapping-save-msg { margin-left: 8px; font-size: 12px; line-height: 1.6; }
.readiness-ask-admin { font-weight: 600; }
.empty-state-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
#copilotBackToProject { max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.project-mapping-actions .mapping-actions-hint:empty { display: none; }
@media (max-width: 640px) {
  .project-mapping-modal { width: calc(100vw - 16px); max-width: calc(100vw - 16px); max-height: calc(100vh - 16px); }
  .project-mapping-body { padding: 14px; max-height: calc(100vh - 18px); }
  .project-mapping-actions { bottom: -14px; margin: 0 -14px -14px; padding: 10px 14px; gap: 6px; justify-content: stretch; }
  .project-mapping-actions button { flex: 1 1 calc(50% - 6px); min-height: 40px; }
  .project-mapping-actions .mapping-dirty-indicator { flex: 1 1 100%; text-align: center; }
}
@media (max-width: 640px) {
  .project-mapping-modal .project-mapping-actions { flex-direction: row; flex-wrap: wrap; align-items: stretch; }
  .project-mapping-modal .project-mapping-actions button { width: auto; flex: 1 1 calc(50% - 6px); min-height: 40px; }
}

/* ==========================================================================
   Row review hosts + the phone card layout (doc 80 Wave 1: B3 + HI-2)
   Placed last on purpose. The neutral-SaaS passes above set
   `.row-review-table td` padding/borders and the 680px block re-sets that
   padding, so these rules must come later to win at equal specificity.
   ========================================================================== */

/* Why the review panel was 1,152px wide on a 390px phone: `.workbench` and
   `.view` are grids with one implicit auto column, so a grid item with the
   default `min-width: auto` reports its content's minimum width upward --
   and `.row-review-table { min-width: 900px }` is that content. `min-width: 0`
   on each host lets the table scroll inside its own wrapper instead of
   stretching the page. Targeted at the hosts; deliberately not a global rule. */
.run-row-review-host,
.history-review-slot,
.file-task-review-host,
#projectInlineReviewHost,
#historyReviewHost {
  min-width: 0;
}

/* A host with nothing in it must not leave an empty row (and its grid gap)
   behind in the card lists it sits in. `.file-task-review-host:empty` is
   declared with the file-task rules above. Needs truly empty markup: a
   whitespace-only host is not `:empty`. */
.run-row-review-host:empty,
.history-review-slot:empty,
#projectInlineReviewHost:empty,
#historyReviewHost:empty,
.run-card-actions:empty {
  display: none;
}

/* The panel sits directly under the card/run it belongs to; the list grid's
   own gap is the spacing, so drop the panel's stand-alone top margin. */
.history-review-slot .review-panel,
.run-row-review-host .review-panel {
  margin-top: 0;
}

/* Export / review buttons on the face of a History run card at every width
   (they used to live inside the collapsed "Run details" disclosure, so a
   phone showed no review button at all). A wrapping row, same button and
   link styles as before -- only the position changed. */
.run-card-actions {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  min-width: 0;
}

.run-card-actions > .run-export-links {
  flex: 1 1 100%;
  margin: 0;
}

@media (max-width: 680px) {
  /* ---- HTML preview panel: stay inside the viewport ---- */
  .html-preview-head {
    grid-template-columns: minmax(0, 1fr);
  }

  .html-preview-head > div,
  .html-preview-summary,
  .html-preview-qa {
    min-width: 0;
    overflow-wrap: anywhere;
  }

  .html-preview-layout,
  .preview-output-fields {
    grid-template-columns: minmax(0, 1fr);
  }

  /* ---- Row review table -> one card per row ----
     Each <td> carries data-label (the column heading, in the screen language) and
     data-col (a fixed id: index, series, status, score, decision, reason, actions);
     the cell's own label is drawn from data-label and every rule below that names a
     column keys on data-col, so a translated heading cannot unstyle a column
     (D270 W3c). The <thead> stays in the DOM and is read by screen readers,
     it is only taken out of the visual layout (same pattern as .sr-only). */
  .row-review-table-wrap,
  .file-task-review-host .row-review-table-wrap {
    max-height: none;
    border: 0;
    border-radius: 0;
    background: transparent;
  }

  .row-review-table,
  .row-review-table tbody,
  .row-review-table tr,
  .row-review-table td {
    display: block;
  }

  .row-review-table {
    width: 100%;
    min-width: 0;
  }

  .row-review-table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* `tr.review` / `tr.fail` (specificity 0,2,1) keep their amber/red tint over
     this card background. */
  .row-review-table tbody tr {
    padding: 12px 14px;
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--panel);
  }

  .row-review-table tbody tr + tr {
    margin-top: 12px;
  }

  .row-review-table td {
    padding: 6px 0;
    border-bottom: 0;
    line-height: 1.55;
    overflow-wrap: anywhere;
  }

  .row-review-table td::before {
    content: attr(data-label);
    display: block;
    margin-bottom: 2px;
    color: var(--muted);
    font-size: 11px;
    font-weight: 600;
    line-height: 1.5;
  }

  /* Loading / empty / error rows are one <td colspan> with no data-label:
     a plain message, no label. */
  .row-review-table td[colspan] {
    padding: 8px 2px;
  }

  .row-review-table td[colspan]::before,
  .row-review-table td:not([data-label])::before {
    content: none;
  }

  /* Short facts share lines instead of one full-width line each. */
  .row-review-table td[data-col="status"],
  .row-review-table td[data-col="score"],
  .row-review-table td[data-col="decision"] {
    display: inline-block;
    max-width: 100%;
    margin-right: 20px;
    vertical-align: top;
  }

  /* The long cells get a rule above them so the card scans in sections. Risk
     and the generated text now sit in the Reason cell's Details, so Reason is
     the one long text cell left (the old Required review / Risk / Generated
     output labels no longer exist). */
  .row-review-table td[data-col="reason"],
  .row-review-table td.review-actions {
    margin-top: 6px;
    padding-top: 10px;
    border-top: 1px solid var(--line);
  }

  /* Preview / Approve / Reject / Clear: wrap onto as many lines as needed, no
     horizontal scroll, comfortable touch height (>= 24px floor, WCAG 2.5.8). */
  .row-review-table td.review-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    min-width: 0;
  }

  .row-review-table td.review-actions::before {
    flex: 0 0 100%;
    margin-bottom: 0;
  }

  .row-review-table td.review-actions .tiny {
    min-height: 36px;
    margin: 0;
    padding: 0 12px;
    font-size: 13px;
  }
}

/* ==========================================================================
   Wave 2 status visuals (doc 80, step 2b CSS: B2 bars, HI-3 / HI-4 / HI-8, PJ-4)
   Appended last on purpose: the neutral-SaaS polish layers above restyle
   `button`, `.pill`, `.row-review-table td` and `.review-guidance`, so these
   rules must come later to win at equal specificity. Tokens only, no colour
   literals and no motion. Desktop-only row rules sit in a min-width media
   query so they can never override the phone card rules of the block above.
   ========================================================================== */

/* ---- QA bar: pass (teal) / needs your check (amber) / failed (red) ----------
   The track is the neutral remainder, so the unprocessed share of a run is the
   empty part and green is full only when every row passed. It is white with a
   ring, not grey: amber on white is 3.2:1 but amber on --panel-strong is 2.9:1,
   under the 3:1 non-text minimum. The markup emits a
   segment for every outcome, including zero-width ones, with an inline width.
   Segments therefore carry no min-width, border, margin or gap (the track has
   no gap either): any of those would make a 0% segment visible and push the
   total past 100%. */
.qa-bar {
  display: flex;
  width: 100%;
  height: 8px;
  margin-top: 4px;
  border-radius: 999px;
  background: var(--panel);
  box-shadow: inset 0 0 0 1px var(--line-strong);
  overflow: hidden;
}

.qa-bar--sm {
  height: 6px;
}

.qa-bar-seg {
  display: block;
  flex: 0 0 auto;
  height: 100%;
}

.qa-bar-seg.is-pass { background: var(--teal); }
.qa-bar-seg.is-review { background: var(--amber); }
.qa-bar-seg.is-fail { background: var(--red); }

/* "Not scored": a quiet grey bar that carries its own label, so it can never
   be mistaken for an empty or a full coloured bar. */
.qa-bar.is-unscored {
  align-items: center;
  height: auto;
  min-height: 20px;
  padding: 0 10px;
  background: var(--panel-strong);
}

.qa-bar.is-unscored.qa-bar--sm {
  min-height: 18px;
}

.qa-bar-label {
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
}

/* ---- Score bar: score against the 95 target ----------------------------------
   Same tone bands as the QA bar and the preview score (>=95 teal, >=80 amber,
   below red, no number neutral). The target tick sticks out above and below
   the track so it stays visible when the fill passes it. */
.score-bar {
  position: relative;
  display: block;
  width: 112px;
  max-width: 100%;
  height: 8px;
  border-radius: 999px;
  background: var(--panel);
  box-shadow: inset 0 0 0 1px var(--line-strong);
}

.score-bar-fill {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  max-width: 100%;
  border-radius: inherit;
  background: var(--muted-3);
}

.score-bar.is-pass > .score-bar-fill { background: var(--teal); }
.score-bar.is-review > .score-bar-fill { background: var(--amber); }
.score-bar.is-fail > .score-bar-fill { background: var(--red); }
.score-bar.is-neutral > .score-bar-fill { background: var(--muted-3); }

.score-bar-target {
  position: absolute;
  top: -3px;
  bottom: -3px;
  width: 2px;
  margin-left: -1px;
  border-radius: 1px;
  background: var(--ink);
  pointer-events: none;
}

.score-value {
  color: var(--ink);
  font-weight: 600;
  line-height: 1.5;
}

.score-delta {
  display: block;
  margin-top: 4px;
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.5;
  white-space: nowrap;
}

/* ---- Project header: one wrapping row of chips + a small QA bar (PJ-4) ------- */
.project-header-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 8px;
  min-width: 0;
  margin: 10px 0 0;
}

/* A flex display would otherwise beat the `hidden` attribute (no run yet). */
.project-header-chips[hidden],
.project-header-chips:empty {
  display: none;
}

.project-header-chips .pill {
  max-width: 100%;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.project-header-chips .qa-bar {
  flex: 0 0 96px;
  width: 96px;
  margin: 0;
}

/* ---- Check rows: one summary line, details folded (HI-3) ----------------------- */
/* Status and decision chips are inline-block chips. `.row-review-table td span`
   (display: block) would stretch them to the full column width. */
.row-review-table td > .qa-chip,
.row-review-table td > .decision-chip {
  display: inline-block;
}

/* "High risk" marker under the status chip: a small amber tint, not red. Red
   stays with failures and the page already has its share of it; amber is the
   "check this" colour. Ink on amber-tint is about 16:1 (amber text on it would
   be 2.9:1). Sized to fit the folded row: 11px x 1.5 line + 2px border = 18.5px
   plus a 3px gap under the 23px status chip, so the Status cell stays under the
   Reason cell (the tallest) and the row stays within 64px. The two-class
   selector outranks `.row-review-table td span { display: block }`. */
.row-review-table td .row-risk-high {
  display: block;
  width: fit-content;
  max-width: 100%;
  margin-top: 3px;
  padding: 0 6px;
  border: 1px solid color-mix(in srgb, var(--amber) 55%, var(--line));
  border-radius: 999px;
  color: var(--ink);
  background: var(--amber-tint);
  font-size: 11px;
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
}

/* One line with an ellipsis. `-webkit-box` + line-clamp is the one clamp that
   also works for Thai, which has no spaces to break on. The second selector
   outranks `.row-review-table td span { display: block }` when the reason is a
   span. The full text lives in the Details disclosure. */
.row-reason,
.row-review-table td .row-reason {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 1;
  line-clamp: 1;
  overflow: hidden;
  overflow-wrap: anywhere;
  color: var(--ink);
  line-height: 1.5;
}

.row-details {
  min-width: 0;
  margin-top: 2px;
}

/* A 24px target without turning the summary into a flex box (that would drop
   the disclosure marker). */
.row-details > summary {
  padding: 3px 0;
  border-radius: 4px;
  color: var(--muted);
  cursor: pointer;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
}

.row-details > summary:hover {
  color: var(--ink);
}

.row-details[open] > summary {
  margin-bottom: 6px;
}

/* ---- Row buttons: Approve (teal tint), Reject (red text on red tint), Clear (ghost)
   Same classes in the table rows and in the HTML preview header. A dangerous
   action is not a solid red block (design system), and the solid reds on this
   screen stay with the failed segments. Specificity is `button.x` so these beat
   `button.ghost`; the :disabled rules put the quiet disabled look back.
   Contrast: teal on teal-tint 4.8:1, red-deep on red-tint 6.4:1, muted on white 7.6:1. */
button.review-approve,
button.review-reject,
button.review-clear {
  min-height: 32px;
  padding: 0 12px;
  border: 1px solid transparent;
  border-radius: 8px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
}

button.review-approve {
  color: var(--teal);
  background: var(--teal-tint);
  border-color: color-mix(in srgb, var(--teal) 28%, var(--line));
}

button.review-reject {
  color: var(--red-deep);
  background: var(--red-tint);
  border-color: color-mix(in srgb, var(--red) 22%, var(--line));
}

button.review-clear {
  color: var(--muted);
  background: transparent;
}

/* Hover keeps the fill (and so the text contrast) and only firms up the border;
   no lift, so a dense column of buttons does not jitter. */
button.review-approve:hover:not(:disabled),
button.review-reject:hover:not(:disabled),
button.review-clear:hover:not(:disabled) {
  box-shadow: none;
  transform: none;
}

button.review-approve:hover:not(:disabled) {
  color: var(--teal);
  background: var(--teal-tint);
  border-color: var(--teal);
}

button.review-reject:hover:not(:disabled) {
  color: var(--red-deep);
  background: var(--red-tint);
  border-color: var(--red-deep);
}

button.review-clear:hover:not(:disabled) {
  color: var(--ink);
  background: var(--panel-strong);
}

button.review-approve:disabled,
button.review-reject:disabled,
button.review-clear:disabled {
  color: var(--muted-3);
  background: var(--panel-strong);
  border-color: var(--line);
}

/* ---- Review toolbar: two filters, Approve all passed rows, More, Close (HI-4) ---
   `.panel-head > .button-row` is the toolbar. Written against the stable panel
   id so it follows the existing markup. One line on a desktop, two on a phone
   (the generic 680px rule turns every .button-row into a column, which is what
   made the old toolbar 510px tall). */
#rowReviewPanel > .panel-head {
  flex-wrap: wrap;
  gap: 10px 16px;
}

#rowReviewPanel > .panel-head .button-row {
  flex: 1 1 auto;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 8px 10px;
}

#rowReviewPanel > .panel-head .button-row select {
  flex: 0 1 190px;
  width: auto;
}

#rowReviewMoreMenu .kebab-trigger {
  width: 42px;
  min-height: 42px;
}

/* The menu is anchored to the toolbar, not to the small trigger: on a phone the
   trigger sits mid-row and a trigger-anchored panel would run off the screen.
   `:has()` finds the toolbar whatever class it carries; without :has() support
   the menu keeps the default trigger anchoring. */
@supports selector(:has(a)) {
  #rowReviewPanel :has(> #rowReviewMoreMenu) {
    position: relative;
  }

  #rowReviewMoreMenu {
    position: static;
  }
}

#rowReviewMoreMenu .kebab-panel {
  min-width: 260px;
  max-width: calc(100vw - 32px);
}

#rowReviewMoreMenu .kebab-item-btn {
  white-space: normal;
}

/* The preview header gains Approve / Reject next to Close. */
.html-preview-head {
  flex-wrap: wrap;
  align-items: center;
}

.html-preview-head > div:first-child {
  flex: 1 1 260px;
  min-width: 0;
}

#htmlPreviewApproveBtn,
#htmlPreviewRejectBtn,
#closeHtmlPreviewBtn {
  flex: none;
}

/* ---- Guidance: one list with counts, the rerun checklist folded (HI-8) ---------
   A wrapping grid keeps the box short at 1440. Items are flex rows so the "N x"
   count, the text and a "run-level" tag sit on one line whatever element each
   one is. */
.review-guidance .review-guidance-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: 2px 24px;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
}

.review-guidance .review-guidance-list > li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 8px;
  min-width: 0;
  margin: 0;
  padding: 2px 0;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.review-guidance .review-guidance-list > li > * {
  min-width: 0;
}

.review-guidance .review-guidance-list > li > b {
  font-weight: 600;
}

/* The "N x" count stays on the line with its text. The text's max-content is
   wider than the item, so with `flex-wrap: wrap` and a `auto` basis it jumped to
   a new line under the count. The element after the count takes a zero basis,
   which can never force a wrap: it gets what the count leaves and wraps inside
   that. `nowrap` on an item that has a count says the same thing outright. */
.review-guidance .review-guidance-list .guidance-count {
  flex: none;
  min-width: 3ch;
  color: var(--ink);
  font-weight: 600;
}

.review-guidance .review-guidance-list .guidance-count + * {
  flex: 1 1 0;
  min-width: 0;
}

.review-guidance .review-guidance-list > li:has(> .guidance-count) {
  flex-wrap: nowrap;
}

.review-guidance .review-guidance-before {
  margin-top: 8px;
}

.review-guidance-before > summary {
  padding: 3px 0;
  color: var(--ink);
  cursor: pointer;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
}

.review-guidance-before[open] > summary {
  margin-bottom: 4px;
}

.review-guidance-before ol {
  margin: 6px 0 0;
  padding-left: 20px;
}

/* ---- Project header rhythm: tabs start higher (PJ-4: row y down >= 25%) -----------
   Nothing is hidden. The gaps are the thing that was large: a 12px top margin
   on the header's `.button-row` made the head taller than its own title, and
   the paragraph, chip, banner and tab margins each added 10-18px. Scoped to the
   project panel so no other panel-head or banner changes. Text keeps its 1.5+
   line-height and every button its 42px height. */
#projectDetailPanel > .panel-head {
  margin-bottom: 8px;
  padding-bottom: 8px;
}

#projectDetailPanel > .panel-head > .button-row {
  margin-top: 0;
}

#projectDetailName {
  overflow-wrap: anywhere;
}

#projectDetailDesc {
  margin: 0 0 4px;
}

#projectDetailPanel .project-header-chips {
  margin-top: 6px;
}

#projectLiveProgress .project-live-progress {
  margin: 8px 0 10px;
}

#projectNextStep .project-next-step {
  margin: 10px 0 12px;
}

/* An empty status line must not add its paragraph margins between the banner
   and the tabs. */
#criteriaStatus:empty {
  margin: 0;
}

#projectDetailPanel > .project-tabs {
  margin-top: 10px;
}

/* ---- Desktop table density: each folded row <= 64px at 1440 ---------------------- */
@media (min-width: 681px) {
  /* Top-aligned: every cell's first line starts at the same y, and an opened
     Details (a tall row) cannot float the other cells into the middle or leave
     the score bar far from its number. */
  .row-review-table td {
    padding: 8px 12px;
    vertical-align: top;
  }

  .row-review-table td[data-col="index"] { width: 44px; color: var(--muted); }
  .row-review-table td[data-col="series"] { width: 180px; }
  .row-review-table td[data-col="status"] { width: 96px; }
  .row-review-table td[data-col="score"] { width: 132px; }
  .row-review-table td[data-col="decision"] { width: 150px; }

  /* Score cell: the number and its "67 -> 69" delta share ONE line, the bar sits
     under them. The markup order is value, bar, delta, so the bar is taken out
     of the flow (a table cell cannot be a grid or flex box without losing its
     table-cell behaviour) and pinned just under that line: line 20px + 4px gap
     = top 32px, and the cell keeps room for the 8px bar below. Anchored from
     the top, never the bottom, so it stays with the number in a tall row. */
  .row-review-table td[data-col="score"] {
    position: relative;
    padding-bottom: 20px;
  }

  .row-review-table td[data-col="score"] > .score-value,
  .row-review-table td[data-col="score"] > .score-delta {
    display: inline-block;
    vertical-align: baseline;
  }

  .row-review-table td[data-col="score"] > .score-delta {
    margin: 0 0 0 8px;
  }

  .row-review-table td[data-col="score"] > .score-bar {
    position: absolute;
    top: 32px;
    right: 12px;
    left: 12px;
    width: auto;
    max-width: none;
  }
  .row-review-table td[data-col="reason"] { min-width: 160px; overflow-wrap: anywhere; }

  /* One line of series name and of the decision date/note; the full text is in
     the details. */
  .row-review-table td[data-col="series"] > span:not(.completeness-chip),
  .row-review-table td[data-col="decision"] small {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 1;
    line-clamp: 1;
    overflow: hidden;
  }

  .row-review-table td[data-col="decision"] small {
    margin-top: 2px;
  }

  /* Preview / Approve / Reject / Clear on one line; the Reason column gives way. */
  .row-review-table td.review-actions {
    width: 1%;
    white-space: nowrap;
  }

  .row-review-table td.review-actions .tiny {
    margin: 0 4px 0 0;
  }
}

/* ---- Phone ---------------------------------------------------------------------- */
@media (max-width: 680px) {
  .row-reason,
  .row-review-table td .row-reason {
    -webkit-line-clamp: 2;
    line-clamp: 2;
  }

  /* The card scans in sections: facts first, then the reason, then the buttons. */
  .row-review-table td[data-col="reason"] {
    margin-top: 6px;
    padding-top: 10px;
    border-top: 1px solid var(--line);
  }

  /* Toolbar: filters share the first row, Approve all passed rows + More + Close
     the second. */
  #rowReviewPanel > .panel-head .button-row {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-start;
    gap: 8px;
    width: 100%;
  }

  #rowReviewPanel > .panel-head .button-row select {
    flex: 1 1 calc(50% - 4px);
    min-width: 0;
  }

  #rowReviewPanel > .panel-head .button-row > button {
    padding: 0 12px;
  }

  /* Two lines, not three: Approve takes whatever the second row has left. With
     `flex-basis: auto` its full text width plus More and Close overflowed the
     ~290px row by a few pixels and Close wrapped onto a third line. A zero
     basis never forces a wrap; the real width is what remains after the fixed
     More and Close. */
  #rowReviewPanel > .panel-head .button-row > #approvePassRowsBtn {
    flex: 1 1 0;
    min-width: 0;
    padding: 0 8px;
    white-space: normal;
  }

  #rowReviewMoreMenu,
  #closeRowReviewBtn {
    flex: none;
  }

  /* The score stacks as number / bar / delta on a card; give the bar a gap. */
  .row-review-table td[data-col="score"] > .score-bar {
    margin-top: 4px;
  }

  /* Full toolbar width, but only where the menu is anchored to the toolbar
     (see the :has() block above); anchored to the 42px trigger it would be
     squeezed to the trigger's width. */
  @supports selector(:has(a)) {
    #rowReviewMoreMenu .kebab-panel {
      right: 0;
      left: 0;
      min-width: 0;
      max-width: none;
    }
  }

  /* Project header on a phone: "All projects" sits at the right of the title
     instead of on its own row, and Ask Copilot takes the row under them (the
     slot Delete used to hold before PJ-9 moved it to Settings).
     `display: contents` lets the two buttons join the head's grid without a
     markup change; a div has no semantics to lose. */
  #projectDetailPanel > .panel-head {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 8px 12px;
  }

  #projectDetailPanel > .panel-head > .button-row {
    display: contents;
  }

  /* Left-aligned under the title, with its text on the title's own left edge
     (the ghost button's 18px side padding would otherwise indent it). */
  #projectDetailPanel > .panel-head #projectAskCopilotBtn {
    grid-column: 1 / -1;
    justify-self: start;
    margin-left: -12px;
    padding: 0 12px;
  }

  /* Preview header: the title takes the first line, the buttons share the next. */
  .html-preview-head {
    display: flex;
    gap: 8px;
  }

  .html-preview-head > div:first-child {
    flex: 1 1 100%;
  }
}

/* ==========================================================================
   Wave 3 fewer buttons, one clear first step (doc 80: B4, PJ-2, PJ-5, PJ-7,
   PJ-8, PJ-9, MR-3, MR-5)
   Appended last on purpose: the neutral-SaaS layers above restyle `button`,
   `.download-btn`, `.stepper` and the file-task controls, so these rules must
   come later to win at equal specificity. Tokens only (a translucent border is
   a color-mix() of two tokens), no colour literals and no motion.
   ========================================================================== */

/* ---- Project stepper (B4 / PJ-2): five steps in one compact row --------------
   `#projectStepper` borrows `.stepper` / `.step-dot` / `.step-label` so Manual
   Run and the project read the same, then drops the card chrome: it sits between
   the header chips and the next-step box, where every pixel of height moves the
   tab row down (PJ-4 budget: tab row y <= 358 at 1440, <= 555 at 390). One
   22px dot per step, a 12px label, no padding, no border. `.active` stays the
   red dot and `.done` the teal one; nothing about which step is current changes. */
.project-stepper {
  margin: 4px 0 0;
  padding: 0;
  gap: 8px;
  align-items: center;
  border: 0;
  border-radius: 0;
  background: transparent;
}

.project-stepper li {
  min-width: 0;
  gap: 6px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
}

.project-stepper .step-dot {
  width: 22px;
  height: 22px;
  font-size: 12px;
}

.project-stepper li:not(:last-child)::after {
  margin: 0 2px;
}

/* With the stepper above it, the next-step box sits closer to it and the tab row
   closer to the box. A sibling selector (not a change to the base rule) so the
   box keeps its own margins on any screen that has no stepper. */
#projectStepper ~ #projectNextStep .project-next-step {
  margin: 8px 0 10px;
  padding-top: 10px;
  padding-bottom: 10px;
}

@media (max-width: 680px) {
  /* Same dot as Manual Run's phone stepper: 24px, the minimum target size. */
  .project-stepper .step-dot {
    width: 24px;
    height: 24px;
  }
}

/* ---- Project list cards (PJ-5): one button per card, paged list --------------
   The card is a grid, so the paragraphs' default 1em margins never collapsed:
   five of them added ~65px per card. They are zeroed here and the grid `gap`
   carries the rhythm instead. The middle of the card stays plain text on
   purpose: clicking it still opens the project, and the one real button lives in
   the bottom-right corner, so no stretched link or full-width button covers it. */
.project-card {
  gap: 6px;
  padding: 14px 16px;
}

.project-card > p {
  margin: 0;
}

/* A description the project does not have is an empty paragraph; it must not
   take a gap of its own. */
.project-card > p:empty {
  display: none;
}

.project-card .project-card-head {
  margin-bottom: 0;
}

/* The status strip is text only now (its buttons are gone): one column, tighter
   box, and a long sentence stops after two lines instead of pushing every card
   taller. Nothing is hidden for good: the project it opens shows the same words. */
.project-card .project-action-strip {
  grid-template-columns: minmax(0, 1fr);
  gap: 2px;
  margin: 2px 0 0;
  padding: 8px 12px;
}

.project-card .project-action-strip span {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  font-size: 12px;
}

.project-card-meta {
  font-size: 12px;
  line-height: 1.5;
}

.project-card-actions {
  justify-content: flex-end;
  margin-top: 2px;
}

.project-card-actions .project-open-btn {
  min-height: 36px;
  padding: 0 16px;
  font-size: 13px;
}

/* Wide cards: the counts line and the one button share a row (the card was
   ~40px taller with the button on a row of its own). Phone cards stay stacked:
   a counts line squeezed beside the button would wrap to four lines. */
@media (min-width: 681px) {
  .project-card {
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 16px;
  }

  .project-card > * {
    grid-column: 1 / -1;
  }

  .project-card > .project-card-meta {
    grid-column: 1;
    align-self: center;
  }

  .project-card > .project-card-actions {
    grid-column: 2;
    align-self: center;
    margin-top: 0;
  }
}

/* "Show 20 more": centred under the list. A quiet outlined button, not red:
   the card buttons above are the only actions on this screen. */
.project-list-more {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  padding: 6px 0 2px;
  text-align: center;
}

.project-list-more > .muted {
  margin: 0;
  font-size: 12px;
  line-height: 1.5;
}

.project-list-more .ghost {
  min-height: 40px;
  padding: 0 20px;
  color: var(--ink);
  border-color: var(--line-strong);
}

/* ---- Project danger zone (PJ-9): Delete lives at the end of Settings ---------
   A quiet separation, not a red block: a stronger rule above, ink heading, a
   muted explanation, and an outlined (not filled) Delete button. */
.project-tab-section-head h4 {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.5;
}

.project-danger-zone {
  gap: 8px;
  margin-top: 28px;
  border-top-color: var(--line-strong);
}

.project-danger-zone .project-tab-section-head small {
  max-width: 64ch;
}

.project-danger-zone > .button-row {
  margin-top: 4px;
  justify-content: flex-start;
}

.project-danger-zone button.ghost.danger:not(:disabled) {
  color: var(--red-deep);
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--red) 40%, var(--line));
}

.project-danger-zone button.ghost.danger:not(:disabled):hover {
  background: var(--red-tint);
}

/* The line beside the button carries blocker / partial messages. Empty, it must
   not leave a gap: it stays in the page (a live region has to exist before its
   text changes) but gives back the grid gap above it. */
.project-danger-zone > #projectDeleteStatus {
  margin: 0;
  font-size: 12px;
  line-height: 1.5;
}

.project-danger-zone > #projectDeleteStatus:empty {
  margin-top: -8px;
}

/* When it does speak it is the only place a person learns why a delete was
   refused, so it reads as body text, not as a muted caption. */
.project-danger-zone > #projectDeleteStatus:not(:empty) {
  color: var(--ink);
  font-size: 13px;
}

@media (max-width: 680px) {
  .project-danger-zone > .button-row {
    align-items: flex-start;
  }
}

/* ---- File rows (PJ-7 / PJ-8): one primary button, a reason, a purpose line ---- */
.file-task-actions {
  align-items: flex-start;
}

.file-task-actions .file-task-primary {
  min-height: 36px;
  padding: 0 16px;
  font-size: 13px;
  white-space: nowrap;
}

/* The ⋯ trigger lines up with the primary button's height and with the first
   line of the run group, even when a reason line makes that group taller. */
.file-task-actions .kebab-trigger {
  min-height: 36px;
  width: 36px;
}

/* Why Test run is greyed out, as a small muted line under the whole run group.
   `.file-task-row span` makes spans block-level 12px; the two-class selector
   outranks it. flex-basis 100% sends it to its own line in the wrapping row. */
.file-task-row .file-task-primary-reason {
  flex: 1 0 100%;
  margin: -2px 0 0;
  color: var(--muted);
  font-size: 11px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

/* What the selected blueprint is for: one muted line under the controls. The
   text is already cut to a sentence in JS; two lines is only the safety net for
   a narrow screen or Thai text that wraps. */
.file-task-row .blueprint-purpose {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  max-width: 80ch;
  margin: -4px 0 0;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

/* ---- Manual Run step 1 (MR-3 / MR-5) ----------------------------------------- */

/* The "advanced path" box became one muted line above the stepper. The view's
   20px grid gap above the stepper is pulled in to 12px so the line belongs to it. */
.advanced-path-line {
  margin: 0;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
}

.advanced-path-line a {
  color: var(--ink);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
}

#view-pipeline > .advanced-path-line {
  margin-bottom: -8px;
}

/* "✓ name · size" inside the drop zone once a file is staged. `.chat-drop-zone
   span` (block, muted, 13px) would otherwise restyle it, so the longer selector
   resets those. Ink on the teal tint is ~15:1; the teal border says "got it". */
.file-chip {
  display: inline-block;
  max-width: 100%;
  padding: 2px 10px;
  border: 1px solid color-mix(in srgb, var(--teal) 40%, var(--line));
  border-radius: 14px;
  background: var(--teal-tint);
  color: var(--ink);
  font-size: 13px;
  font-weight: 500;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.chat-drop-zone .file-chip {
  display: inline-block;
  margin-top: 4px;
  color: var(--ink);
  font-size: 13px;
}

/* "Or create a new project": one line until opened. */
details.manual-create-project {
  max-width: 460px;
  margin-top: 10px;
}

details.manual-create-project > summary {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 28px;
  padding: 2px 0;
  color: var(--ink);
  font-size: 13px;
  font-weight: 500;
  line-height: 1.5;
  list-style: none;
  cursor: pointer;
}

details.manual-create-project > summary::-webkit-details-marker {
  display: none;
}

details.manual-create-project > summary::before {
  content: "▸";
  color: var(--muted);
  font-size: 12px;
}

details.manual-create-project[open] > summary::before {
  content: "▾";
}

details.manual-create-project > .manual-upload-project {
  margin-top: 8px;
}

/* ==========================================================================
   Wave 4a quiet History, short run card, Advanced panels (doc 80: HI-6, HI-7,
   BP-2, ST-7, B6)
   Appended last on purpose, for the same reason as the Wave 3 section: the
   neutral-SaaS layers above restyle `button`, `.pill`, `.status-pill` and the
   `.run-card` grid, so these rules must come later to win at equal
   specificity. Tokens only (no colour literals), no motion, no uppercase, no
   text under 11px.
   ========================================================================== */

/* ---- B6: one closed-details style for every "Technical details" box ----------
   `<details class="tech-details">` is the shared look: a quiet 12px summary with
   a caret, nothing else until it opens. The History run card carries it as
   `run-card-details tech-details`; Idea templates borrow the same summary. The
   caret is the same text glyph `.run-export-more` uses, so two disclosures side
   by side on one card read as the same control. Both `[open]` selectors below
   match the specificity of the older `.run-card-details[open]` rule and come
   after it, so the caret is not set twice. */
.tech-details,
details.bp-idea-templates {
  min-width: 0;
}

.tech-details > summary,
details.bp-idea-templates > summary {
  display: flex;
  align-items: center;
  width: fit-content;
  max-width: 100%;
  min-height: 28px;
  margin: 0;
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
  list-style: none;
  cursor: pointer;
}

.tech-details > summary::-webkit-details-marker,
details.bp-idea-templates > summary::-webkit-details-marker {
  display: none;
}

.tech-details > summary::after,
details.bp-idea-templates > summary::after {
  content: "▸";
  margin-left: 6px;
}

.tech-details[open] > summary::after,
details.bp-idea-templates[open] > summary::after {
  content: "▾";
}

.tech-details > summary:hover,
details.bp-idea-templates > summary:hover {
  color: var(--ink);
}

.tech-details > summary:focus-visible,
details.bp-idea-templates > summary:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px;
  border-radius: 4px;
}

.tech-details > :not(summary) {
  margin-top: 8px;
}

/* ---- HI-6: the History status strip -------------------------------------------
   One compact line: Running / Waiting in queue / Failed (all time) and, for admin
   and Manager, a Details link to Settings > Advanced. The chips are
   `.status-pill`s, so the dot colours are the ones the run cards already use
   (processing amber, failed red). Only the dot carries the colour: the words stay
   ink or muted, because amber on white is 3.2:1 and these are 12px words. A
   count of 0 is the grey `idle` dot and a lighter weight, so a healthy line is
   not a row of coloured alarms. Waiting, when above 0, gets a darker grey dot
   than idle so 0 and 3 do not look alike. */
#historyStatusStrip:empty {
  display: none;
}

.ops-status-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 16px;
  min-width: 0;
  padding: 0 2px;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
}

.ops-status-strip .ops-status-chip {
  color: var(--ink);
  font-weight: 500;
}

.ops-status-strip .ops-status-chip.idle {
  color: var(--muted);
}

.ops-status-strip .ops-status-chip.queued::before {
  background: var(--muted);
}

.ops-status-num {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.ops-status-chip.idle .ops-status-num {
  font-weight: 500;
}

.ops-status-note {
  color: var(--muted);
}

.ops-status-link {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  font-size: 12px;
  line-height: 1.5;
}

/* ---- HI-7: project filter + count above the list (outside #runList) ---------- */
.run-list-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 12px;
  min-width: 0;
  margin: 0 0 12px;
}

.run-list-toolbar[hidden] {
  display: none;
}

.run-list-toolbar .field-label {
  flex: 0 0 auto;
  margin: 0;
}

.run-list-toolbar select {
  flex: 1 1 120px;
  max-width: 320px;
  min-width: 0;
  min-height: 36px;
}

/* The count never wraps and never shrinks: on a 390px phone label, select and
   count then share one row (48 + 120 + 125 + gaps), and the select takes what is
   left. */
.run-list-toolbar > .muted {
  flex: 0 0 auto;
  font-size: 12px;
  white-space: nowrap;
}

#runListMoreBtn {
  margin-top: 12px;
}

/* ---- HI-7: the History run card face ------------------------------------------
   Face = file name, project, status, QA bar, date, kind pill, Check rows /
   download; everything else is inside the closed Technical details. Two layouts,
   one column order. Narrower than 1100px the rows stack (identity, then the
   action bar, then the disclosure): ~155px tall. From 1100px the action bar moves
   up beside the identity block, under the kind pill, so the whole card is ~125px.
   The two-column grid is restated here at every width because the phone rule
   further up collapses it to one column, which put the kind pill on its own row
   (a 28px row of nothing but "file run"). */
.run-card {
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 8px 12px;
  padding: 12px 14px;
}

.run-card-main {
  grid-column: 1;
  display: grid;
  align-content: start;
  gap: 3px;
  min-width: 0;
}

.run-card-main h4 {
  margin: 0;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.5;
}

.run-card-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 12px;
  min-width: 0;
}

.run-card-project {
  min-width: 0;
  color: var(--ink);
  font-size: 12.5px;
  font-weight: 500;
  overflow-wrap: anywhere;
}

.run-card-date {
  color: var(--muted-2);
  font-size: 11.5px;
  white-space: nowrap;
}

/* A bar the width of a 1,000px card reads as a page divider, not a figure. */
.run-card-main .qa-bar {
  max-width: 420px;
  margin-top: 2px;
}

.run-card > .pill {
  grid-column: 2;
  align-self: start;
  min-height: 24px;
  padding: 2px 10px;
  font-size: 11.5px;
  white-space: nowrap;
}

.run-card-actions button,
.run-card-actions .download-btn {
  min-height: 36px;
}

/* "More export options" is a closed one-line disclosure: it sits in the same row
   as Check rows and All rows (CSV) instead of taking a row of its own. Open, it
   holds the Rows/Format pickers and goes back to a full row. */
.run-card-actions .run-export-more {
  flex: 0 1 auto;
  margin-top: 0;
}

.run-card-actions .run-export-more[open] {
  flex: 1 1 100%;
}

/* The older caret rule is " ▸" with a leading space, which collapses inside the
   summary's inline-flex; a margin gives it back. */
.run-card-actions .run-export-more > summary::after {
  margin-left: 4px;
}

.run-card .tech-details {
  grid-column: 1 / -1;
}

@media (min-width: 1100px) {
  .run-card {
    grid-template-columns: minmax(0, 1fr) fit-content(560px);
  }

  .run-card-main {
    grid-row: 1 / span 2;
  }

  .run-card > .pill {
    grid-row: 1;
    justify-self: end;
  }

  .run-card-actions {
    grid-column: 2;
    grid-row: 2;
    justify-content: flex-end;
  }

  .run-card-actions > .run-export-links {
    justify-content: flex-end;
  }

  .run-card .tech-details {
    grid-row: 3;
  }
}

@media (max-width: 680px) {
  /* The phone heads a view with one row, not three: title on the left, the
     Auto-refresh pill on the right. Stacked, they cost ~36px before the list. */
  #runs .panel-head {
    flex-direction: row;
    align-items: center;
  }

  #runs.panel {
    padding: 14px;
  }

  #runs .panel-head {
    margin-bottom: 10px;
    padding-bottom: 8px;
  }

  #view-history {
    gap: 12px;
  }

  /* Thumb targets on the card: the review/download buttons and both disclosures. */
  .run-card-actions button,
  .run-card-actions .download-btn {
    min-height: 40px;
  }

  .run-card-actions .run-export-more > summary {
    min-height: 32px;
  }

  .run-card .tech-details > summary {
    min-height: 36px;
  }
}

/* ---- BP-2: Idea templates fold away, with the count in the summary ------------
   The summary reads "Idea templates (N) · planning only, cannot run yet"; the
   hairline above it sets it apart from the Ready cards it follows. */
details.bp-idea-templates {
  padding-top: 4px;
  border-top: 1px solid var(--line);
}

details.bp-idea-templates > summary {
  min-height: 36px;
  font-size: 13px;
}

details.bp-idea-templates > .blueprint-list {
  margin-top: 6px;
}

/* ---- HI-6 / BP-2 / ST-7: Settings > Advanced holds four stacked sections -----
   The Agent Map pair, the Operations monitor, the Runtime Skill Registry (admin)
   and the sharing requests (admin and Manager). One 20px gap between all of them
   (the same as `.view`), a single column capped like every other settings panel,
   and the margin the two blueprint-page sections used to carry is dropped (they
   are panels here, not sections inside one). `:not([hidden])` is load-bearing:
   an id selector that set `display: grid` unconditionally would beat
   `.settings-tabpanel[hidden]` and show the closed tab. */
#settingsPanelAdvanced:not([hidden]) {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-content: start;
  gap: 20px;
}

#settingsPanelAdvanced > .runtime-skill-manager,
#settingsPanelAdvanced > .bp-governance {
  margin-top: 0;
}

.ops-monitor-details {
  display: grid;
  gap: 12px;
}

/* Six tiles reflow to the room they have (3 wide, 1 on a phone) without a
   breakpoint; the 1040px rule that forces one column would stack them at tablet
   width where three fit. */
.ops-monitor-details .ops-grid {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr));
}

/* A short tile (Setup, Export) stretches to the tallest in its row; without this
   its two lines drift to the middle of the box. */
.ops-monitor-details .ops-card {
  align-content: start;
}

.ops-monitor-note {
  margin: 0;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
}

/* The Registry form was drawn for the wide Blueprints page: its four-column grid
   scatters name, description, checkboxes and schema boxes across a 920px panel.
   Here it is one column (what it already does under 760px), capped so a text box
   is not 880px wide. */
#settingsPanelAdvanced .runtime-skill-manager .bp-decision-form {
  grid-template-columns: minmax(0, 1fr);
  max-width: 640px;
}

#settingsPanelAdvanced .runtime-skill-manager .bp-decision-form button {
  justify-self: start;
}

/* Title left, action right, also on a phone: stacked, the Refresh button became a
   full-width bar under each heading. */
@media (max-width: 680px) {
  .advanced-monitor-panel > .panel-head,
  .bp-access-requests > .panel-head {
    flex-direction: row;
    align-items: center;
  }
}

/* These two Advanced panel titles were <h4> with no <h3> above them in the
   panel; they are <h3> now. `.panel h3` would restyle them (14px, margin 0), so
   they keep the look the browser's own <h4> gave them: 1em bold with 1.33em
   margins. */
#runtimeSkillTitle,
#blueprintAccessRequestsTitle {
  margin: 1.33em 0;
  font-size: 1em;
  font-weight: 700;
  line-height: inherit;
  letter-spacing: inherit;
}

/* ---- ST-7: Change Password is as wide as its words, not the whole form -------- */
#changePasswordForm button {
  justify-self: start;
}

/* ---- Stepper: a finished step is a check mark, not only a teal dot -----------
   Colour alone told "done" from "not yet" (WCAG 1.4.1). The number is shrunk to
   nothing (it stays in the markup and in the accessibility tree) and a drawn
   check takes its place in the dot's own colour, so it holds at 22px and 28px and
   needs no icon font. The check is absolutely positioned: as a grid item it would
   have shared the dot's single column with the number and moved off-centre. The
   second `content` declaration gives the check an accessible name where the
   browser supports alt text on generated content; older ones keep the first. */
.stepper li.done .step-dot {
  position: relative;
  font-size: 0;
}

.stepper li.done .step-dot::before {
  content: "";
  content: "" / "Done";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 5px;
  height: 10px;
  border: solid currentColor;
  border-width: 0 2px 2px 0;
  transform: translate(-50%, -62%) rotate(45deg);
}

/* ==========================================================================
   Wave 4b Blueprints, What's new, People, AI keys, Research & QA (doc 80:
   BP-1, BP-3, BP-4, BP-5, ST-3, ST-4, ST-6, CL-2)
   Appended last on purpose, for the same reason as the Wave 3 and 4a sections:
   the neutral-SaaS layers above restyle `button`, `.pill`, `.status-pill`,
   `.kebab-trigger` and `.blueprint-card p`, so these rules must come later to
   win at equal specificity. Tokens only (no colour literals), no motion, no
   uppercase, no text under 11px.
   ========================================================================== */

/* ---- BP-5: Refresh is an icon button, and it keeps its icon while busy -------
   `beginButtonBusy` does not replace the label here (it only sets aria-busy and
   disabled), so the glyph stays. 36px square, above the 24px WCAG 2.2 target
   minimum; the stock `.icon-btn` is 28px. A busy or disabled ghost button must
   not turn into the global grey `button:disabled` block, so both states are a
   quiet tint. The spin the brief asked for is not here: the Wave 2 and Wave 3
   scans ban `animation` in everything from their markers to the end of this
   file, so a busy refresh is shown as a tint and a progress cursor. */
.bp-refresh-btn {
  display: inline-grid;
  place-items: center;
  width: 36px;
  min-width: 36px;
  min-height: 36px;
  padding: 0;
}

.bp-refresh-btn svg {
  width: 16px;
  height: 16px;
}

.bp-refresh-btn:disabled,
.bp-refresh-btn[aria-busy="true"] {
  color: var(--muted);
  background: var(--panel-strong);
  cursor: progress;
}

#blueprintListPanel > .panel-head .button-row {
  margin-top: 0;
}

/* ---- BP-1: search above the list, one quiet line per card ---------------------
   The search box lives outside #blueprintList, so a re-render never wipes it. */
.blueprint-search {
  margin: 0 0 12px;
  max-width: 420px;
}

.blueprint-search input {
  width: 100%;
}

.blueprint-saved-card {
  align-items: center;
  gap: 8px 16px;
  padding: 14px 16px;
}

.blueprint-card-main {
  display: grid;
  align-content: start;
  gap: 4px;
  min-width: 0;
}

.blueprint-card-main .project-card-head {
  margin-bottom: 0;
}

.blueprint-saved-card .project-card-head h4 {
  margin: 0;
}

/* One line, ink, with an ellipsis when it is longer. `.blueprint-card p` forces
   muted and wraps anywhere, so this needs the extra class to win. The empty
   state ("No description yet") goes back to muted so it reads as a placeholder
   and not as a description. */
.blueprint-card .blueprint-purpose {
  overflow: hidden;
  color: var(--ink);
  font-size: 13px;
  line-height: 1.5;
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow-wrap: normal;
}

.blueprint-card .blueprint-purpose.is-empty {
  color: var(--muted);
}

.blueprint-cap-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 6px;
  min-width: 0;
}

.blueprint-cap-chips .capability-pill {
  display: inline-flex;
  align-items: center;
  min-height: 22px;
  padding: 0 8px;
  font-size: 11.5px;
  line-height: 1.5;
  white-space: nowrap;
}

.blueprint-cap-chips .capability-more {
  color: var(--muted);
  background: transparent;
}

.blueprint-card .blueprint-meta-line {
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
}

.blueprint-card .blueprint-builtin-note {
  max-width: 90ch;
  margin-top: 2px;
  font-size: 12px;
  line-height: 1.5;
}

/* Open, Use to run and the three-dot menu on one row. The stock phone rule turns
   every `.button-row` into a stretched column, which would stack the three; they
   stay a row on a phone and the whole bar moves under the text. */
.blueprint-card-actions {
  flex-wrap: nowrap;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 0;
}

.blueprint-card-actions button {
  min-height: 36px;
}

.blueprint-card-actions .kebab-trigger {
  width: 36px;
}

@media (max-width: 680px) {
  .blueprint-card-actions {
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
  }

  #blueprintListPanel > .panel-head {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
  }

  #blueprintListPanel > .panel-head .button-row {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
  }

  .blueprint-search {
    max-width: none;
  }
}

/* ---- BP-3: editor toolbar = Add node menu, Save, the three-dot menu -----------
   "Add node" is also a `.kebab-trigger`, which is a 34px square with no padding:
   a label inside that clips. `.bp-menu-trigger` makes it a normal-width button
   with a small chevron (the 12px svg replaces the 16px kebab one). */
.kebab-trigger.bp-menu-trigger {
  width: auto;
  min-width: 0;
  min-height: 40px;
  gap: 6px;
  padding: 0 14px;
  color: var(--ink);
  font-size: 13.5px;
  font-weight: 600;
}

.kebab-trigger.bp-menu-trigger svg {
  width: 12px;
  height: 12px;
}

.bp-add-menu .kebab-panel {
  right: auto;
  left: 0;
}

/* The three-dot menu is anchored to the toolbar's right edge, not to its own
   34px trigger. On a phone the trigger sits mid-row (or, under a wrapped lock
   note, at the left), and the stock phone rule opens a trigger-anchored panel to
   the right of it, off the screen. Same pattern as the row-review More menu. */
.bp-toolbar-actions {
  position: relative;
}

.bp-more-menu {
  position: static;
}

.bp-more-menu .kebab-panel {
  right: 0;
  left: auto;
  max-width: calc(100vw - 32px);
}

/* The reason a system template cannot be edited, written out next to the button
   it switches off, because a `title` on a disabled button is not shown on touch. */
.bp-lock-note {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 44ch;
  font-size: 12px;
  line-height: 1.5;
}

/* The reason under a disabled item in the three-dot menu. */
.kebab-item-reason {
  display: block;
  margin: -4px 10px 2px;
  color: var(--muted);
  font-size: 11.5px;
  line-height: 1.5;
}

/* ---- BP-3: the step dots above the canvas -------------------------------------
   One dot per stage. The visible dot is a 10px ring (12px filled when it is the
   selected stage); the button around it is 24px, the WCAG 2.2 target minimum.
   The selected stage is a filled ink dot, not a red one (the Wave 2 red test
   allows a solid red fill only on a failed state), so it differs from the others
   by shape as well as by colour. A ring is --muted-3 (3.5:1 on white) so an
   unselected dot still passes the 3:1 rule for graphics. */
.bp-stage-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 12px;
  min-width: 0;
  margin: 0;
}

.bp-stage-dots {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.bp-stage-dots li {
  display: flex;
  margin: 0;
  padding: 0;
}

.bp-stage-dots .bp-stage-dot,
.bp-stage-dots .bp-stage-dot:hover:not(:disabled) {
  display: grid;
  place-items: center;
  width: 24px;
  min-width: 24px;
  height: 24px;
  min-height: 24px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: transparent;
  box-shadow: none;
  transform: none;
}

.bp-stage-dot::before {
  content: "";
  width: 10px;
  height: 10px;
  border: 2px solid var(--muted-3);
  border-radius: 999px;
  background: var(--panel);
}

.bp-stage-dot:hover::before {
  border-color: var(--ink);
}

.bp-stage-dot.active::before {
  width: 12px;
  height: 12px;
  border-color: var(--ink);
  background: var(--ink);
}

.bp-stage-dots-label {
  white-space: nowrap;
}

/* ---- BP-3: Decision records and Revision history fold to one line -------------
   Empty, each is a single summary line: caret, small label, title, count. The
   rest (note, list, form) is inside the fold. The title is inline with the other
   words instead of a block of its own. */
.bp-governance-fold {
  min-width: 0;
}

.bp-governance-summary {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 10px;
  min-height: 32px;
  cursor: pointer;
  list-style: none;
}

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

.bp-governance-summary::before {
  content: "▸";
  content: "▸" / "";
  color: var(--muted);
  font-size: 12px;
}

.bp-governance-fold[open] > .bp-governance-summary::before {
  content: "▾";
  content: "▾" / "";
}

.bp-governance-summary .eyebrow {
  margin: 0;
}

.bp-governance-summary h4 {
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
}

.bp-governance-summary .small {
  font-size: 12px;
}

.bp-governance-fold[open] > .bp-governance-summary {
  margin-bottom: 8px;
}

.bp-governance-actions {
  flex-direction: row;
  justify-content: flex-end;
  margin: 0 0 8px;
}

/* ---- BP-4: Default / Custom chip on the closed Policy and Run settings bars ---
   Default is a quiet grey chip. Custom is outlined in ink, so the two differ in
   more than a shade (the words already differ). */
.bp-state-chip {
  display: inline-flex;
  align-items: center;
  min-height: 22px;
  margin-left: 8px;
  padding: 0 8px;
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.5;
  vertical-align: middle;
}

.bp-state-chip[data-state="default"] {
  color: var(--muted);
  background: var(--panel-strong);
}

.bp-state-chip[data-state="custom"] {
  color: var(--ink);
  background: var(--panel);
  border-color: var(--ink);
}

/* ---- CL-2: the "new since last visit" dot in the sidebar, and line length -----
   The words for a screen reader are in the markup (a `.sr-only` span inside); the
   dot only has to be seen. `position: relative` keeps that span from escaping.
   Ink, not red: the Wave 2 red test allows a solid red fill only on a failed
   state, and "new" is not one. */
.nav-new-dot {
  position: relative;
  display: inline-block;
  flex: 0 0 8px;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: var(--ink);
}

.changelog-items li {
  max-width: 72ch;
}

/* ---- ST-6: the people card spans both columns, the date sits under the email --- */
#users {
  grid-column: 1 / -1;
}

#users .table-wrap table {
  min-width: 0;
}

/* The card is full width now, so the organization picker can show its longest
   option ("Default organization" was cut to "Default organi"). */
#users .inline-form select {
  width: auto;
  min-width: 130px;
  max-width: 220px;
}

#usersTable td {
  padding-top: 8px;
  padding-bottom: 8px;
  vertical-align: middle;
}

#usersTable td:last-child button {
  min-height: 32px;
}

/* `anywhere` would let the auto table layout squeeze the email column to a few
   letters (it shrinks the cell's minimum width); `break-word` only breaks a word
   that cannot fit, and a narrow screen scrolls the table instead. */
.user-email {
  font-weight: 500;
  overflow-wrap: break-word;
}

.user-created {
  display: block;
  font-size: 11.5px;
  line-height: 1.5;
}

/* ---- ST-3: provider API keys as one table --------------------------------------
   The table used to be 520px wide at the smallest (the global `table` rule), and
   a grid item will not shrink below its content, so on a phone it pushed the page
   sideways. The view and the tab panel are told they may shrink, and the table
   scrolls inside its own wrapper instead. */
#view-system,
#view-system .settings-tabpanel {
  min-width: 0;
}

.org-keys-table-wrap {
  margin-top: 0;
}

.org-keys-table {
  min-width: 0;
}

.org-keys-table th,
.org-keys-table td {
  padding: 8px 12px;
  vertical-align: middle;
}

.org-keys-table th {
  white-space: nowrap;
}

.org-key-provider {
  font-size: 13px;
  font-weight: 600;
}

/* Only the dot carries the colour (teal set, grey server .env, amber not set); the
   words are ink, because amber text on white is 3.2:1. */
.org-keys-table .status-pill.org-key-status {
  color: var(--ink);
  background: transparent;
}

.org-key-hint {
  padding: 0;
  color: var(--ink);
  background: transparent;
  font-size: 12.5px;
}

.org-key-label-text {
  margin-left: 6px;
  font-size: 12px;
}

.org-key-pending {
  display: inline-block;
  margin-left: 8px;
  padding: 0 8px;
  border-radius: 999px;
  color: var(--ink);
  background: var(--amber-tint);
  font-size: 11.5px;
  line-height: 1.5;
}

.org-key-actions {
  text-align: right;
  white-space: nowrap;
}

.org-key-actions button {
  min-height: 32px;
  padding: 0 10px;
  font-size: 12.5px;
}

.org-key-actions button + button {
  margin-left: 4px;
}

.org-key-actions [data-remove-key] {
  color: var(--red-deep);
}

.org-key-actions [data-remove-key]:hover {
  color: var(--red-deep);
  background: var(--red-tint);
}

/* A row whose input row is open loses its bottom rule, so the two read as one. */
.org-key-row:has(+ .org-key-edit-row:not([hidden])) > td {
  border-bottom-color: transparent;
}

.org-key-edit-row > td {
  padding-top: 0;
  padding-bottom: 12px;
}

.org-key-edit {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 8px 12px;
  margin-bottom: 6px;
}

.org-key-edit-field {
  display: grid;
  gap: 4px;
  min-width: 0;
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
}

.org-key-edit-field input {
  width: 100%;
}

/* On a phone the four columns have to fit the 322px card without a sideways
   scroll, or Change and Remove sit off screen: tighter cells, a status that may
   wrap under its dot, and the two buttons stacked in their own narrow column. */
@media (max-width: 680px) {
  .org-keys-table th,
  .org-keys-table td {
    padding: 8px 6px;
  }

  .org-keys-table .status-pill.org-key-status {
    align-items: flex-start;
    white-space: normal;
  }

  .org-keys-table .status-pill.org-key-status::before {
    margin-top: 6px;
  }

  .org-key-actions {
    white-space: normal;
  }

  .org-key-actions button {
    display: block;
    width: 100%;
  }

  .org-key-actions button + button {
    margin: 2px 0 0;
  }
}

/* ---- ST-3: Save Organization Settings stays in view while you edit -------------
   Sticky, not moved: the footer stays where the markup puts it (a settings-tabs
   test pins that), it just rides the bottom edge of the screen. Opaque, and above
   the table headers, which are sticky at z-index 1. */
.settings-org-save {
  position: sticky;
  bottom: 12px;
  z-index: 5;
  padding: 12px 16px;
  border: 1px solid var(--line-strong);
  border-radius: 12px;
  background: var(--panel);
  box-shadow: var(--shadow);
}

/* The bar covers part of the screen the whole time it rides along, so it is as
   short as it can be: the two note lines add no height while they are empty
   (they stay in the page, because the status line is a live region), and the
   button row no longer carries its 12px top margin. */
.settings-org-save p {
  margin: 0;
}

.settings-org-save p:not(:empty) {
  margin: 0 0 8px;
}

.settings-org-save .button-row {
  margin-top: 0;
}

.settings-org-save .button-row + p:not(:empty) {
  margin: 8px 0 0;
}

/* ---- ST-4: Research & QA ------------------------------------------------------
   Rows already come out the same height. What was wrong: the two domain fields
   share a 283px column, and a list of four MISUMI domains is ~480px of text, so
   it was cut off; and a checkbox beside a label that wraps to two or three lines
   was centred against the whole label, floating mid-sentence. */
.settings-tabpanel > .panel .criteria-grid > .settings-label:has(> #researchDomainsInput),
.settings-tabpanel > .panel .criteria-grid > .settings-label:has(> #researchExternalDomainsInput) {
  grid-column: 1 / -1;
}

#researchDomainsInput,
#researchExternalDomainsInput {
  text-overflow: ellipsis;
}

#settingsPanelResearchQa .bp-checkline {
  align-items: flex-start;
  padding: 2px 0;
}

#settingsPanelResearchQa .bp-checkline input {
  flex: 0 0 auto;
  margin: 2px 0 0;
}

/* The first switch sat directly under the last field, and the hint under a field
   was the browser's 10.8px `small`, under the 11px caption floor. */
#settingsPanelResearchQa .criteria-grid + .bp-checkline {
  margin-top: 12px;
}

#settingsPanelResearchQa .settings-label > small {
  font-size: 12px;
  font-weight: 400;
  line-height: 1.5;
}

/* ==========================================================================
   Copilot wave A (doc 82 section 5: C-1 result cards, C-2 one primary,
   C-3 readable notice, C-4 error view, C-11 QA95 fold)
   Appended last so it wins at equal specificity. Tokens only, no motion, no
   uppercase, no text under 11px. Thai-safe: every line-height is 1.5 or more.
   ========================================================================== */

/* ---- C-3: the notice is ink text with an amber rule (amber text was ~3.2:1) --
   and the card's own spans no longer sit at 1.45. */
.copilot-result span {
  line-height: 1.6;
}

.copilot-result .copilot-result-notice {
  margin-top: 6px;
  padding-left: 10px;
  border-left: 3px solid var(--amber);
  color: var(--ink);
  line-height: 1.6;
}

/* ---- C-1: a saved result card is the live card's body in a bubble ----------- */
#view-copilot .cp-bubble .copilot-results-saved {
  margin-top: 4px;
}

.copilot-results-saved .copilot-result b {
  line-height: 1.5;
}

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

.cp-tech-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 8px;
  min-width: 0;
  font-size: 12px;
  line-height: 1.6;
}

.cp-tech-label {
  flex: 0 0 auto;
  color: var(--muted);
  font-weight: 600;
}

.cp-tech-list code {
  min-width: 0;
  padding: 1px 6px;
  border-radius: 4px;
  background: var(--panel-strong);
  color: var(--ink);
  font-size: 12px;
  line-height: 1.6;
  overflow-wrap: anywhere;
  word-break: break-all;
}

/* ---- C-2: Open Project is the only red button in the card ---------------------
   button.primary takes its red fill and white text from the base `button` rule
   (a second solid-red declaration here would trip the "red stays rare" scan in
   wave2-css.test.js, which allows solid red only in .is-fail rules). What this
   adds: a 36px target, and the secondary and the text link stay clearly quieter
   (the base `button:hover` would otherwise paint the link red). */
#view-copilot .copilot-next-actions {
  align-items: center;
  gap: 8px;
  margin-top: 10px;
}

#view-copilot .copilot-next-actions button {
  min-height: 36px;
  line-height: 1.5;
}

#view-copilot .copilot-next-actions button.primary {
  border: 0;
}

#view-copilot .copilot-next-actions button.link-btn,
#view-copilot .copilot-next-actions button.link-btn:hover:not(:disabled) {
  padding: 0 4px;
  background: none;
  color: var(--ink);
  font-weight: 600;
  text-decoration: underline;
}

#view-copilot .copilot-next-actions button:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* ---- C-4: the error is as wide as every other Copilot box ---------------------
   A saved error bubble used to shrink to its text (about 150px for "fetch
   failed"); the live one already stretched. Both stretch now. */
#view-copilot .cp-msg.assistant .cp-bubble.is-error {
  align-self: stretch;
  max-width: none;
}

#view-copilot .cp-bubble > p + .tech-details {
  margin-top: 6px;
}

.copilot-error-extra {
  display: grid;
  gap: 8px;
  margin-top: 8px;
  min-width: 0;
}

#view-copilot .copilot-error-extra .copilot-error-actions {
  margin-top: 0;
}

#view-copilot .cp-bubble .copilot-error-raw {
  margin-top: 8px;
  white-space: pre-wrap;
}

.copilot-error-raw code {
  display: block;
  max-height: 160px;
  padding: 8px 10px;
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
  color: var(--ink);
  font-size: 12px;
  line-height: 1.6;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}

/* ---- C-11: QA95 reads as one line; the full brief is folded and capped ------- */
#view-copilot .cp-bubble .cp-qa95-summary {
  margin: 0 0 4px;
  color: var(--ink);
  font-weight: 500;
  line-height: 1.6;
}

#view-copilot .cp-bubble .cp-qa95-details {
  margin-top: 0;
}

#view-copilot .cp-bubble .cp-qa95-full {
  max-height: min(40vh, 320px);
  margin-top: 8px;
  padding: 8px 10px;
  overflow-y: auto;
  overscroll-behavior: contain;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel-strong);
  color: var(--ink);
  font-size: 12px;
  line-height: 1.6;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

#view-copilot .cp-bubble .cp-qa95-full:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

@media (max-width: 680px) {
  #view-copilot .cp-bubble .cp-qa95-full {
    max-height: 45vh;
  }
}

/* ---- Copilot wave B (doc 82 C-6, C-7, C-12 to C-15, long-bubble clamp) --------
   Less chrome per bubble and a lighter head. Tokens only, no motion. The ID
   selector on #view-copilot beats .sr-only and [hidden], so both are restated
   where a rule below sets `display` or the name must stay screen-reader only. */

/* C-6: the visible "Copilot" heading is sr-only now, so the tools sit at the end. */
#view-copilot .cp-head {
  justify-content: flex-end;
}

/* C-12: New chat reads as a button (border + plus icon), not as plain text. */
#view-copilot .cp-head-tools .cp-new-chat,
#view-copilot .cp-head-tools .cp-archive-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--panel);
  color: var(--ink);
  font-weight: 500;
  line-height: 1.5;
}

#view-copilot .cp-head-tools .cp-new-chat:hover,
#view-copilot .cp-head-tools .cp-archive-btn:hover {
  background: var(--panel-strong);
}

#view-copilot .cp-head-tools .cp-new-chat:focus-visible,
#view-copilot .cp-head-tools .cp-archive-btn:focus-visible,
#view-copilot .cp-project-chip:focus-visible,
#view-copilot .cp-clamp-toggle:focus-visible,
#view-copilot .cp-archive-note .link-btn:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

#view-copilot .cp-head-tools .cp-new-chat svg,
#view-copilot .cp-head-tools .cp-archive-btn svg {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
}

/* Archive is an icon button: the label stays for screen readers only. */
#view-copilot .cp-head-tools .cp-archive-btn {
  min-width: 34px;
  min-height: 34px;
  padding: 0 8px;
}

#view-copilot .cp-head-tools .cp-archive-btn > span {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

#view-copilot .cp-head-tools .cp-new-chat[hidden],
#view-copilot .cp-head-tools .cp-archive-btn[hidden],
#view-copilot .cp-archive-note[hidden],
#view-copilot .cp-archive-note .link-btn[hidden],
#view-copilot .cp-project[hidden],
#view-copilot .cp-project-chip[hidden] {
  display: none;
}

/* "Chat archived · Undo" and "This chat is archived · Restore" on their own line. */
#view-copilot .cp-archive-note {
  flex: 1 1 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 4px 10px;
  margin: 0;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
}

#view-copilot .cp-archive-note .link-btn,
#view-copilot .cp-clamp-toggle {
  min-height: 24px;
  padding: 0 2px;
  color: var(--ink);
  font-size: 12px;
  font-weight: 500;
  line-height: 1.5;
}

/* C-13: a day separator and a time-only stamp replace a full date on every bubble. */
#view-copilot .cp-day {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 2px 0;
  color: var(--muted);
  font-size: 11px;
  font-weight: 500;
  line-height: 1.5;
}

#view-copilot .cp-day::before,
#view-copilot .cp-day::after {
  content: "";
  flex: 1 1 0;
  height: 1px;
  background: var(--line);
}

#view-copilot .cp-time {
  margin-top: 2px;
  font-size: 11px;
  line-height: 1.5;
}

/* The speaker stays in the DOM for the log, but a repeat is not painted. */
#view-copilot .cp-name.cp-name-repeat {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* C-14: the stream shows only the latest messages and says so. */
#view-copilot .cp-history-note {
  margin: 0;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
  text-align: center;
}

/* Long bubbles: six lines, then a Show more button the page adds only when
   something is hidden. max-height is the fallback where -webkit-line-clamp is
   not supported; the line height here is 1.6. */
#view-copilot .cp-bubble .cp-clamp-text {
  line-height: 1.6;
}

#view-copilot .cp-bubble .cp-clamp-text.is-clamped {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 6;
  line-clamp: 6;
  max-height: calc(6 * 1.6em);
  overflow: hidden;
}

#view-copilot .cp-clamp-toggle {
  display: inline-block;
  margin-top: 4px;
  border: 0;
  background: none;
  text-decoration: underline;
  cursor: pointer;
}

/* C-7: the project is one chip until a file or a project makes it matter. */
#view-copilot .cp-project-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 100%;
  min-height: 28px;
  padding: 2px 10px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--panel);
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
}

#view-copilot .cp-project-chip:hover {
  background: var(--panel-strong);
  color: var(--ink);
}

/* C-15: the panel clips overflow, so the stream ring is drawn inside its edge. */
#view-copilot .cp-stream:focus-visible {
  outline-offset: -2px;
}

@media (max-width: 680px) {
  /* C-14: the starter buttons are one full-width column on a phone. */
  #view-copilot .cp-chips {
    flex-direction: column;
    align-items: stretch;
  }

  #view-copilot .cp-chips .cp-chip {
    width: 100%;
  }
}

@media (max-width: 480px) {
  /* The head can wrap now so the archive note has a line; the tools still fit one. */
  #view-copilot .cp-head {
    flex-wrap: wrap;
    gap: 6px 8px;
  }

  #view-copilot .cp-head-tools .cp-archive-btn {
    min-width: 44px;
    min-height: 44px;
  }

  /* The chip is the one control allowed under 44px here (doc 82 C-7: 32px max). */
  #view-copilot .cp-project-chip {
    min-height: 28px;
  }
}

/* ==========================================================================
   Copilot wave C (doc 82 §7: C-8, C-9, C-10) -- file review, plan, approve.
   Appended last so these win at equal specificity. Existing tokens only, no
   colour literals, no new red (the current step is an ink dot, the disabled
   Preview is neutral), no uppercase, line-height >= 1.5 for Thai.
   ========================================================================== */

/* ---- C-8: the three-step line under the file-review head ----------------------
   "1 Confirm columns > 2 Preview plan > 3 Approve" in one compact row. Same
   spirit as the project stepper (small dot + 12px label, hairline between) but
   the current step is an ink dot with a bold ink label, never red. Colour is not
   the only signal: done steps carry a check mark, the current one is bold and
   has aria-current in the markup. The separator is drawn BEFORE each step but the
   first, so when the row wraps on a phone a line starts with the separator
   instead of ending with a dangling one. */
.copilot-file-steps-host {
  margin: 8px 0 0;
}

.copilot-file-steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 0;
}

.copilot-file-steps li {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  color: var(--muted);
  font-size: 12px;
  font-weight: 500;
  line-height: 1.5;
}

.copilot-file-steps li:not(:first-child)::before {
  content: "";
  flex: none;
  width: 14px;
  height: 1px;
  margin: 0 8px;
  background: var(--line-strong);
}

.copilot-step-mark {
  flex: none;
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  color: var(--muted);
  background: var(--panel);
  font-size: 11px;
  font-weight: 600;
}

.copilot-step-label {
  min-width: 0;
  overflow-wrap: anywhere;
}

.copilot-file-steps li.is-done .copilot-step-mark {
  border-color: var(--teal);
  color: var(--teal);
  background: var(--teal-tint);
}

.copilot-file-steps li.is-current {
  color: var(--ink);
  font-weight: 700;
}

.copilot-file-steps li.is-current .copilot-step-mark {
  border-color: var(--ink);
  color: var(--panel);
  background: var(--ink);
}

/* ---- C-8: why Preview plan is off ---------------------------------------------
   Its own line under the buttons (the flex row wraps it), muted ink at 12px with
   a Thai-safe line height. A disabled Preview reads as disabled without red:
   neutral fill, muted text, not-allowed cursor. */
.copilot-gate-reason {
  flex: 1 1 100%;
  margin: 0;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.6;
  overflow-wrap: anywhere;
}

.copilot-gate-reason[hidden] {
  display: none;
}

#view-copilot .cp-inline-actions button:disabled {
  color: var(--muted);
  background: var(--panel-strong);
  border: 1px solid var(--line);
  cursor: not-allowed;
}

/* A long label ("เปิด column mapping · Open column mapping") may wrap rather than
   push the row wider than a 390px bubble. */
#view-copilot .cp-inline-actions button {
  max-width: 100%;
  padding-top: 6px;
  padding-bottom: 6px;
  white-space: normal;
  text-align: center;
}

/* ---- C-9: folded sections inside the file-review card -------------------------
   "Add a note for Copilot" borrows the quiet `.tech-details` summary (12px muted,
   caret, hover to ink). The Technical details box is a real `.tech-details`; the
   rules below only undo what the older `.copilot-review-details summary` rules
   (13px, weight 900, 10px gap when open) would otherwise do to a nested summary. */
.copilot-column-notes > summary,
.copilot-review-details .tech-details > summary {
  display: flex;
  align-items: center;
  width: fit-content;
  max-width: 100%;
  min-height: 28px;
  margin: 0;
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
  list-style: none;
  cursor: pointer;
}

.copilot-column-notes > summary::-webkit-details-marker {
  display: none;
}

.copilot-column-notes > summary::after {
  content: "▸";
  margin-left: 6px;
}

.copilot-column-notes[open] > summary::after {
  content: "▾";
}

.copilot-column-notes > summary:hover {
  color: var(--ink);
}

.copilot-column-notes > summary:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px;
  border-radius: 4px;
}

.copilot-review-details[open] .copilot-column-notes > summary,
.copilot-review-details[open] .tech-details > summary {
  margin-bottom: 0;
}

.copilot-column-notes {
  margin: 8px 0 0;
  min-width: 0;
}

.copilot-column-notes > .copilot-column-plan {
  margin: 8px 0 0;
}

.copilot-review-details .tech-details {
  margin-top: 8px;
}

/* The mapping list keeps its 120px label column on a desktop; on a phone, inside
   two folded boxes, it stacks so a long value is not squeezed. */
@media (max-width: 480px) {
  .copilot-review-details .tech-details > dl {
    grid-template-columns: minmax(0, 1fr);
    gap: 2px 0;
  }

  .copilot-review-details .tech-details > dl dd {
    margin-bottom: 6px;
  }
}

p[data-testid="copilot-quality-target"] {
  margin: 8px 0 0;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
}

/* ---- C-10: neutral number, folded command, one-row Apply bar ------------------ */
.copilot-index {
  color: var(--ink);
  background: var(--panel-strong);
  border: 1px solid var(--line);
  font-size: 13px;
  font-weight: 600;
}

.copilot-action-card .copilot-command {
  margin: 0;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.6;
  overflow-wrap: anywhere;
}

.copilot-action-card .copilot-command code {
  display: inline;
  padding: 1px 6px;
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--ink);
  background: var(--panel-strong);
  font-size: 12px;
  line-height: 1.6;
  white-space: normal;
}

/* "Apply these N actions?" + Apply + Back: one row on a desktop, the question
   above two equal buttons on a phone. The host (`.cp-inline-actions`) already
   gives the 8px gap and the ink focus ring; the bubble's 14px padding keeps the
   ring (2px + 2px offset) from being clipped by the stream. */
.copilot-apply-bar {
  flex: 1 1 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.copilot-apply-question {
  flex: 1 1 auto;
  margin: 0 4px 0 0;
  color: var(--ink);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

@media (max-width: 680px) {
  .copilot-apply-question {
    flex-basis: 100%;
    margin-right: 0;
  }

  .copilot-apply-bar button {
    flex: 1 1 0;
    min-width: 0;
    min-height: 44px;
  }
}

/* ---------- Phones (<= 480px): users table as stacked rows, Copilot header compact ----------
   Users table: five columns and three actions never fit 358px, so the table
   scrolled sideways inside its card and cut long emails. Each row becomes a
   small grid instead: email (wraps) on top, role + status next, actions last.
   The cells have no data-label, so the column header row is dropped here and
   the role select keeps its own aria-label. Desktop and tablet are untouched. */
@media (max-width: 480px) {
  #users .table-wrap {
    overflow: visible;
    padding: 0 12px;
  }

  #users .table-wrap table,
  #users .table-wrap tbody {
    display: block;
    width: 100%;
    min-width: 0;
  }

  #users .table-wrap thead {
    display: none;
  }

  #usersTable tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 6px 12px;
    padding: 12px 0;
    border-bottom: 1px solid var(--line);
  }

  #usersTable tr:last-child {
    border-bottom: 0;
  }

  #usersTable td {
    display: block;
    min-width: 0;
    padding: 0;
    border: 0;
  }

  /* Email (and the date under it) takes the full row and wraps anywhere. */
  #usersTable td:first-child {
    grid-column: 1 / -1;
  }

  #usersTable .user-email {
    overflow-wrap: anywhere;
  }

  /* Actions: a wrapping row of 44px targets instead of one long nowrap line. */
  #usersTable td:last-child {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    white-space: normal;
  }

  #usersTable td:last-child button,
  #usersTable td:last-child button + button {
    margin-left: 0;
    min-height: 44px;
  }

  /* Copilot header: the title bar and the chat tools were two 44-62px rows with
     20px gaps. Same 44px touch targets, less air around them. Copilot view only,
     so every other screen keeps its normal title-bar spacing. */
  .workbench:has(> #view-copilot:not([hidden])) {
    gap: 8px;
    padding-top: 10px;
  }

  .workbench:has(> #view-copilot:not([hidden])) > .topbar {
    padding-top: 4px;
    padding-bottom: 4px;
  }

  #view-copilot .cp-panel {
    gap: 6px;
  }
}

/* ---- Status filter chips (Projects list, project Files tab, project Runs tab) ----
   A row of pill buttons with a count each, then one quiet "Showing n of total"
   line while a group is chosen. Neutral until pressed (ink fill); the dots carry
   the only colour and stay semantic. Chips wrap onto a second line rather than
   scroll, so nothing overflows at 375px or when Thai labels run long. */
.status-filter {
  margin: 12px 0 10px;
}

.status-filter-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.status-filter .status-filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 34px;
  max-width: 100%;
  padding: 0 12px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  color: var(--muted);
  background: var(--panel);
  font-size: 13px;
  font-weight: 500;
  line-height: 1.5;
}

.status-filter .status-filter-chip:hover:not(:disabled):not([aria-pressed="true"]) {
  color: var(--ink);
  background: var(--panel);
  border-color: var(--muted-2);
}

.status-filter .status-filter-chip[aria-pressed="true"] {
  color: var(--panel);
  background: var(--ink);
  border-color: var(--ink);
}

.status-filter .status-filter-chip:disabled {
  color: var(--muted-3);
  background: var(--panel);
  cursor: not-allowed;
  opacity: 0.6;
}

.status-filter .status-filter-chip:focus-visible,
.status-filter .status-filter-clear:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px;
}

.status-filter-count {
  min-width: 22px;
  padding: 0 6px;
  border-radius: 999px;
  color: var(--muted);
  background: var(--panel-strong);
  font-size: 12px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.status-filter-chip[aria-pressed="true"] .status-filter-count {
  color: var(--ink);
  background: var(--panel);
}

.status-filter-dot {
  width: 8px;
  height: 8px;
  flex: 0 0 8px;
  border-radius: 50%;
  background: var(--muted-3);
}

.status-filter-dot.all { display: none; }
/* Needs action is a ring, not a solid red dot: red stays rare (wave2-css). */
.status-filter-dot.action { background: transparent; box-shadow: inset 0 0 0 2px var(--red); }
.status-filter-dot.running { background: var(--amber); }
.status-filter-dot.done { background: var(--teal); }

.status-filter-summary {
  margin: 8px 0 0;
  color: var(--muted-2);
  font-size: 12px;
  line-height: 1.5;
}

.status-filter .status-filter-clear {
  min-height: 24px;
  padding: 0;
  border-radius: 4px;
  color: var(--red);
  background: none;
  font-size: 12px;
  font-weight: 500;
  text-decoration: underline;
}

.status-filter .status-filter-clear:hover {
  color: var(--red-deep);
  background: none;
}

/* The Projects list chip row sits in the panel, above the card grid. */
#projectStatusFilter .status-filter {
  margin-bottom: 0;
}

.status-filter-empty {
  align-items: center;
}

@media (max-width: 480px) {
  .status-filter .status-filter-chip {
    white-space: normal;
    text-align: left;
  }
}

/* QA bar visible counts (release a11y batch, W2) */
/* "12 passed · 3 need review · 1 failed": the words that carry the QA bar's
   colour split on a card that no longer prints "QA pass N/M" (WCAG 1.4.1). It
   sits first in the export bar, right under the bar. Muted, small, Thai-safe:
   it wraps instead of overflowing at 390px, and keeps the 1.5 line-height. */
.qa-bar-counts {
  min-width: 0;
  max-width: 100%;
  color: var(--muted);
  font-size: 12px;
  font-weight: 500;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.run-export-links > .qa-bar-counts {
  flex: 1 1 100%;
}

/* ---------------------------------------------------------------------------
   Doc 85 P6: "This blueprint needs" panel (Manual Run Step 2 and the project's
   Column mapping window), the Step 2 summary, the Start gate note and the
   file-row badge. Tokens only; every word is Thai-safe (wraps, no uppercase).
   ------------------------------------------------------------------------- */
.blueprint-fields[hidden] { display: none; }
.bp-fields-title {
  margin: 0 0 4px;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.5;
}
.bp-fields-help { margin: 0 0 10px; font-size: 12px; line-height: 1.6; overflow-wrap: anywhere; }
.bp-field-list { display: grid; gap: 6px; }
.bp-field-row {
  display: grid;
  grid-template-columns: minmax(150px, 1fr) minmax(180px, 1.2fr) minmax(140px, 1fr);
  align-items: center;
  gap: 8px 12px;
  padding: 6px 8px;
  border: 1px solid var(--line);
  border-radius: 6px;
  font-size: 13px;
  line-height: 1.5;
}
.bp-field-row.is-error { border-color: var(--red); background: var(--red-tint); }
.bp-field-row.is-warn { border-color: var(--amber); border-style: dashed; background: var(--amber-tint); }
.bp-field-name { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; margin: 0; overflow-wrap: anywhere; }
.bp-field-by { font-size: 11px; font-weight: 500; }
.bp-field-row select { min-height: 34px; min-width: 0; max-width: 100%; font-size: 12px; }
.bp-field-level {
  display: inline-block;
  padding: 0 6px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  line-height: 1.6;
}
.bp-field-level.is-required { border-color: var(--ink); color: var(--ink); }
.bp-field-state { font-size: 12px; font-weight: 600; overflow-wrap: anywhere; }
.bp-field-state::before {
  content: "";
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-right: 6px;
  border-radius: 50%;
  background: var(--muted-2);
}
.bp-field-row.is-ok .bp-field-state { color: var(--teal); }
.bp-field-row.is-ok .bp-field-state::before { background: var(--teal); }
.bp-field-row.is-warn .bp-field-state { color: var(--amber-text); }
.bp-field-row.is-warn .bp-field-state::before { background: var(--amber); }
.bp-field-row.is-error .bp-field-state { color: var(--red); }
/* red stays rare (wave2-css): the dot is a ring, not a solid red fill */
.bp-field-row.is-error .bp-field-state::before { background: transparent; box-shadow: inset 0 0 0 4px var(--red); }
.bp-field-row.is-muted .bp-field-state { color: var(--muted); }
.bp-field-guess { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; font-size: 12px; }
.bp-fields-other { margin-top: 12px; }
.bp-fields-other > summary { cursor: pointer; font-size: 13px; font-weight: 600; line-height: 1.6; }
.bp-fields-other[open] > summary { margin-bottom: 6px; }
@media (max-width: 1040px) {
  .bp-field-row { grid-template-columns: minmax(0, 1fr); }
}

.manual-mapping-usage-line { grid-column: 1 / -1; margin: 0; font-size: 14px; font-weight: 600; line-height: 1.6; overflow-wrap: anywhere; }
.manual-mapping-usage-details,
.manual-mapping-summary > .manual-mapping-group,
.manual-mapping-summary > .manual-mapping-warning { grid-column: 1 / -1; }
.manual-mapping-usage-details > summary { cursor: pointer; font-size: 13px; font-weight: 600; line-height: 1.6; }
.manual-mapping-usage-details .manual-mapping-group { margin-top: 8px; }
.manual-mapping-usage-details .manual-mapping-list { max-height: 260px; overflow: auto; }

#startRunGateNote { margin-top: 12px; overflow-wrap: anywhere; }
.task-fields-missing { font-size: 12px; overflow-wrap: anywhere; }

/* ---------- plan issues (public/plan-issues.js): a plan that cannot run, shown before Run ---------- */
.plan-notice {
  display: grid;
  gap: 8px;
  margin: 8px 0 0;
  padding: 10px 12px;
  border: 1px solid var(--amber);
  border-radius: 8px;
  background: var(--amber-tint);
  color: var(--ink);
  font-size: 13px;
  line-height: 1.55;
  overflow-wrap: anywhere;
}
.plan-notice-list { margin: 0; padding-left: 18px; display: grid; gap: 4px; }
.plan-notice-fix { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; }
.plan-notice-cost { font-size: 12px; line-height: 1.5; }
/* The file the editor's plan check is asked about: a compact label + select row with muted help under it, above the notice. */
.bp-plan-file { margin: 8px 0 0; display: grid; gap: 4px; }
.bp-plan-file[hidden] { display: none; }
.bp-plan-file-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.bp-plan-file-row .field-label { margin: 0; }
.bp-plan-file-row select { flex: 0 1 320px; min-width: 0; max-width: 100%; }
.bp-plan-file .muted { margin: 0; overflow-wrap: anywhere; }
.bp-plan-file .muted:empty { display: none; }
.bp-plan-notice-host { margin: 8px 0; display: grid; gap: 8px; }
.bp-plan-notice-host[hidden] { display: none; }
.bp-plan-notice-host .plan-notice { margin: 0; }
.blueprint-card-main .plan-notice { margin: 8px 0 0; font-size: 12px; }
.file-task-row .plan-notice { margin: 8px 0 0; font-size: 12px; }
.file-plan-status { margin: 8px 0 0; font-size: 12px; line-height: 1.55; overflow-wrap: anywhere; }
.manual-mapping-plan-notice .plan-notice { margin: 8px 0 0; }

.plan-steps { margin: 0; padding-left: 20px; display: grid; gap: 4px; font-size: 13px; line-height: 1.55; }
.plan-steps li { overflow-wrap: anywhere; }
.plan-step-name { font-weight: 600; }
.plan-step-capability { font-size: 12px; }
.plan-node-badge { flex: 0 0 auto; font-size: 11px; line-height: 1.5; margin-left: auto; }
.plan-steps .plan-node-badge { margin-left: 6px; }
.bp-node-head b { min-width: 0; overflow-wrap: anywhere; }

.plan-changes { display: grid; gap: 6px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 8px; background: var(--panel); font-size: 13px; line-height: 1.55; }
.plan-changes-list { margin: 0; padding: 0; list-style: none; display: grid; gap: 6px; }
.plan-changes-list li { overflow-wrap: anywhere; }
.plan-change-name { font-weight: 600; }
.plan-change-detail, .plan-change-writes { font-size: 12px; line-height: 1.5; }
.plan-change-writes { color: var(--amber-text); font-weight: 600; }
.plan-changes p { margin: 0; }

.file-task-row .file-task-plan-note {
  margin: 4px 0 0;
  color: var(--amber-text);
  font-size: 12px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

/* ---- The AI check of free-form steps (Decision 281 X4) -------------------------------------------------------------------------------
   Three places: the switch in the blueprint's Run settings, the check list under a free-form step's prompt, and one block per row in Row
   Review. Neutral surfaces; amber only for "the list may be out of date", red only for a failed Must pass check (semantic, not decoration). */
.bp-freeform-judge { margin: 4px 0 12px; }
.bp-freeform-judge .field-label { margin-bottom: 4px; }
.bp-freeform-judge .muted { overflow-wrap: anywhere; }

/* A direct child of the inspector grid, like the Rules section: span both columns instead of landing in the narrow settings column. */
.bp-checklist-section {
  grid-column: 1 / -1;
  margin: 14px 0 0;
  padding: 10px 0 0;
  border-top: 1px solid var(--line);
  border-bottom: 0;
}
.bp-checklist-section[hidden] { display: none; }
.bp-checklist { display: grid; gap: 8px; min-width: 0; max-width: 760px; }
.bp-checklist p { margin: 0; overflow-wrap: anywhere; }
.bp-checklist-stale {
  padding: 6px 10px;
  border-left: 3px solid var(--amber);
  border-radius: 6px;
  background: var(--amber-tint);
  color: var(--amber-text);
  font-size: 12px;
  line-height: 1.5;
}
.bp-checklist-stale[hidden] { display: none; }
.bp-checklist-list { margin: 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.bp-checklist-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto auto;
  gap: 6px 10px;
  align-items: center;
}
.bp-checklist-item .bp-checklist-text { min-width: 0; width: 100%; }
.bp-checklist-must { white-space: nowrap; }
.bp-checklist-origin { white-space: nowrap; font-size: 11px; line-height: 1.5; }
.bp-checklist-add-row { display: flex; gap: 8px; align-items: center; }
.bp-checklist-add-row input { flex: 1 1 auto; min-width: 0; }
.bp-checklist-draft-list { margin: 0 0 8px; padding-left: 18px; display: grid; gap: 4px; overflow-wrap: anywhere; }
.bp-checklist-status { min-height: 1.5em; }
@media (max-width: 700px) {
  .bp-checklist-item { grid-template-columns: minmax(0, 1fr) auto; }
  .bp-checklist-item .bp-checklist-text { grid-column: 1 / -1; }
}

/* The columns a free-form step declares it writes (Decision 281, doc 86 X1): sits inside the free-form settings, above the step hint. */
.bp-declared-outputs { min-width: 0; margin: 4px 0 0; }
.bp-declared-outputs[hidden] { display: none; }
.bp-outputs { display: grid; gap: 8px; min-width: 0; max-width: 760px; }
.bp-outputs p { margin: 0; overflow-wrap: anywhere; }
.bp-outputs-list { margin: 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.bp-outputs-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: 6px 10px;
  align-items: center;
}
.bp-outputs-item .bp-outputs-label { min-width: 0; width: 100%; }
.bp-outputs-item .bp-outputs-label[aria-invalid="true"] { border-color: var(--amber); }
.bp-outputs-issues {
  padding: 6px 10px;
  border-left: 3px solid var(--amber);
  border-radius: 6px;
  background: var(--amber-tint);
  color: var(--amber-text);
  font-size: 12px;
  line-height: 1.5;
}
.bp-outputs-issues[hidden] { display: none; }
.bp-outputs-add-row { display: flex; gap: 8px; align-items: center; }
.bp-outputs-add-row input { flex: 1 1 auto; min-width: 0; }
.bp-outputs-add-row select, .bp-outputs-item select { flex: 0 0 auto; width: auto; min-width: 7em; }
.bp-outputs-status { min-height: 1.5em; }
@media (max-width: 700px) {
  .bp-outputs-item { grid-template-columns: minmax(0, 1fr) auto; }
  .bp-outputs-item .bp-outputs-label { grid-column: 1 / -1; }
  .bp-outputs-add-row { flex-wrap: wrap; }
}

/* Row Review: the AI check's finding sits under the one-line reason. `.row-review-table td span` makes every span a block; these
   selectors are more specific on purpose, and the chip stays an inline-block chip. */
.row-review-table td .row-judge {
  display: grid;
  gap: 2px;
  min-width: 0;
  margin-top: 4px;
  font-size: 12px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}
.row-review-table td .row-judge p { margin: 0; }
.row-review-table td .row-judge span { display: inline; }
.row-review-table td .row-judge .row-judge-chip { display: inline-block; width: fit-content; max-width: 100%; }
.row-judge-failed-head { color: var(--muted); font-weight: 600; }
.row-judge-items { margin: 0; padding-left: 16px; display: grid; gap: 2px; }
.row-review-table td .row-judge .row-judge-must { color: var(--red-deep); font-weight: 600; }
.row-review-table td .row-judge .row-judge-why,
.row-review-table td .row-judge .row-judge-step { color: var(--muted); }
