/* Cooper&Wright — editorial serif skin: engraved serifs, ivory paper,
   hunter green and brass, hairline rules, small-caps letterspaced labels,
   zero rounded corners. Copy stays plain and professional -- no in-character
   "law firm" language, this is a visual style only.
   Fonts are loaded via <link> in the application layout (CSP-friendly). */

/* ---- tokens: color ---- */
:root {
  --ink-1: #1c1a15;
  --ink-2: #45402f;
  --ink-3: #6e6753;
  --ink-4: #9a9280;
  --paper-1: #f4eedf;
  --paper-2: #fbf7ec;
  --paper-3: #ece4cf;
  --paper-4: #e2d8be;
  --green-9: #0f231c;
  --green-8: #16302b;
  --green-7: #1e4237;
  --green-6: #2a594a;
  --green-3: #7fa08f;
  --green-1: #dde5da;
  --brass-7: #6e5320;
  --brass-6: #8c6a2f;
  --brass-5: #a3803c;
  --brass-3: #c8ae72;
  --brass-1: #efe5c8;
  --oxblood-8: #4a161a;
  --oxblood-7: #5e1f24;
  --oxblood-6: #7a2b30;
  --oxblood-1: #ead5d2;

  --surface-page: var(--paper-1);
  --surface-card: var(--paper-2);
  --surface-inset: var(--paper-3);
  --surface-inverse: var(--green-9);
  --surface-raised: #fffdf6;
  --text-display: var(--ink-1);
  --text-body: var(--ink-2);
  --text-muted: var(--ink-3);
  --text-faint: var(--ink-4);
  --text-on-inverse: var(--paper-2);
  --text-accent: var(--brass-6);
  --text-link: var(--green-7);
  --action-primary: var(--green-8);
  --action-primary-hover: var(--green-9);
  --action-destructive: var(--oxblood-7);
  --action-destructive-hover: var(--oxblood-8);
  --focus-ring: var(--brass-5);
  --rule-hairline: rgba(28, 26, 21, 0.28);
  --rule-faint: rgba(28, 26, 21, 0.14);
  --rule-strong: var(--ink-1);
  --rule-brass: var(--brass-5);

  --status-detected: var(--brass-6);
  --status-generating: var(--brass-6);
  --status-creating-pr: var(--brass-7);
  --status-pr-opened: var(--green-7);
  --status-resolved: var(--green-8);
  --status-failed: var(--oxblood-7);
  --status-generating-bg: var(--brass-1);
  --status-pr-opened-bg: var(--green-1);
  --status-resolved-bg: var(--green-1);
  --status-failed-bg: var(--oxblood-1);
  --status-detected-bg: var(--paper-3);

  /* billing status: green=good, brass=in-progress, oxblood=bad, ink=neutral */
  --status-good: var(--green-7);
  --status-good-bg: var(--green-1);
  --status-progress: var(--brass-6);
  --status-progress-bg: var(--brass-1);
  --status-bad: var(--oxblood-7);
  --status-bad-bg: var(--oxblood-1);
  --status-neutral: var(--ink-3);
  --status-neutral-bg: var(--paper-3);

  /* type */
  --font-display: 'Cormorant Garamond', Georgia, serif;
  --font-body: 'EB Garamond', Georgia, serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, monospace;
  --type-display-1: 44px;
  --type-display-2: 34px;
  --type-title: 26px;
  --type-heading: 20px;
  --type-body: 17px;
  --type-small: 15px;
  --type-caption: 13px;
  --type-label: 12.5px;
  --weight-display: 600;
  --weight-heading: 600;
  --weight-body: 400;
  --weight-medium: 500;
  --leading-display: 1.12;
  --leading-body: 1.55;
  --leading-tight: 1.3;
  --tracking-label: 0.14em;
  --tracking-wide: 0.08em;
  --tracking-display: 0.005em;

  /* spacing */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;
  --space-9: 96px;
  --page-max-width: 1120px;
  --content-measure: 64ch;

  /* effects */
  --radius-0: 0;
  --radius-1: 2px;
  --border-hairline: 1px solid var(--rule-hairline);
  --border-faint: 1px solid var(--rule-faint);
  --border-strong: 1.5px solid var(--rule-strong);
  --border-double: 3px double var(--rule-hairline);
  --border-brass: 1px solid var(--rule-brass);
  --shadow-card: 0 1px 0 rgba(28, 26, 21, 0.08);
  --shadow-raised:
    0 2px 10px rgba(28, 26, 21, 0.1), 0 1px 0 rgba(28, 26, 21, 0.06);
  --shadow-modal: 0 12px 40px rgba(15, 35, 28, 0.22);
  --ease-out: cubic-bezier(0.25, 0.1, 0.25, 1);
  --dur-fast: 120ms;
  --dur-med: 220ms;
  --dur-slow: 400ms;
}

/* ---- base ---- */
* {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  background: var(--surface-page);
  color: var(--text-body);
  font-family: var(--font-body);
  font-size: var(--type-body);
  line-height: var(--leading-body);
  margin: 0;
  -webkit-font-smoothing: antialiased;
  font-variant-numeric: lining-nums;
}

a {
  color: var(--text-link);
  text-decoration: underline;
  text-decoration-color: var(--rule-brass);
  text-underline-offset: 3px;
  transition: color var(--dur-fast) var(--ease-out);
}

a:hover {
  color: var(--green-9);
  text-decoration-color: var(--brass-6);
}

::selection {
  background: var(--brass-1);
}

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

h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  line-height: var(--leading-display);
  color: var(--text-display);
  margin: 0;
}

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

/* ---- house classes ---- */
.cw-label {
  font-family: var(--font-body);
  font-size: var(--type-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  font-variant-numeric: lining-nums;
}

.cw-display {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  line-height: var(--leading-display);
  letter-spacing: var(--tracking-display);
  color: var(--text-display);
}

.cw-body {
  font-family: var(--font-body);
  font-size: var(--type-body);
  line-height: var(--leading-body);
  color: var(--text-body);
}

.cw-mono {
  font-family: var(--font-mono);
  font-size: var(--type-caption);
  font-variant-ligatures: none;
}

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

.cw-italic {
  font-style: italic;
}

.cw-numero {
  color: var(--text-accent);
}

/* ---- wordmark ---- */
.cw-wordmark {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: 0.005em;
  color: var(--text-display);
  text-decoration: none;
  line-height: 1;
}

.cw-wordmark .amp {
  color: var(--brass-6);
}

.cw-wordmark--dark {
  color: var(--paper-2);
}

.cw-wordmark--dark .amp {
  color: var(--brass-3);
}

/* ---- app shell: header / main / footer ---- */
.cw-appshell {
  /* 100vh first as the fallback, then the honest number: iOS Safari's vh is
     the viewport with the URL bar HIDDEN, so a shell sized in vh puts its
     last row behind the chrome and lurches as the bar comes and goes. */
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--surface-page);
}

.cw-header {
  background: var(--surface-inverse);
  color: var(--text-on-inverse);
}

.cw-header__inner {
  max-width: var(--page-max-width);
  margin: 0 auto;
  padding: 0 var(--space-6);
  height: 64px;
  display: flex;
  align-items: center;
  gap: 40px;
}

/* Sized here rather than inline on the link so the phone rule below can
   take it down a step. */
.cw-header .cw-wordmark {
  font-size: 23px;
  flex-shrink: 0;
}

.cw-header__nav {
  display: flex;
  gap: 28px;
  flex: 1;
}

.cw-header__nav a {
  color: var(--paper-2);
  text-decoration: none;
  padding-bottom: 2px;
}

.cw-header__nav a.is-active {
  border-bottom: 1px solid var(--brass-5);
}

.cw-header__nav a:hover {
  border-bottom: 1px solid var(--brass-5);
  color: var(--paper-2);
}

/* Allowed to give way: on a narrow header a long GitHub login is the one
   thing here that can be shortened without losing a control. */
.cw-header__user {
  color: var(--green-3);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cw-header form {
  margin: 0;
  display: inline;
}

.cw-header__signout-btn {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  color: var(--brass-3);
  font-family: var(--font-body);
  font-size: var(--type-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
}

.cw-header__signout-btn:hover {
  color: var(--brass-1);
}

.cw-main {
  flex: 1;
  max-width: var(--page-max-width);
  width: 100%;
  margin: 0 auto;
  padding: 40px var(--space-6) var(--space-8);
}

.cw-footer {
  background: var(--surface-inverse);
  color: var(--green-3);
}

.cw-footer__inner {
  max-width: var(--page-max-width);
  margin: 0 auto;
  padding: 18px var(--space-6);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 6px var(--space-5);
  font-size: 13.5px;
  font-style: italic;
}

.cw-footer__inner .amp {
  color: var(--brass-3);
  font-style: normal;
}

/* ---- page heads ---- */
.cw-pagehead {
  margin-bottom: 26px;
}

.cw-pagehead__over {
  color: var(--text-accent);
}

.cw-pagehead h1 {
  font-size: var(--type-display-1);
  margin: 6px 0 0;
}

/* ---- buttons ---- */
.cw-btn {
  font-family: var(--font-body);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  padding: 10px 22px;
  border: 1px solid transparent;
  border-radius: 0;
  cursor: pointer;
  background: transparent;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  transition:
    background var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
  text-decoration: none;
  line-height: 1;
}

.cw-btn:active {
  transform: translateY(1px);
}

.cw-btn--lg {
  padding: 13px 30px;
}

.cw-btn--sm {
  padding: 7px 16px;
  font-size: 11.5px;
}

.cw-btn--block {
  width: 100%;
}

.cw-actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 4px;
}

.cw-actions__form {
  margin: 0;
}

.cw-btn--primary {
  background: var(--action-primary);
  color: var(--text-on-inverse);
  border-color: var(--action-primary);
}

.cw-btn--primary:hover {
  background: var(--action-primary-hover);
  color: var(--text-on-inverse);
}

.cw-btn--secondary {
  border: 1px solid var(--rule-strong);
  color: var(--text-display);
}

.cw-btn--secondary:hover {
  background: var(--surface-inset);
  color: var(--text-display);
}

.cw-btn--ghost {
  color: var(--text-body);
  text-decoration: underline;
  text-decoration-color: var(--rule-brass);
  text-underline-offset: 4px;
}

.cw-btn--ghost:hover {
  color: var(--green-9);
}

.cw-btn--destructive {
  background: var(--action-destructive);
  color: var(--text-on-inverse);
  border-color: var(--action-destructive);
}

.cw-btn--destructive:hover {
  background: var(--action-destructive-hover);
  color: var(--text-on-inverse);
}

/* ---- cards ---- */
.cw-card {
  background: var(--surface-card);
  border: var(--border-hairline);
  box-shadow: var(--shadow-card);
  padding: 28px 32px;
}

.cw-card__over {
  color: var(--text-accent);
  display: block;
}

.cw-card__title {
  font-size: var(--type-heading);
  margin: 4px 0 0;
}

.cw-card__head {
  padding-bottom: 14px;
  margin-bottom: 18px;
}

.cw-card__head--brass {
  border-bottom: var(--border-brass);
}

.cw-card__head--double {
  border-bottom: var(--border-double);
}

.cw-sync-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 16px;
  margin-bottom: 18px;
}

.cw-sync-line__form {
  flex-shrink: 0;
}

/* The GitHub App card's list of accounts the App is installed on. */
.cw-install-list {
  list-style: none;
  margin: 0 0 4px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.cw-install-list__item {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
}

.cw-card__note {
  font-size: 13px;
  font-style: italic;
  color: var(--text-muted);
  margin: 14px 0 0;
}

/* The README badge snippet on the mapping page: a markdown image link whose
   longest token is wider than a phone and has nothing to break on. Left to
   the default wrapping it sets the column's min-content width, which drags
   the settings card -- and the page -- past the viewport. */
.cw-card__note[data-badge='markdown'] {
  overflow-wrap: anywhere;
}

/* The Headroom snapshot never expires, so an old one still shows its
   figures. This is the only thing on the panel saying they are old --
   it has to read as a warning, not as another muted footnote. */
.cw-headroom-age.is-stale {
  font-style: normal;
  color: var(--status-bad);
  background: var(--status-bad-bg);
  border-left: 2px solid var(--status-bad);
  padding: 6px 10px;
}

/* ---- badges (status pills) ---- */
.cw-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  font-family: var(--font-body);
  font-size: var(--type-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  border: 1px solid transparent;
  white-space: nowrap;
}

.cw-badge--detected {
  color: var(--status-detected);
  background: var(--status-detected-bg);
  border-color: var(--brass-3);
}

.cw-badge--generating {
  color: var(--status-generating);
  background: var(--status-generating-bg);
  border-color: var(--brass-3);
}

.cw-badge--creating_pr {
  color: var(--status-creating-pr);
  background: var(--status-generating-bg);
  border-color: var(--brass-3);
}

.cw-badge--pr_opened {
  color: var(--status-pr-opened);
  background: var(--status-pr-opened-bg);
  border-color: var(--green-3);
}

.cw-badge--resolved {
  color: var(--status-resolved);
  background: var(--status-resolved-bg);
  border-color: var(--green-3);
}

.cw-badge--failed {
  color: var(--status-failed);
  background: var(--status-failed-bg);
  border-color: var(--oxblood-6);
}

/* a pull request that landed -- merged by a human, or by Cooper itself */
.cw-badge--merged,
.cw-badge--auto_merged {
  color: var(--status-good);
  background: var(--status-good-bg);
  border-color: var(--green-3);
}

.cw-badge--fixing_ci {
  color: var(--status-generating);
  background: var(--status-generating-bg);
  border-color: var(--brass-3);
}

/* incident: flagged for a human to step in -- warm attention, not an error */
.cw-badge--needs_attention {
  color: var(--status-bad);
  background: var(--status-bad-bg);
  border-color: var(--oxblood-6);
}

/* incident: gated on billing */
.cw-badge--billing_blocked {
  color: var(--status-bad);
  background: var(--status-bad-bg);
  border-color: var(--oxblood-6);
}

/* billing states -- subscription / invoice / refund / dispute */
.cw-badge--active,
.cw-badge--paid,
.cw-badge--succeeded,
.cw-badge--won {
  color: var(--status-good);
  background: var(--status-good-bg);
  border-color: var(--green-3);
}

.cw-badge--trialing,
.cw-badge--open,
.cw-badge--incomplete,
.cw-badge--needs_response,
.cw-badge--under_review,
.cw-badge--pending {
  color: var(--status-progress);
  background: var(--status-progress-bg);
  border-color: var(--brass-3);
}

.cw-badge--past_due,
.cw-badge--unpaid,
.cw-badge--uncollectible,
.cw-badge--lost {
  color: var(--status-bad);
  background: var(--status-bad-bg);
  border-color: var(--oxblood-6);
}

.cw-badge--closed,
.cw-badge--canceled,
.cw-badge--void,
.cw-badge--draft,
.cw-badge--paused,
.cw-badge--incomplete_expired {
  color: var(--status-neutral);
  background: var(--status-neutral-bg);
  border-color: var(--rule-faint);
}

/* self-improve run outcomes (admin panel) */
.cw-badge--running {
  color: var(--status-generating);
  background: var(--status-generating-bg);
  border-color: var(--brass-3);
}

.cw-badge--filed_issue {
  color: var(--status-detected);
  background: var(--status-detected-bg);
  border-color: var(--brass-3);
}

.cw-badge--opened_pr {
  color: var(--status-good);
  background: var(--status-good-bg);
  border-color: var(--green-3);
}

/* Cooper declining is normal operation, not a failure -- same neutral
   treatment as a closed/canceled row. */
.cw-badge--refused {
  color: var(--status-neutral);
  background: var(--status-neutral-bg);
  border-color: var(--rule-faint);
}

.cw-badge--errored {
  color: var(--status-bad);
  background: var(--status-bad-bg);
  border-color: var(--oxblood-6);
}

/* ---- status filter chips (dashboard) ---- */
.cw-filter {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}

.cw-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 12px;
  font-family: var(--font-body);
  font-size: var(--type-label);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
  background: var(--surface-inset);
  border: var(--border-faint);
  text-decoration: none;
  cursor: pointer;
  transition:
    color 120ms ease,
    background 120ms ease,
    border-color 120ms ease;
}

.cw-chip:hover {
  color: var(--text-body);
  border-color: var(--brass-3);
}

.cw-chip__check {
  width: 14px;
  height: 14px;
  margin: 0;
  accent-color: var(--brass-6);
  cursor: pointer;
}

/* The chip text is a real control (click => filter to this status only), so it
   must shed all default <button> chrome and inherit the chip's typography. */
.cw-chip__label {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 0;
  margin: 0;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}

/* Active = checkbox ticked; keep the pill subtle so the tick reads clearly. */
.cw-chip.is-active {
  color: var(--text-body);
  border-color: var(--brass-6);
}

.cw-chip__count {
  font-family: var(--font-mono);
  font-size: 11px;
  opacity: 0.85;
}

.cw-chip--reset {
  color: var(--text-muted);
  background: transparent;
}

.cw-filter__note {
  margin: 0 0 18px;
  font-size: var(--type-small);
  color: var(--text-muted);
}

/* ---- filter dropdowns (dashboard) ---- */
.cw-dropdown {
  position: relative;
  display: inline-block;
  margin: 0 8px 12px 0;
}

.cw-dropdown__trigger {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  font-family: var(--font-body);
  font-size: var(--type-label);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
  background: var(--surface-inset);
  border: var(--border-faint);
  cursor: pointer;
  list-style: none;
  user-select: none;
}

.cw-dropdown__trigger::-webkit-details-marker {
  display: none;
}

.cw-dropdown__trigger:hover {
  color: var(--text-body);
  border-color: var(--brass-3);
}

.cw-dropdown[open] > .cw-dropdown__trigger {
  color: var(--text-body);
  border-color: var(--brass-6);
}

.cw-dropdown__badge {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--surface-page);
  background: var(--brass-6);
  padding: 1px 6px;
}

.cw-dropdown__caret {
  font-size: 9px;
  opacity: 0.7;
  transition: transform 120ms ease;
}

.cw-dropdown[open] .cw-dropdown__caret {
  transform: rotate(180deg);
}

.cw-dropdown__panel {
  position: absolute;
  z-index: 20;
  top: calc(100% + 4px);
  left: 0;
  min-width: 220px;
  max-height: 320px;
  overflow-y: auto;
  padding: 10px;
  background: var(--surface-raised);
  border: var(--border-hairline);
  box-shadow: 0 6px 18px rgba(28, 26, 21, 0.24);
}

.cw-dropdown__panel .cw-filter {
  flex-direction: column;
  align-items: stretch;
  margin-bottom: 0;
}

.cw-dropdown__panel .cw-chip {
  justify-content: flex-start;
}

/* ---- tags ---- */
.cw-tag {
  display: inline-flex;
  align-items: center;
  padding: 2px 9px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-body);
  background: var(--surface-inset);
  border: var(--border-faint);
  /* A pill that breaks over two lines stops reading as a pill -- except
     under a page title, where the pill IS the branch name and the whole of
     it has to be on the page (see .cw-matter__tags below). */
  white-space: nowrap;
}

/* ---- tables (docket) ---- */
.cw-table {
  width: 100%;
  border-collapse: collapse;
}

.cw-table thead th {
  text-align: left;
  padding: 8px 14px;
  font-family: var(--font-body);
  font-size: var(--type-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
  border-bottom: var(--border-strong);
}

.cw-table thead th.is-right,
.cw-table td.is-right {
  text-align: right;
}

.cw-table tbody td {
  padding: 13px 14px;
  border-bottom: 1px solid var(--rule-hairline);
  vertical-align: middle;
  font-size: var(--type-small);
  color: var(--text-body);
}

.cw-table tbody tr.is-clickable {
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out);
}

.cw-table tbody tr.is-clickable:hover {
  background: var(--surface-inset);
}

.cw-table a {
  text-decoration: none;
}

.cw-table td .cw-mono {
  font-size: 12.5px;
}

/* A column that takes exactly its content's width and never breaks it (a
   tag, a repo slug, a relative time), leaving the flexible columns -- the
   title -- to absorb the rest of the table. `width: 1%` reads as "as narrow
   as possible": auto table layout raises it to the cell's min-content, which
   nowrap makes its full single line. Only works while the table is
   `table-layout: auto` (the default) -- under `fixed` the 1% would be taken
   literally and the content would spill out of the cell instead. */
.cw-table th.is-tight,
.cw-table td.is-tight {
  width: 1%;
  white-space: nowrap;
}

/* The column that absorbs whatever the is-tight ones leave. It has to be
   allowed to break below its longest word: auto layout sizes a table to the
   SUM of its columns' min-content widths, so one unbreakable token in here
   -- a Flutter exception carrying a 90-character method channel, say --
   pushes that sum past the card and the last column lands outside the
   border. Breaking anywhere caps this column's min-content at one
   character, and the leftover width still comes to it because it has by far
   the largest max-content of the row. */
.cw-table th.is-elastic,
.cw-table td.is-elastic {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* ...and, where the leftover width should go to that column rather than be
   shared out, 100% against the others' 1%. Auto layout hands the slack to
   the widest max-content otherwise, which left the title on ~180px while
   Repository sat on 45px of dead space beside its longest value. Pairs with
   is-elastic on the same cell; a table wanting its columns to share the
   slack (the by-repository one) simply does not use it. */
.cw-table th.is-remainder,
.cw-table td.is-remainder {
  width: 100%;
}

/* A table that would rather scroll than spill. Auto layout can shrink a
   table only to the sum of its columns' min-content widths; past that it
   overflows its card, straight across the right border. Wrapping the table
   gives that overflow a scrollbar instead. */
.cw-table-scroll {
  overflow-x: auto;
}

/* A column of prose (a CI-fix reason, an incident title) inside a scrolling
   table. Auto layout would hand it its min-content width -- one word -- and
   wrap the reason into a column of thirty short lines; the floor keeps it
   readable and lets the wrapper scroll for the rest. */
.cw-table th.is-prose,
.cw-table td.is-prose {
  min-width: 24ch;
}

/* ---- the same table on a phone: one docket per row ----
   Below this width a six-column table can only scroll, and scrolling hides
   the very cell the row exists for (its title, its status). So a table
   marked --stack turns each row into a short docket: every cell on its own
   line, labelled by its `data-label` in the same small caps the column head
   used, and the `.is-remainder` cell -- the column that was already the
   row's point on the wide layout -- first and unlabelled, as the headline.
   The label sits in the cell's left padding rather than as a first child, so
   a cell with several inline children (a link, its glyph, a note beneath)
   keeps flowing exactly as it did in the wide table. The head is dropped:
   its text is now on every cell. Tables that are numbers all the way across
   (the by-repository one, the admin ledgers) stay tables and scroll in a
   `.cw-table-scroll` instead.

   Every selector here doubles up as `.cw-table.cw-table--stack`: the wide
   layout's column rules (`.cw-table td.is-right`, `.cw-table td.is-tight`
   with its 1% width and nowrap, the tablet cell padding) are two classes
   deep, and a docket has to out-rank them, not just come later. */
@media (max-width: 560px) {
  .cw-table.cw-table--stack,
  .cw-table.cw-table--stack tbody,
  .cw-table.cw-table--stack tbody td,
  .cw-table.cw-table--stack .cw-table__group,
  .cw-table.cw-table--stack .cw-table__group th {
    display: block;
    width: auto;
  }

  .cw-table.cw-table--stack thead {
    display: none;
  }

  /* A flex column, for `order`: the headline cell comes first whichever
     column it was. */
  .cw-table.cw-table--stack tbody tr {
    display: flex;
    flex-direction: column;
    padding: 12px 0 14px;
    border-bottom: 1px solid var(--rule-hairline);
  }

  .cw-table.cw-table--stack tbody td {
    position: relative;
    min-height: 1.6em;
    padding: 3px 0 3px 7.5em;
    border-bottom: none;
    text-align: left;
    white-space: normal;
  }

  .cw-table.cw-table--stack td[data-label]::before {
    content: attr(data-label);
    position: absolute;
    top: 5px;
    left: 0;
    width: 7em;
    font-family: var(--font-body);
    font-size: var(--type-label);
    font-weight: var(--weight-medium);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--text-muted);
  }

  .cw-table.cw-table--stack tbody td.is-remainder {
    order: -1;
    padding-left: 0;
    padding-bottom: 6px;
    font-size: var(--type-body);
  }

  /* An expanded Lessons row is its own docket, not a headline. */
  .cw-table.cw-table--stack tbody td[colspan] {
    padding-left: 0;
  }

  .cw-table.cw-table--stack .cw-table__group th {
    padding: 22px 0 6px;
  }

  /* The wide layout's caps and right-hand alignment no longer apply: a note
     hangs under its badge on the left, a branch name has the whole line,
     and the rule column's floor (there for a table that could still scroll
     sideways) would push this docket past the phone. */
  .cw-table.cw-table--stack .cw-row-note,
  .cw-table.cw-table--stack .cw-row-sub {
    margin-left: 0;
    max-width: none;
  }

  .cw-table.cw-table--stack .cw-branch {
    max-width: 100%;
  }

  .cw-table.cw-table--stack .cw-lesson__rule {
    min-width: 0;
  }

  /* Stacked cells (state over scope, mute over the ladder steps) go side by
     side: the docket is short on width, not on height. */
  .cw-table.cw-table--stack .cw-lesson__badges,
  .cw-table.cw-table--stack .cw-lesson__actions {
    grid-auto-flow: column;
    justify-items: start;
    gap: 6px 14px;
  }
}

.cw-table__caption {
  font-size: 13.5px;
  font-style: italic;
  color: var(--text-muted);
  margin-top: 14px;
}

/* ---- forms ---- */
.cw-field {
  display: grid;
  gap: 6px;
}

.cw-field > label {
  color: var(--text-muted);
}

.cw-input,
.cw-select {
  font-family: var(--font-body);
  font-size: var(--type-small);
  color: var(--text-display);
  background: var(--surface-raised);
  border: var(--border-hairline);
  border-radius: 0;
  padding: 9px 12px;
  width: 100%;
  transition: border-color var(--dur-fast) var(--ease-out);
}

.cw-input--mono,
.cw-select--mono {
  font-family: var(--font-mono);
  font-size: 13px;
}

.cw-input:focus,
.cw-select:focus {
  outline: none;
  border-color: var(--brass-5);
  box-shadow: inset 0 -1px 0 var(--brass-5);
}

.cw-input::placeholder {
  color: var(--text-faint);
}

/* switch (retainer) */
.cw-switch {
  position: relative;
  display: inline-flex;
  align-items: center;
}

.cw-switch input {
  position: absolute;
  opacity: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  cursor: pointer;
}

.cw-switch__track {
  width: 40px;
  height: 20px;
  background: var(--paper-4);
  border: 1px solid var(--rule-hairline);
  position: relative;
  transition: background var(--dur-med) var(--ease-out);
}

.cw-switch__track::after {
  content: '';
  position: absolute;
  top: 1px;
  left: 1px;
  width: 16px;
  height: 16px;
  background: var(--surface-raised);
  border: 1px solid var(--rule-hairline);
  transition: transform var(--dur-med) var(--ease-out);
}

.cw-switch input:checked + .cw-switch__track {
  background: var(--green-6);
  border-color: var(--green-7);
}

.cw-switch input:checked + .cw-switch__track::after {
  transform: translateX(20px);
  border-color: var(--green-7);
}

/* ---- tabs ---- */
.cw-tabs {
  display: flex;
  gap: 28px;
  border-bottom: var(--border-hairline);
  margin-bottom: 8px;
}

.cw-tabs a {
  font-family: var(--font-body);
  font-size: var(--type-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
  text-decoration: none;
  padding: 0 0 12px;
  margin-bottom: -1px;
  border-bottom: 2px solid transparent;
}

.cw-tabs a:hover {
  color: var(--text-body);
}

.cw-tabs a.is-active {
  color: var(--text-display);
  border-bottom-color: var(--brass-5);
}

/* The settings tabs sit at the far right, away from the work tabs. */
.cw-tabs a.is-trailing {
  margin-left: auto;
}

/* ...as a GROUP: only the tab that opens it takes the auto margin. A second
   one would split the free space with the first and leave a gap mid-bar
   instead of two tabs sitting together at the end. */
.cw-tabs a.is-trailing ~ a.is-trailing {
  margin-left: 0;
}

/* ---- flashes ---- */
.cw-flash {
  padding: 12px 16px;
  margin-bottom: 20px;
  border: 1px solid transparent;
  font-size: var(--type-small);
}

.cw-flash--notice {
  color: var(--green-7);
  background: var(--status-pr-opened-bg);
  border-color: var(--green-3);
}

.cw-flash--alert {
  color: var(--oxblood-7);
  background: var(--status-failed-bg);
  border-color: var(--oxblood-6);
}

/* ---- launch banner ---- */

.cw-ph-banner {
  background: var(--surface-inverse);
  border-bottom: 1px solid var(--green-7);
}

.cw-ph-banner__inner {
  max-width: var(--page-max-width);
  margin: 0 auto;
  padding: var(--space-2) var(--space-6);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
}

.cw-ph-banner .cw-label {
  color: var(--text-on-inverse);
}

.cw-ph-banner img {
  display: block;
  width: 135px;
  height: auto;
}

/* ---- empty states ---- */
.cw-empty {
  padding: 28px;
  border: var(--border-hairline);
  background: var(--surface-card);
  color: var(--text-muted);
  font-style: italic;
  text-align: center;
}

/* ---- sign in ---- */
.cw-signin {
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--surface-page);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 40px;
}

.cw-signin__brand {
  text-align: center;
  margin-bottom: 36px;
}

/* The wordmark at letterhead size; a phone takes it down (see the phone
   rules), which an inline size on the markup could not be. */
.cw-signin__wordmark {
  font-size: 52px;
}

.cw-signin__over {
  color: var(--text-accent);
  margin-top: 10px;
}

.cw-signin__card {
  background: var(--surface-card);
  border: var(--border-hairline);
  box-shadow: var(--shadow-card);
  padding: 36px 44px;
  width: 380px;
  max-width: 100%;
  text-align: center;
}

.cw-signin__card-inner {
  border-top: var(--border-double);
  padding-top: 20px;
}

.cw-signin__pitch {
  font-family: var(--font-body);
  font-size: 16.5px;
  line-height: 1.55;
  color: var(--text-body);
  margin: 0 0 24px;
}

.cw-signin form {
  margin: 0;
}

/* ---- incident detail ---- */
.cw-back {
  font-size: 14px;
}

.cw-matter__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 18px;
  margin: 18px 0 4px;
}

.cw-matter__over {
  color: var(--text-accent);
}

/* The title is the customer's own exception message, and a compare URL or a
   90-character method channel in it has no space to break at: without this
   it runs off the right of the page at every width, 1440px included. */
.cw-matter h1 {
  font-size: var(--type-display-2);
  margin: 2px 0 8px;
  max-width: 56ch;
  overflow-wrap: anywhere;
}

.cw-matter__tags {
  display: flex;
  gap: 8px;
  margin-bottom: 28px;
  flex-wrap: wrap;
}

/* The one place a tag may wrap: these are the branch names, shown whole. */
.cw-matter__tags .cw-tag {
  white-space: normal;
  overflow-wrap: anywhere;
}

.cw-matter__grid {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 24px;
  align-items: start;
}

.cw-matter__col {
  display: grid;
  gap: 24px;
  /* Without this, a column with an unbreakable long string (a stack trace
     line, a commit-compare URL in an incident title) forces its track past
     the 2fr/1fr ratio and squeezes the other column down to its own
     min-content width. */
  min-width: 0;
}

/* pre-wrap keeps the trace's own line breaks and indentation; anywhere lets
   a gem path -- the longest token on the page, with no space in it -- break
   inside a phone's width instead of widening the card past it. */
.cw-trace {
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font-size: 13px;
  line-height: 1.6;
  color: var(--text-body);
}

.cw-diff {
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1.7;
}

.cw-diff__line {
  padding: 0 8px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.cw-diff__line--add {
  color: var(--status-pr-opened);
  background: var(--status-pr-opened-bg);
}

.cw-diff__line--del {
  color: var(--status-failed);
  background: var(--status-failed-bg);
}

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

.cw-timeline__step {
  display: flex;
  gap: 12px;
  align-items: baseline;
  padding: 8px 0;
  border-bottom: 1px solid var(--rule-faint);
}

.cw-timeline__step:last-child {
  border-bottom: none;
}

.cw-timeline__mark {
  font-family: var(--font-display);
  font-size: 16px;
  color: var(--ink-4);
}

.cw-timeline__step.is-done .cw-timeline__mark {
  color: var(--brass-6);
}

.cw-timeline__step.is-done .cw-label {
  color: var(--text-display);
}

.cw-timeline__step.is-failed .cw-timeline__mark,
.cw-timeline__step.is-failed .cw-label {
  color: var(--status-failed);
}

.cw-timeline__step .cw-label {
  color: var(--text-faint);
}

.cw-timeline__time {
  margin-left: auto;
  font-size: 11px;
  color: var(--text-muted);
}

/* A step's note (which files, which checks, why Cooper stopped) gets its own
   row: a `reason` is a whole sentence of Claude's and would push the
   timestamp off the step's line. It belongs to the step above it, so the step
   hands its rule down to the note and the pair reads as one entry -- a
   browser without :has() just shows one extra hairline between them.
   Indented past the mark so it aligns under the label, and free to wrap
   anywhere, since a long path has no spaces to break on. */
.cw-timeline__note {
  margin: -4px 0 0;
  padding: 0 0 8px 28px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--text-muted);
  border-bottom: 1px solid var(--rule-faint);
  overflow-wrap: anywhere;
}

.cw-timeline__step:has(+ .cw-timeline__note) {
  padding-bottom: 4px;
  border-bottom: none;
}

.cw-timeline__note:last-child {
  border-bottom: none;
}

.cw-matter__meta {
  font-size: 13px;
  font-style: italic;
  color: var(--text-muted);
  margin: 0;
}

/* ---- dashboard: retainer switch + inline forms + retain form ---- */
.cw-switch-form,
.cw-inline-form {
  margin: 0;
  display: inline;
}

.cw-switch-btn {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
}

.cw-switch-btn .cw-switch__track {
  width: 40px;
  height: 20px;
  background: var(--paper-4);
  border: 1px solid var(--rule-hairline);
  position: relative;
  transition: background var(--dur-med) var(--ease-out);
}

.cw-switch-btn .cw-switch__track::after {
  content: '';
  position: absolute;
  top: 1px;
  left: 1px;
  width: 16px;
  height: 16px;
  background: var(--surface-raised);
  border: 1px solid var(--rule-hairline);
  transition: transform var(--dur-med) var(--ease-out);
}

.cw-switch-btn.is-on .cw-switch__track {
  background: var(--green-6);
  border-color: var(--green-7);
}

.cw-switch-btn.is-on .cw-switch__track::after {
  transform: translateX(20px);
  border-color: var(--green-7);
}

.cw-switch-btn:disabled {
  cursor: not-allowed;
  opacity: 0.35;
}

.cw-switch-stack {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}

.cw-switch-row {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.cw-link-btn {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--text-link);
  text-decoration: underline;
  text-decoration-color: var(--rule-brass);
  text-underline-offset: 3px;
  text-align: left;
}

.cw-link-btn:hover {
  color: var(--green-9);
}

.cw-retain-form {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 18px 20px;
  align-items: start;
}

.cw-retain-form__half {
  grid-column: span 3;
}

.cw-retain-form__third {
  grid-column: span 2;
}

.cw-retain-form__submit {
  grid-column: 1 / -1;
  justify-self: start;
}

.cw-retain-form .cw-label {
  white-space: nowrap;
}

.cw-retain-form .cw-select,
.cw-retain-form .cw-input {
  width: 100%;
  min-width: 0;
}

/* Optional toggles for a mapping sit on their own full-width row beneath
   the main fields, so the checkboxes never stretch to match a tall
   select-plus-hint cell beside them. */
.cw-retain-form__options {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 32px;
  padding-top: 6px;
  border-top: 1px solid var(--rule-faint);
}

.cw-check-row {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
}

.cw-check-row .cw-label {
  white-space: nowrap;
}

.cw-check {
  width: 15px;
  height: 15px;
  margin: 0;
  accent-color: var(--green-9);
}

.cw-select--compact {
  padding-top: 6px;
  padding-bottom: 6px;
  min-width: 200px;
}

.cw-field__hint {
  color: var(--text-muted);
  font-size: 0.85rem;
  line-height: 1.4;
}

.cw-retain-form__options-hint {
  flex-basis: 100%;
}

/* ---- repo mapping cards (repos tab) ---- */
.cw-mapping-list {
  display: grid;
  gap: 20px;
}

.cw-mapping-card__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px 16px;
}

/* `min-width: 0` on the head's first child so the title can shrink below
   its own longest token, which anywhere then breaks: a monorepo slug in
   20px mono is wider than a phone. */
.cw-mapping-card__head > div {
  min-width: 0;
}

.cw-mapping-card__title {
  display: block;
  font-size: var(--type-heading);
  color: var(--text-display);
  text-decoration: none;
  margin-top: 2px;
  overflow-wrap: anywhere;
}

.cw-mapping-card__title:hover {
  color: var(--text-link);
}

.cw-mapping-card__summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
  margin-top: 16px;
}

.cw-mapping-card__loops {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  font-size: 13px;
}

.cw-mapping-card__settings {
  margin-top: 20px;
  padding-top: 20px;
  border-top: 1px solid var(--rule-faint);
}

/* ---- settings stack (repo mapping switches, shared by the tab card and
   the detail page) ---- */
.cw-settings-stack {
  display: grid;
  gap: 18px;
}

.cw-settings-row {
  display: grid;
  gap: 4px;
  padding-bottom: 18px;
  border-bottom: 1px solid var(--rule-faint);
}

.cw-settings-row:last-child {
  padding-bottom: 0;
  border-bottom: none;
}

.cw-settings-row__control {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}

.cw-settings-row__sub {
  display: grid;
  gap: 4px;
  margin: 8px 0 0 50px;
}

.cw-settings-row--danger .cw-field__hint {
  max-width: 48ch;
}

/* ---- recent-activity lists (repo mapping detail page) ---- */
.cw-activity-list .cw-timeline__step {
  flex-wrap: wrap;
}

.cw-activity-list .cw-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}

/* ==========================================================================
   activity tab — the headline strip, the chart, the two panels and the
   grouped list. Reads top to bottom as how much / how well / what: each
   band is separated by a rule rather than a box, so the whole tab is still
   one card.
   ========================================================================== */

.cw-activity {
  margin-bottom: 28px;
}

.cw-activity__section {
  margin-top: var(--space-6);
}

.cw-activity__heading {
  margin: 0 0 12px;
}

/* Inside a panel a heading follows a figure rather than opening a band, so
   it needs air above it ("Checks", under the success ratio). */
.cw-activity__panels .cw-activity__heading {
  margin: 18px 0 8px;
}

/* A run of small counts under a bar or a figure ("44 passed · 6 failed"). */
.cw-activity__figures {
  margin: 10px 0 0;
  font-size: 13px;
}

/* Both panels take the row's height (the default `stretch`), so the pair
   reads as one band rather than as two cards of different lengths. */
.cw-activity__panels {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-5);
  margin-top: var(--space-6);
}

/* ---- headline strip: label, big number, delta ---- */
.cw-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  margin: 0;
  border-top: var(--border-double);
  border-bottom: var(--border-hairline);
}

.cw-stat {
  padding: 16px 20px 18px;
  border-right: 1px solid var(--rule-faint);
  min-width: 0;
}

.cw-stat:last-child {
  border-right: none;
}

.cw-stat__value {
  font-size: var(--type-display-2);
  margin: 6px 0 4px;
}

.cw-stat__delta {
  margin: 0;
  font-size: 13px;
  color: var(--text-muted);
  font-variant-numeric: lining-nums;
}

.cw-stat__delta--good {
  color: var(--status-good);
}

.cw-stat__delta--bad {
  color: var(--status-bad);
}

.cw-stat__note {
  margin: 4px 0 0;
  font-size: 12.5px;
  font-style: italic;
}

/* Inside a panel the same strip carries secondary figures: no double rule
   above it, and a number sized to sit under a card head rather than a page
   head. Three fixed columns, never auto-fit -- a panel is only ~450px wide,
   so auto-fit's 150px floor wrapped the third figure onto a row of its
   own. */
.cw-stats--tight {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border-top: none;
  border-bottom: 1px solid var(--rule-faint);
}

.cw-stats--tight .cw-stat {
  padding: 8px 14px 12px;
}

.cw-stats--tight .cw-stat:first-child {
  padding-left: 0;
}

.cw-stats--tight .cw-stat__value {
  font-size: var(--type-title);
  margin: 2px 0 0;
}

.cw-stats--pair {
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}

/* ---- chart: a Chart.js canvas, framed by this stylesheet ---- */

/* The canvas's positioning parent, which is what Chart.js measures: it needs
   a definite height (the canvas has none of its own) and `min-width: 0` so a
   grid track cannot hand it a min-content width it will never give back.
   The font is set here rather than in JS because the chart reads its own
   ticks, legend and tooltip type off this element's computed style -- so
   this file stays the source of truth for both the palette and the type. */
.cw-chart__plot {
  position: relative;
  height: 200px;
  min-width: 0;
  font-family: var(--font-body);
  font-size: var(--type-caption);
  border-bottom: 1px solid var(--rule-hairline);
}

.cw-chart__foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px 20px;
  margin-top: 14px;
}

.cw-chart__peak,
.cw-chart__hint {
  margin: 0;
  font-size: 12.5px;
  font-style: italic;
}

/* ---- funnel: label, count, conversion, proportion bar ---- */
.cw-funnel {
  display: grid;
  grid-template-columns: minmax(84px, auto) 40px 44px minmax(60px, 1fr);
  gap: 10px 12px;
}

.cw-funnel__row {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
  align-items: center;
}

.cw-funnel__label {
  color: var(--text-muted);
  white-space: nowrap;
}

.cw-funnel__value {
  font-size: var(--type-heading);
  text-align: right;
}

.cw-funnel__rate {
  font-size: 11.5px;
  text-align: right;
}

.cw-funnel__track {
  display: block;
  height: 10px;
  background: var(--surface-inset);
  border: var(--border-faint);
}

.cw-funnel__bar {
  display: block;
  height: 100%;
  background: var(--brass-5);
}

/* ---- two-tone proportion bar (checks passed vs failed) ---- */
.cw-ratio-bar {
  display: flex;
  height: 12px;
  background: var(--surface-inset);
  border: var(--border-faint);
}

.cw-ratio-bar__part {
  display: block;
  height: 100%;
}

.cw-ratio-bar__part--good {
  background: var(--green-6);
}

.cw-ratio-bar__part--bad {
  background: var(--oxblood-6);
}

/* ---- a date header inside a table body ---- */
.cw-table__group th {
  padding: 20px 14px 6px;
  text-align: left;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: var(--weight-heading);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-muted);
  border-bottom: 1px solid var(--rule-hairline);
}

/* A muted second line under a cell's own link ("3 files"), as opposed to
   .cw-row-note, which hangs off the right-aligned status column. */
.cw-row-sub {
  display: block;
  margin-top: 3px;
  font-size: 12px;
}

/* Chips that sit in a card head, where the head owns the spacing. */
.cw-filter--flush {
  margin-bottom: 0;
}

/* ---- the Lessons tab ---- */

/* Category and trigger as a kicker over the rule, not two columns beside it
   (see the note above the table in LessonsTab.vue). Wrapping, so a narrow
   Rule column puts the second tag on a line of its own. */
.cw-lesson__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 6px;
}

/* The rule is the row's headline AND the keyboard-reachable way to expand it,
   so it is a button that reads as text.

   Its min-width is the floor under the Rule column. The cell is is-elastic,
   whose one-character min-content is what lets a long rule wrap instead of
   pushing the table out of the card -- and is also what let the column
   collapse to one letter per line once the nowrap columns had taken the
   rest of the width. 200px reads as a sentence, and is wider than the widest
   kicker tag ("Abandoned then merged"), so a tag never breaks mid-word in
   here either; below it the table scrolls (.cw-table-scroll) rather than
   shrinking further. */
.cw-lesson__rule {
  display: block;
  min-width: 200px;
  padding: 0;
  font-family: var(--font-body);
  font-size: var(--type-small);
  font-weight: var(--weight-medium);
  color: var(--text-display);
  text-align: left;
  background: none;
  border: 0;
  cursor: pointer;
}

/* State over scope: side by side the pair is a 170px column, stacked it is
   the wider badge. */
.cw-lesson__badges {
  display: inline-grid;
  gap: 4px;
  justify-items: start;
}

/* The row's two actions, one under the other for the same reason as the
   badges and right-aligned like their cell. Vue's default `whitespace:
   'condense'` deletes the whitespace-only text node between two sibling
   elements, so the gap has to be a real box in any case. */
.cw-lesson__actions {
  display: inline-grid;
  gap: 4px;
  justify-items: end;
}

/* A lesson whose rule is no longer trusted, and one promoted past its own
   repository -- to its stack, or to every repository the account has: the
   three states worth telling apart at a glance. */
.cw-badge--muted {
  color: var(--text-muted);
  background: var(--surface-inset);
  border-color: var(--rule-hairline);
}

.cw-badge--stack {
  color: var(--status-detected);
  background: var(--status-detected-bg);
  border-color: var(--brass-3);
}

/* The rung above stack: the same brass, a shade deeper on a tinted ground,
   so the two upper rungs read as one family with system the stronger. */
.cw-badge--system {
  color: var(--brass-7);
  background: var(--brass-1);
  border-color: var(--brass-5);
}

.cw-lesson__panel {
  background: var(--surface-inset);
}

/* The evidence, side by side: what the person shipped against what Cooper
   tried. Two tracks of equal width, each allowed to shrink below its
   content -- a diff line has no break opportunities, so without minmax(0)
   one long line would push the other column out of the card. */
.cw-lesson__diffs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
}

.cw-lesson__side {
  margin: 0 0 6px;
}

.cw-lesson__diff {
  margin: 0;
  max-height: 320px;
  overflow: auto;
  padding: 10px 12px;
  font-size: 12.5px;
  line-height: 1.6;
  white-space: pre-wrap;
  color: var(--text-body);
  background: var(--surface-page);
  border: var(--border-faint);
}

@media (max-width: 860px) {
  .cw-matter__grid {
    grid-template-columns: 1fr;
  }

  /* Below this the panels are too narrow for a funnel bar and a legend side
     by side, and the headline strip reads better two-up than squeezed. */
  .cw-activity__panels {
    grid-template-columns: minmax(0, 1fr);
  }

  .cw-stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* The CI panel's three figures are one reading, not a strip: they stay
     three-up on a stacked panel, which is wider than a column was. */
  .cw-stats--tight {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  /* Half a card is not enough for a diff line; below this the person's
     excerpt sits above Cooper's rather than beside it. */
  .cw-lesson__diffs {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Below the general rule on purpose: two 170px cells cannot hold
     "Detected → fix PR" and a duration, so the speed pair stacks -- and its
     divider turns from a vertical rule into a horizontal one. */
  .cw-stats--pair {
    grid-template-columns: minmax(0, 1fr);
  }

  .cw-stats--pair .cw-stat {
    border-right: none;
    border-bottom: 1px solid var(--rule-faint);
  }

  .cw-stats--pair .cw-stat:last-child {
    border-bottom: none;
  }

  .cw-stats:not(.cw-stats--tight) .cw-stat:nth-child(2n) {
    border-right: none;
  }

  .cw-header__inner,
  .cw-main,
  .cw-footer__inner {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }

  .cw-header__inner {
    gap: 24px;
  }

  /* Six tabs and their counts do not fit one line, and wrapping them was
     the first answer: it cost three rows of the screen before any content
     began, on every dashboard and admin page. One row that scrolls sideways
     costs one. The bar keeps its own overflow, which is also what keeps it
     out of the page's overflow -- a scroll container is allowed to be wider
     than the phone, exactly as the table wrappers are.

     No scrollbar is drawn: a phone overlays its own and takes no width for
     it, while a desktop browser narrowed past 860px would otherwise get a
     permanent grey bar under the tabs. */
  .cw-tabs {
    flex-wrap: nowrap;
    gap: 0 22px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
    /* The one cue that there is more to the right. With the scrollbar
       hidden, a tab clipped by the edge is the only other hint, and a tab
       that happens to end near the edge gives none at all. The mask fades
       the last few pixels instead, and is dropped once the bar is scrolled
       to its end so the final tab is not left permanently dimmed. */
    mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
  }

  .cw-tabs::-webkit-scrollbar {
    display: none;
  }

  /* Tabs must keep their own width: left to flex they would each shrink to
     fit, which is how a scrollable bar turns back into a squeezed one. */
  .cw-tabs a {
    padding-top: 8px;
    flex: 0 0 auto;
    white-space: nowrap;
    scroll-snap-align: start;
  }

  .cw-tabs a.is-trailing {
    margin-left: 0;
  }

  /* Tighter cells and a smaller, less tracked column head, so the
     six-column PR table fits a tablet without a scrollbar (with the shorter
     caps on .cw-branch and .cw-row-note, set beside their own rules further
     down): "ATTEMPTS" in full small caps is a 100px column for a single
     digit. */
  .cw-table thead th,
  .cw-table tbody td {
    padding-left: 10px;
    padding-right: 10px;
  }

  .cw-table thead th {
    font-size: 11.5px;
    letter-spacing: 0.1em;
  }

  .cw-retain-form {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .cw-retain-form__half,
  .cw-retain-form__third {
    grid-column: span 1;
  }

  /* Five fields in two columns leaves Stack alone on the last row; let it
     take the full width instead of sitting as an orphan. */
  .cw-retain-form__stack {
    grid-column: span 2;
  }
}

/* ---- phones ----
   One column of everything. The display sizes step down through the tokens
   rather than rule by rule, so a page head, a hero, a headline figure and a
   closing banner all shrink together. */
@media (max-width: 560px) {
  :root {
    --type-display-1: 34px;
    --type-display-2: 28px;
    --type-title: 23px;
    --type-heading: 19px;
  }

  /* The heading is clamped here, not shrunk. An incident or PR title is the
     customer's own exception message, and Sentry's routinely carry a compare
     URL -- a hundred characters with nowhere to break -- which unclamped
     runs to nine lines at 360px. Shrinking the type was tried first and
     bought one line out of nine, so it went back.

     Only the BOX is clipped. The full title stays in the DOM, so it is still
     selected, searched, and read aloud in full by a screen reader; what is
     lost is the sighted phone reader's view of the tail, which is the
     accepted cost of three lines of heading over nine of shattered URL. */
  .cw-matter h1 {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    overflow: hidden;
  }

  /* The header becomes two rows: wordmark, login and sign-out on the first,
     the nav on its own line beneath -- every control stays on the page. */
  .cw-header__inner {
    flex-wrap: wrap;
    height: auto;
    padding-top: 10px;
    padding-bottom: 6px;
    gap: 0 16px;
  }

  .cw-header .cw-wordmark {
    font-size: 20px;
  }

  .cw-header__nav {
    order: 3;
    flex-basis: 100%;
    gap: 22px;
  }

  /* A basis of zero, so the login never asks the wrapping row for its full
     width (a wrapping flex line breaks before it shrinks anything): it
     takes whatever is left between the wordmark and Sign out, and shows an
     ellipsis when that is not enough. */
  .cw-header__user {
    flex: 1 1 0;
    text-align: right;
  }

  .cw-main {
    padding-top: var(--space-5);
    padding-bottom: var(--space-7);
  }

  .cw-pagehead {
    margin-bottom: 18px;
  }

  .cw-card {
    padding: 20px 16px;
  }

  .cw-card__head {
    padding-bottom: 12px;
    margin-bottom: 14px;
  }

  .cw-empty {
    padding: 20px 16px;
  }

  .cw-btn--lg {
    padding-left: 20px;
    padding-right: 20px;
  }

  /* A button whose label wraps needs its lines apart; 1 is right only for
     the one-line button the wide layouts always have room for. */
  .cw-btn {
    line-height: 1.25;
  }

  /* A step as a small grid: the mark, then everything else in one column
     beside it, the label on the first line and the timestamp (or the
     "required" tag) on its own line beneath, right-aligned. A wrapping flex
     row put the label on a line of its own under a lonely mark instead. */
  .cw-timeline__step {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: 12px;
  }

  .cw-timeline__step > :nth-child(n + 3) {
    grid-column: 2;
  }

  .cw-timeline__time {
    justify-self: end;
    margin-left: 0;
    white-space: nowrap;
  }

  /* The mapping page's lists have no mark: a title that wraps, then its
     badge. The badge's track is `auto`, never the flexible one -- a grid
     item in a minmax(0, 1fr) track has no automatic minimum, and the badge
     was squeezed to its padding with its nowrap text running off the
     phone. */
  .cw-activity-list .cw-timeline__step {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  /* A funnel row is label, count and rate on one line with the bar beneath:
     four tracks across need 264px, and a panel here has about 250. */
  .cw-funnel {
    grid-template-columns: minmax(0, 1fr) auto auto;
    gap: 6px 12px;
  }

  .cw-funnel__track {
    grid-column: 1 / -1;
  }

  /* The CI panel's three figures as a list, each label beside its number:
     three-up they were 80px cells, too narrow for "Abandoned" in small
     caps. (The 860px rule above kept them three-up on the grounds that a
     stacked panel is wide; a phone's is not.) */
  .cw-stats--tight {
    grid-template-columns: minmax(0, 1fr);
  }

  .cw-stats--tight .cw-stat {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 0;
    border-right: none;
    border-bottom: 1px solid var(--rule-faint);
  }

  .cw-stats--tight .cw-stat:last-child {
    border-bottom: none;
  }

  .cw-stats--tight .cw-stat__value {
    margin: 0;
  }

  /* The settings stack's sub-setting keeps a visible indent, just not the
     switch-width one, which is a fifth of a phone. */
  .cw-settings-row__sub {
    margin-left: 22px;
  }

  .cw-settings-row__control .cw-select {
    max-width: 14em;
  }

  /* The mapping form is one column. `span 1` on Stack, not the tablet's
     `span 2`: a span past the last explicit column makes the grid grow an
     implicit one, and the whole form went two-up again with its labels
     overprinting each other. */
  .cw-retain-form {
    grid-template-columns: minmax(0, 1fr);
  }

  .cw-retain-form__stack {
    grid-column: span 1;
  }

  /* Each option on its own line; the merge-gate select fills what is left
     beside its label instead of insisting on 200px it does not have. */
  .cw-retain-form__options {
    gap: 10px;
  }

  .cw-retain-form__options .cw-check-row {
    display: flex;
    flex-wrap: wrap;
    width: 100%;
  }

  .cw-select--compact {
    min-width: 0;
    flex: 1 1 10em;
  }

  .cw-signin {
    padding: var(--space-5) var(--space-4);
  }

  .cw-signin__wordmark {
    font-size: 40px;
  }

  .cw-signin__card {
    padding: 28px 20px;
  }

  .cw-modal {
    padding: 22px 18px 20px;
  }

  .cw-modal__actions {
    flex-wrap: wrap;
  }
}

/* ==========================================================================
   Marketing page — same firm, same paper, wider room to make the pitch.
   ========================================================================== */

.cw-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 4px 12px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--text-muted);
  background: var(--surface-card);
  border: var(--border-faint);
}

.cw-pill__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
}

.cw-pill__dot--rails {
  background: #b33b1e;
}

.cw-pill__dot--laravel {
  background: #3b5bdb;
}

.cw-pill__dot--fastapi {
  background: var(--green-6);
}

.cw-pill__dot--sentry {
  background: var(--brass-5);
}

.cw-section {
  padding: var(--space-9) 0;
  border-bottom: var(--border-hairline);
}

.cw-section:last-of-type {
  border-bottom: none;
}

.cw-section__over {
  color: var(--text-accent);
  margin-bottom: 10px;
}

.cw-section__title {
  font-size: var(--type-display-2);
  margin: 0 0 10px;
}

.cw-section__lead {
  font-family: var(--font-body);
  font-size: var(--type-body);
  color: var(--text-muted);
  max-width: 56ch;
  margin: 0;
}

.cw-section__title .amp {
  color: var(--brass-6);
}

/* ---- hero ---- */
.cw-hero {
  padding: var(--space-9) 0 var(--space-8);
}

.cw-hero__inner {
  max-width: 62ch;
}

.cw-hero__over {
  color: var(--text-accent);
  margin-bottom: 16px;
}

.cw-hero h1 {
  font-size: var(--type-display-1);
  margin: 0 0 20px;
  max-width: 20ch;
}

.cw-hero h1 .amp {
  color: var(--brass-6);
}

.cw-hero__lead {
  font-family: var(--font-body);
  font-size: 19px;
  line-height: 1.6;
  color: var(--text-body);
  max-width: 52ch;
  margin: 0 0 30px;
}

.cw-hero__actions {
  display: flex;
  align-items: center;
  gap: 22px;
  flex-wrap: wrap;
  margin-bottom: 26px;
}

.cw-hero__actions form {
  margin: 0;
}

.cw-hero__pills {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

/* ---- exhibits (before/after) ---- */
.cw-exhibits {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 20px;
  align-items: stretch;
  margin-top: 36px;
}

.cw-exhibits__arrow {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  color: var(--text-accent);
}

.cw-exhibits__arrow-mark {
  font-family: var(--font-display);
  font-size: 26px;
}

.cw-exhibits__caption {
  font-size: 13.5px;
  font-style: italic;
  color: var(--text-muted);
  text-align: center;
  margin-top: 22px;
}

/* ---- how it works ---- */
.cw-steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  margin-top: 34px;
  border-top: var(--border-hairline);
}

.cw-step {
  padding: 26px 28px 0 10px;
  border-right: var(--border-hairline);
}

.cw-step:last-child {
  border-right: none;
}

.cw-step__num {
  font-family: var(--font-display);
  font-size: 30px;
  color: var(--brass-3);
  line-height: 1;
  margin-bottom: 14px;
}

.cw-step h3 {
  font-size: var(--type-heading);
  margin-bottom: 10px;
}

.cw-step p {
  font-family: var(--font-body);
  font-size: 14.5px;
  color: var(--text-muted);
  line-height: 1.6;
  margin: 0;
}

.cw-note {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-top: 34px;
  padding: 14px 20px;
  background: var(--green-1);
  border: 1px solid var(--green-3);
  color: var(--green-7);
  font-size: 14px;
  max-width: 60ch;
}

.cw-note::before {
  content: '✓';
  font-size: 14px;
}

/* ---- social proof ---- */
.cw-built-for {
  display: flex;
  align-items: center;
  gap: 22px;
  flex-wrap: wrap;
  margin-top: 20px;
}

/* ---- pricing (retainers) ---- */
.cw-retainers {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  margin-top: 34px;
}

.cw-retainer {
  background: var(--surface-card);
  border: var(--border-hairline);
  box-shadow: var(--shadow-card);
  padding: 30px 28px;
  position: relative;
  display: flex;
  flex-direction: column;
}

.cw-retainer--featured {
  border-color: var(--brass-5);
  box-shadow: var(--shadow-raised);
}

.cw-retainer__badge {
  position: absolute;
  top: -12px;
  left: 30px;
  background: var(--green-8);
  color: var(--paper-2);
  font-family: var(--font-body);
  font-size: 11px;
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  padding: 4px 12px;
}

.cw-retainer__tier {
  color: var(--text-accent);
  margin-bottom: 10px;
}

.cw-retainer__price {
  font-family: var(--font-display);
  font-size: 38px;
  font-weight: 600;
  color: var(--text-display);
}

.cw-retainer__period {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-muted);
  margin-left: 4px;
}

.cw-retainer__desc {
  font-family: var(--font-body);
  font-size: 13.5px;
  color: var(--text-muted);
  margin: 8px 0 22px;
  flex: 1;
}

.cw-retainer form {
  margin: 0;
}

/* ---- faq ---- */
.cw-faq-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 30px 48px;
  margin-top: 30px;
}

.cw-faq-item h4 {
  font-size: 16px;
  margin-bottom: 8px;
}

.cw-faq-item p {
  font-family: var(--font-body);
  font-size: 14.5px;
  color: var(--text-muted);
  line-height: 1.65;
  margin: 0;
}

/* ---- closing banner ---- */
.cw-closing {
  background: var(--surface-inverse);
  color: var(--paper-2);
  padding: var(--space-9) 0;
  text-align: center;
}

.cw-closing__inner {
  max-width: 60ch;
  margin: 0 auto;
}

.cw-closing__over {
  color: var(--brass-3);
  margin-bottom: 16px;
}

.cw-closing h2 {
  font-size: var(--type-display-1);
  color: var(--paper-2);
  margin: 0 0 14px;
}

.cw-closing h2 .amp {
  color: var(--brass-3);
}

.cw-closing p {
  font-family: var(--font-body);
  font-size: 16px;
  color: var(--green-3);
  margin: 0 0 30px;
}

.cw-closing form {
  display: inline-block;
  margin: 0;
}

/* ---- the second half of the claim ----
   Inside the h1, not under it: "we file the fix" and "we stay on the PR" are
   one sentence's worth of promise, and the second half is the one a
   per-issue fixer cannot make. A size down and in italic, so the brand line
   keeps the top billing it always had. */
.cw-hero__then {
  display: block;
  margin-top: 14px;
  font-size: var(--type-display-2);
  font-style: italic;
  font-weight: 500;
  color: var(--text-body);
}

/* ---- the arc in the hero card ----
   The incident page's own timeline rows under the docket's facts, so the
   card shows the whole arc rather than ending at "PR opened". */
.cw-mkt-hero__timeline {
  margin-top: 4px;
  padding-top: 4px;
  border-top: var(--border-double);
}

.cw-mkt-hero__timeline .cw-timeline__step {
  padding: 7px 0;
}

/* ---- loop dockets ----
   Each loop is three labelled rows -- what it watches, does, and where it
   stops -- rather than a paragraph, because the stopping place is the
   difference between the three and the thing a paragraph buries. */
.cw-step__facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 10px 14px;
  margin: 0;
}

.cw-step__facts dt {
  padding-top: 3px;
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-accent);
}

.cw-step__facts dd {
  margin: 0;
  font-family: var(--font-body);
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--text-muted);
}

/* ---- one incident (the arc) ----
   The timeline card takes the wider track; the two diffs it ends by
   comparing stack beside it. */
.cw-arc {
  display: grid;
  grid-template-columns: 1.2fr 0.8fr;
  gap: 20px;
  align-items: start;
  margin-top: 36px;
}

.cw-arc__side {
  display: grid;
  gap: 20px;
}

/* The incident page's diff lines are pre-wrap for the whitespace a real
   patch carries. These two are typed into the template, where the markup's
   own indentation would otherwise render as part of the code. */
.cw-arc .cw-diff__line {
  white-space: normal;
}

/* ---- lessons ----
   The lesson in the Lessons tab's shape (rule over summary, tags under),
   and the ladder it climbs as a ruled list: the section has to show what a
   lesson looks like before it explains where one goes. */
.cw-lessons {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 40px;
  align-items: start;
  margin-top: 36px;
}

.cw-lesson-example__rule {
  margin: 0 0 10px;
  font-family: var(--font-body);
  font-size: 17px;
  font-weight: 600;
  line-height: 1.45;
  color: var(--text-display);
}

.cw-lesson-example__summary {
  margin: 0 0 14px;
  font-family: var(--font-body);
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--text-muted);
}

.cw-lesson-example__tags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.cw-ladder {
  margin: 0;
  border-top: var(--border-hairline);
}

.cw-ladder dt {
  padding-top: 16px;
  font-family: var(--font-display);
  font-size: var(--type-heading);
  font-weight: 600;
  color: var(--text-display);
}

.cw-ladder dd {
  margin: 6px 0 0;
  padding-bottom: 16px;
  font-family: var(--font-body);
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--text-muted);
  border-bottom: var(--border-hairline);
}

/* ---- compared with Seer ----
   Two columns of scope, one difference per row. The head row is decoration
   for the wide layout; on a phone each cell names its column itself
   (data-who), so the row still reads when the two columns become one. */
.cw-compare {
  margin-top: 36px;
  border-top: var(--border-double);
}

.cw-compare__head,
.cw-compare__row {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 16px;
}

.cw-compare__head {
  padding: 10px 0;
  border-bottom: var(--border-hairline);
}

.cw-compare__head .cw-label:first-child {
  grid-column: 2;
}

.cw-compare__rows {
  margin: 0;
}

.cw-compare__row {
  padding: 14px 0;
  border-bottom: var(--border-hairline);
}

.cw-compare__row dt {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 600;
  color: var(--text-display);
}

.cw-compare__row dd {
  margin: 0;
  font-family: var(--font-body);
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--text-muted);
}

.cw-compare__row dd:last-child {
  color: var(--text-body);
}

.cw-compare__row dd::before {
  display: none;
  content: attr(data-who);
  margin-bottom: 2px;
  font-size: 11px;
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-accent);
}

/* ---- pricing: the beta panel ----
   The only price that is true today sits above the planned tiers, on the
   featured tier's brass rule, with its button beside the copy. */
.cw-beta {
  margin-top: 34px;
  border-color: var(--brass-5);
  box-shadow: var(--shadow-raised);
}

.cw-beta__body {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 20px 32px;
}

.cw-beta__lead {
  margin: 0;
  max-width: 58ch;
  font-family: var(--font-body);
  font-size: var(--type-body);
  line-height: 1.6;
  color: var(--text-body);
}

.cw-beta form {
  margin: 0;
}

.cw-retainers__over {
  margin-top: 44px;
  color: var(--text-accent);
}

.cw-retainers__over + .cw-retainers {
  margin-top: 20px;
}

@media (max-width: 860px) {
  .cw-exhibits,
  .cw-arc,
  .cw-lessons {
    grid-template-columns: 1fr;
  }

  .cw-exhibits__arrow {
    flex-direction: row;
    padding: 8px 0;
  }

  .cw-steps {
    grid-template-columns: 1fr;
  }

  .cw-step {
    border-right: none;
    border-bottom: var(--border-hairline);
    padding-bottom: 26px;
  }

  .cw-step:last-child {
    border-bottom: none;
  }

  .cw-retainers {
    grid-template-columns: 1fr;
  }

  .cw-faq-grid {
    grid-template-columns: 1fr;
  }
}

/* ==========================================================================
   marketing — nav band, page container, masthead & big footer (cw-mkt-*)
   Layout scaffolding for the public landing page. Component-level marketing
   classes (.cw-hero/.cw-section/.cw-exhibits/.cw-steps/.cw-retainers …) live
   above; these bookend them with the letterhead chrome.
   ========================================================================== */

/* ---- top nav band (logged-out masthead) ---- */
.cw-mkt-nav {
  background: var(--surface-inverse);
  color: var(--text-on-inverse);
  border-bottom: 1px solid var(--green-7);
}

.cw-mkt-nav__inner {
  max-width: var(--page-max-width);
  margin: 0 auto;
  padding: 0 var(--space-6);
  height: 70px;
  display: flex;
  align-items: center;
  gap: var(--space-7);
}

.cw-mkt-nav__brand {
  display: inline-flex;
  flex-direction: column;
  gap: 3px;
  text-decoration: none;
}

.cw-mkt-nav__brand .cw-wordmark {
  font-size: 23px;
}

.cw-mkt-nav__brand .cw-label {
  color: var(--brass-3);
  font-size: 10px;
  letter-spacing: 0.18em;
}

.cw-mkt-nav__links {
  display: flex;
  gap: var(--space-6);
  flex: 1;
}

.cw-mkt-nav__links a {
  font-family: var(--font-body);
  font-size: var(--type-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--paper-2);
  text-decoration: none;
  padding-bottom: 3px;
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur-med) var(--ease-out);
}

.cw-mkt-nav__links a:hover {
  border-bottom-color: var(--brass-5);
  color: var(--paper-2);
}

.cw-mkt-nav__cta {
  display: flex;
  align-items: center;
  gap: var(--space-5);
}

.cw-mkt-nav__cta form {
  margin: 0;
}

.cw-mkt-nav__signin {
  color: var(--brass-3);
  text-decoration: none;
  font-family: var(--font-body);
  font-size: var(--type-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
}

.cw-mkt-nav__signin:hover {
  color: var(--brass-1);
}

.cw-mkt-nav__cta .cw-btn--primary {
  border-color: var(--brass-5);
  background: var(--green-7);
}

.cw-mkt-nav__cta .cw-btn--primary:hover {
  background: var(--brass-6);
  color: var(--green-9);
  border-color: var(--brass-6);
}

/* ---- page container ---- */
.cw-mkt {
  max-width: var(--page-max-width);
  margin: 0 auto;
  padding: 0 var(--space-6);
}

/* ---- hero masthead caption line (a brief's caption) ---- */
.cw-mkt-caption {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
  padding: 14px 0;
  border-top: var(--border-double);
  border-bottom: var(--border-hairline);
  color: var(--text-muted);
  margin-bottom: var(--space-7);
}

.cw-mkt-caption .cw-label {
  color: var(--text-muted);
}

.cw-mkt-caption__sep {
  color: var(--brass-5);
}

/* ---- hero two-column (pitch + docket card) ---- */
.cw-mkt-hero {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: var(--space-8);
  align-items: start;
}

.cw-mkt-hero__aside {
  border: var(--border-hairline);
  background: var(--surface-card);
  box-shadow: var(--shadow-card);
  padding: 26px 28px;
}

.cw-mkt-hero__aside-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding-bottom: 12px;
  margin-bottom: 16px;
  border-bottom: var(--border-double);
}

.cw-mkt-hero__filed {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--text-muted);
}

.cw-mkt-hero__row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  padding: 11px 0;
  border-bottom: 1px solid var(--rule-faint);
}

.cw-mkt-hero__row:last-child {
  border-bottom: none;
}

.cw-mkt-hero__row .cw-mono {
  color: var(--text-body);
  font-size: 12.5px;
}

.cw-mkt-hero__row-label {
  font-family: var(--font-body);
  font-size: 13.5px;
  color: var(--text-muted);
  font-style: italic;
}

/* ---- big footer band ---- */
.cw-mkt-footer {
  background: var(--surface-inverse);
  color: var(--green-3);
  padding: var(--space-8) 0 var(--space-6);
}

.cw-mkt-footer__inner {
  max-width: var(--page-max-width);
  margin: 0 auto;
  padding: 0 var(--space-6);
}

.cw-mkt-footer__top {
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr;
  gap: var(--space-7);
  padding-bottom: var(--space-6);
  border-bottom: 1px solid var(--green-7);
}

.cw-mkt-footer__brand .cw-wordmark {
  font-size: 26px;
}

.cw-mkt-footer__blurb {
  font-family: var(--font-body);
  font-size: 14px;
  font-style: italic;
  color: var(--green-3);
  margin: 14px 0 0;
  max-width: 34ch;
  line-height: 1.6;
}

.cw-mkt-footer__col h4 {
  font-family: var(--font-body);
  font-size: var(--type-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--brass-3);
  margin: 0 0 16px;
}

.cw-mkt-footer__col ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 11px;
}

.cw-mkt-footer__col a {
  color: var(--paper-2);
  text-decoration: none;
  font-size: 14.5px;
}

.cw-mkt-footer__col a:hover {
  color: var(--brass-3);
}

.cw-mkt-footer__base {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-5);
  padding-top: 20px;
  font-size: 13px;
  font-style: italic;
  color: var(--green-3);
  flex-wrap: wrap;
}

.cw-mkt-footer__base .amp {
  color: var(--brass-3);
  font-style: normal;
}

@media (max-width: 860px) {
  .cw-mkt-hero {
    grid-template-columns: 1fr;
  }

  /* The band follows the reader. The home page is 11,885px on a phone and
     /docs is longer still, and these section links are the only way around
     either of them. */
  .cw-mkt-nav {
    position: sticky;
    top: 0;
    z-index: 20;
  }

  /* These links were display:none here. That is the usual mobile move, and
     it is usually paired with a hamburger -- but there is no hamburger in
     this app, so the effect was simply that a phone had no way to reach How
     it works, Demo, vs Seer or Pricing at all. They come back as a row that
     scrolls, the same answer as the dashboard tabs and the docs contents.

     min-width: 0 from the start: a nowrap row inside a flex parent is the
     exact shape that blew the docs grid track out to 1287px, because a flex
     item will not shrink below its content unless told it may. */
  .cw-mkt-nav__links {
    display: flex;
    flex-wrap: nowrap;
    min-width: 0;
    flex: 1 1 100%;
    gap: var(--space-5);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
  }

  .cw-mkt-nav__links::-webkit-scrollbar {
    display: none;
  }

  .cw-mkt-nav__links a {
    flex: 0 0 auto;
    white-space: nowrap;
  }

  .cw-mkt-footer__top {
    grid-template-columns: 1fr;
    gap: var(--space-6);
  }

  .cw-mkt,
  .cw-mkt-nav__inner,
  .cw-mkt-footer__inner {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }

  .cw-mkt-nav__inner {
    gap: var(--space-5);
  }
}

/* Phones: the nav band wraps its call to action under the brand when the
   two will not share a line, the bands lose most of their vertical air,
   and the exhibits' mono lines -- a controller path, a diff line -- break
   inside the card instead of widening it. */
@media (max-width: 560px) {
  /* The contents list follows the shorter band at this width. */
  .cw-docs-toc {
    top: 56px;
  }

  .cw-mkt-nav__inner {
    flex-wrap: wrap;
    justify-content: space-between;
    height: auto;
    min-height: 56px;
    padding-top: 10px;
    padding-bottom: 10px;
    gap: 8px 16px;
  }

  .cw-mkt-nav__brand .cw-wordmark {
    font-size: 20px;
  }

  .cw-mkt-nav__cta {
    margin-left: auto;
    gap: var(--space-4);
  }

  .cw-hero {
    padding: var(--space-6) 0 var(--space-6);
  }

  .cw-mkt-caption {
    margin-bottom: var(--space-6);
  }

  .cw-section {
    padding: var(--space-7) 0;
  }

  .cw-closing {
    padding: var(--space-7) 0;
  }

  .cw-mkt-footer {
    padding-top: var(--space-7);
  }

  .cw-exhibits .cw-mono {
    overflow-wrap: anywhere;
  }

  .cw-mkt-hero__aside,
  .cw-retainer {
    padding: 22px 18px;
  }

  /* The comparison's two columns become one: the head row goes, and each
     cell names its column itself. */
  .cw-compare__head {
    display: none;
  }

  .cw-compare__row {
    grid-template-columns: 1fr;
    gap: 10px;
  }

  .cw-compare__row dd::before {
    display: block;
  }

  /* The product's phone rule drops a step's timestamp under its label,
     because a label there can be a whole check name. The labels on this
     page are the short ones, so the time keeps the label's line. */
  .cw-mkt .cw-timeline__step {
    grid-template-columns: auto minmax(0, 1fr) auto;
  }

  .cw-mkt .cw-timeline__time {
    grid-column: 3;
    align-self: baseline;
  }
}

/* ==========================================================================
   Documentation page (cw-docs-*). The marketing page's paper and pieces --
   section eyebrow and lead, the loop dockets' <dl>, the docket table, the
   ladder -- laid out as a reference rather than a pitch. The one new piece
   is the table of contents: it stays put on the left while the sections
   scroll past on the right, and on a phone, where there is no room beside
   the text, it becomes a plain list above it.
   ========================================================================== */
.cw-docs__head {
  padding: var(--space-8) 0 var(--space-6);
  border-bottom: var(--border-double);
}

.cw-docs__head h1 {
  font-size: var(--type-display-1);
  margin: 0 0 12px;
}

.cw-docs__grid {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  gap: var(--space-8);
  align-items: start;
}

.cw-docs-toc {
  position: sticky;
  top: var(--space-5);
  padding-top: var(--space-7);
}

.cw-docs-toc .cw-label {
  color: var(--text-accent);
  margin-bottom: 10px;
}

/* Numbered by CSS rather than by the list itself, so the number can sit in
   the mono face and the brass the rest of the page uses for its counters. */
.cw-docs-toc ol {
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: toc;
  border-top: var(--border-hairline);
}

.cw-docs-toc li {
  counter-increment: toc;
  border-bottom: 1px solid var(--rule-faint);
}

.cw-docs-toc a {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 8px 0;
  font-size: var(--type-small);
  color: var(--text-body);
  text-decoration: none;
}

.cw-docs-toc a::before {
  content: counter(toc, decimal-leading-zero);
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-accent);
}

.cw-docs-toc a:hover {
  color: var(--green-9);
  text-decoration: underline;
}

/* min-width: 0 so a table wider than the column scrolls inside its
   .cw-table-scroll rather than widening the grid track and the page. */
.cw-docs__body {
  min-width: 0;
}

.cw-docs-section {
  padding: var(--space-7) 0;
  border-bottom: var(--border-hairline);
}

.cw-docs-section:last-child {
  border-bottom: none;
}

.cw-docs-section__title {
  font-size: var(--type-display-2);
  margin: 0 0 16px;
}

.cw-docs-section h3 {
  font-size: var(--type-heading);
  margin: 30px 0 8px;
}

/* Reference prose holds to the body measure; tables and dockets may run the
   column's full width. */
.cw-docs-section p,
.cw-docs-section ul,
.cw-docs-section .cw-step__facts {
  max-width: var(--content-measure);
}

.cw-docs-section p {
  margin: 0 0 14px;
}

.cw-docs-section ul {
  margin: 0 0 14px;
  padding-left: 22px;
}

.cw-docs-section li {
  margin-bottom: 6px;
}

.cw-docs-section .cw-step__facts {
  margin: 14px 0 20px;
}

.cw-docs-section .cw-step__facts dd {
  color: var(--text-body);
}

.cw-docs-section .cw-table-scroll {
  margin: 14px 0 20px;
}

.cw-docs-section .cw-table tbody td {
  vertical-align: top;
}

/* A code block: the mono face on the inset paper, wrapped rather than
   scrolled, because the one thing in it is a URL a reader has to see whole
   on a phone. */
.cw-docs-section pre.cw-mono {
  margin: 0 0 14px;
  padding: 12px 16px;
  max-width: var(--content-measure);
  background: var(--surface-inset);
  border: var(--border-faint);
  color: var(--text-body);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.cw-docs-section pre.cw-mono a {
  text-decoration-color: var(--rule-brass);
}

.cw-docs-section .cw-ladder ul {
  margin: 0;
  padding-left: 20px;
}

.cw-docs-section .cw-ladder dd {
  color: var(--text-body);
}

/* The section's own rule closes the ladder; the last entry's would double it. */
.cw-docs-section .cw-ladder dd:last-child {
  border-bottom: none;
}

.cw-docs-section .cw-hero__actions {
  margin: 20px 0 0;
}

@media (max-width: 860px) {
  .cw-docs__grid {
    grid-template-columns: 1fr;
    gap: 0;
  }

  /* The contents list stays with the reader. It was made static here, which
     on the longest page of the site -- /docs runs past 14,000px on a phone
     -- meant the only way back scrolled away after the first screen and
     never returned. Sticky costs a strip of the screen; being lost in a
     document seventeen screens tall costs more.

     It stays one line tall (see the list below), so the strip it costs is a
     strip and not a third of the screen. Capping its height instead was the
     first attempt and it read badly: a box showing four of twelve entries,
     scrolling inside a page that also scrolls. Given the page's own
     background so the prose does not read through it while it is stuck. */
  .cw-docs-toc {
    position: sticky;
    /* Below the band, not under it: the nav is sticky too now, and is 70px
       tall at this width (56px on a phone, see the 560 block). */
    top: 70px;
    z-index: 2;
    /* This is a grid item, and a grid item's min-width is `auto`: it will
       not shrink below the intrinsic width of its contents. A nowrap row of
       twelve entries is over 1200px of intrinsic width, so without this the
       track grows to fit it and takes the whole page -- prose and all --
       sideways with it, and the list's own overflow-x never gets a chance
       because its parent was already sized to the content. */
    min-width: 0;
    background: var(--surface-page);
    padding-top: var(--space-6);
    padding-bottom: var(--space-4);
    border-bottom: var(--border-hairline);
  }

  /* Twelve entries become one swipeable line rather than a column: the same
     answer as the tab bar above, for the same reason. A list this long
     cannot be both complete and short stacked vertically, and stacked is
     what pushed the prose off the first screen. */
  .cw-docs-toc ol {
    display: flex;
    flex-wrap: nowrap;
    min-width: 0;
    gap: 0 var(--space-5);
    margin: 0;
    padding: 0;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
  }

  .cw-docs-toc ol::-webkit-scrollbar {
    display: none;
  }

  .cw-docs-toc li {
    flex: 0 0 auto;
    white-space: nowrap;
  }
}

@media (max-width: 560px) {
  .cw-docs__head {
    padding-top: var(--space-6);
  }

  .cw-docs__head h1 {
    font-size: var(--type-display-2);
  }

  .cw-docs-toc ol {
    columns: 1;
  }

  .cw-docs-section {
    padding: var(--space-6) 0;
  }

  .cw-docs-section .cw-step__facts {
    grid-template-columns: 1fr;
    gap: 4px 0;
  }

  .cw-docs-section .cw-step__facts dd {
    margin-bottom: 10px;
  }

  /* The reference tables' first column names the row (a field, a
     permission, a switch), so in the phone docket it is the headline, not a
     labelled line -- the product tables do this through .is-remainder, whose
     wide-layout width these tables do not want. */
  .cw-docs-section .cw-table--stack tbody td:first-child {
    padding-left: 0;
    padding-bottom: 6px;
    font-size: var(--type-body);
    font-weight: var(--weight-medium);
    color: var(--text-display);
  }

  .cw-docs-section .cw-table--stack tbody td:first-child::before {
    display: none;
  }
}

/* ---- modal (native <dialog>, opened by the Vue islands) ---- */
.cw-modal {
  width: min(520px, calc(100vw - 32px));
  padding: 28px 32px 24px;
  border: var(--border-hairline);
  background: var(--surface-raised);
  color: var(--text-body);
  box-shadow: var(--shadow-modal);
}

.cw-modal::backdrop {
  background: rgba(15, 35, 28, 0.45);
}

.cw-modal__close {
  position: absolute;
  top: 10px;
  right: 14px;
  background: none;
  border: 0;
  font-size: 22px;
  line-height: 1;
  color: var(--text-muted);
  cursor: pointer;
}

.cw-modal__title {
  margin: 0 0 12px;
  font-family: var(--font-display);
  font-size: 22px;
  color: var(--text-display);
}

.cw-modal__body {
  margin: 0 0 20px;
  font-size: var(--type-small);
  line-height: 1.5;
}

.cw-modal__actions {
  display: flex;
  gap: 18px;
  align-items: center;
}

/* Branch names can run long (Dependabot's especially); cap the column and
   let the title attribute carry the full name. */
.cw-branch {
  display: inline-block;
  max-width: 30ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}

/* A card head that carries an action button (or a row of chips) on the
   right -- and under the title once the two no longer fit side by side. */
.cw-card__head--actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 16px;
}

/* One-line note under a status badge (the PR's last outcome). */
.cw-row-note {
  display: block;
  max-width: 26ch;
  margin-left: auto;
  margin-top: 4px;
  font-size: 12px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A self-improvement run's reason, under its outcome badge. Deliberately
   NOT .cw-row-note above: that clamp exists because a watched PR's last
   outcome is a footnote to its status, whereas here the reason IS the row --
   why Cooper refused, or the error it died on -- and a reason you cannot
   read is a row that says nothing. So: wrapped in full, and broken mid-token
   where it has to be, since these carry file paths and backtrace lines. */
.cw-run-reason {
  display: block;
  max-width: 62ch;
  margin-top: 4px;
  font-size: 12px;
  color: var(--text-muted);
  white-space: normal;
  overflow-wrap: anywhere;
}

/* What else a run left behind, under its issue: the pull request it opened
   and the warning that the patch touches a migration. */
.cw-run-links {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 12px;
  margin-top: 4px;
  font-size: 12px;
}

.cw-run-flag {
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* Shorter caps on a tablet, where the PR table's six columns have about
   690px between them: the title attribute still carries the whole branch
   and the whole reason. Here, after the two rules above, because an
   earlier rule of the same weight would lose to them. */
@media (max-width: 860px) {
  .cw-branch {
    max-width: 16ch;
  }

  .cw-row-note {
    max-width: 16ch;
  }
}

/* Billing page opt-in card body: copy on the left, badge + switch on the right. */
.cw-optin {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  padding: 22px 24px;
}

.cw-optin__copy {
  max-width: 52ch;
}

.cw-optin__control {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 12px;
}

/* A link that opens a GitHub resource in a new tab: text (optional) plus a
   small boxed arrow glyph, used for repo/branch cells in the dashboard
   tables. */
.cw-extlink {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

.cw-extlink__glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 15px;
  font-size: 10px;
  line-height: 1;
  color: var(--text-muted);
  background: var(--surface-inset);
  border: var(--border-faint);
  flex-shrink: 0;
}

.cw-extlink:hover .cw-extlink__glyph {
  color: var(--text-body);
  border-color: var(--brass-3);
}

/* ==========================================================================
   Touch targets. On a phone, or on anything driven by a finger, every
   control a person has to hit measures at least 44px both ways (the AAA
   figure; test/system/responsive_layout_test.rb holds the page to it), and
   the two small secondary affordances -- a checkbox, an external-link
   glyph -- at least 24px. The visible weight stays what it was: the extra
   is padding, or a min-height on an inline-flex box, never a bigger glyph.
   The header links swap their border-bottom underline for a text underline
   here, because a border sits at the bottom of the (now 44px) box, a long
   way under the word.
   ========================================================================== */
@media (max-width: 560px), (pointer: coarse) {
  .cw-btn {
    min-height: 44px;
  }

  .cw-tabs a {
    min-height: 44px;
    padding-top: 10px;
  }

  .cw-header__nav a,
  .cw-header__signout-btn,
  .cw-mkt-nav__signin,
  .cw-mkt-nav__links a,
  .cw-mkt-footer__col a,
  .cw-back {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }

  /* The contents list keeps its flex row (number, then title). */
  .cw-docs-toc a {
    min-height: 44px;
    align-items: center;
  }

  .cw-header__nav a,
  .cw-mkt-nav__links a {
    padding-bottom: 0;
    border-bottom: 0;
    text-decoration: underline;
    text-decoration-color: transparent;
    text-underline-offset: 5px;
  }

  /* "Docs" is 41px of text; the box under the thumb is not. The others in
     the row clear 44px on their own, and this only began to matter once the
     row stopped being display:none and a thumb could reach it at all. */
  .cw-mkt-nav__links a {
    min-width: 44px;
    justify-content: center;
  }

  .cw-header__nav a.is-active,
  .cw-header__nav a:hover,
  .cw-mkt-nav__links a:hover {
    text-decoration-color: var(--brass-5);
  }

  .cw-mkt-footer__col ul {
    gap: 0;
  }

  /* "Demo" is 35px of text; the box under the thumb is not. */
  .cw-mkt-footer__col a {
    min-width: 44px;
  }

  .cw-chip,
  .cw-dropdown__trigger {
    min-height: 44px;
  }

  .cw-link-btn {
    display: inline-flex;
    align-items: center;
    min-width: 44px;
    min-height: 44px;
  }

  /* 16px is not a taste: below it, iOS Safari zooms the page in when the
     field takes focus and never zooms back out. Being 44px tall does not
     exempt a field from that, which is why the height and the size are set
     together here. The mono fields are named explicitly rather than left to
     source order, so moving this block cannot quietly undo them. */
  .cw-input,
  .cw-select {
    min-height: 44px;
    font-size: 16px;
  }

  .cw-input--mono,
  .cw-select--mono {
    font-size: 16px;
  }

  .cw-check-row {
    min-height: 44px;
  }

  /* The track stays 40 by 20; the button around it grows to the target. */
  .cw-switch-btn {
    padding: 12px 2px;
  }

  .cw-modal__close {
    top: 4px;
    right: 6px;
    width: 44px;
    height: 44px;
  }

  .cw-extlink {
    min-width: 24px;
    min-height: 24px;
  }
}

/* ==========================================================================
   admin — the back office. The same paper, rules and small caps as the
   rest of the app, with one thing the customer pages never have: the
   ledger, an inverse band of brass figures straight under the page head,
   so the six numbers an operator opens the page for are read before
   anything else is. Everything under it is the dashboard's own vocabulary
   (stats strips, funnels, ratio bars, docket tables).
   ========================================================================== */

.cw-admin__pagehead {
  margin-bottom: 14px;
}

.cw-admin-nav {
  margin-bottom: 28px;
}

/* ---- the ledger band ---- */
.cw-ledger {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  background: var(--surface-inverse);
  color: var(--text-on-inverse);
  border: 1px solid var(--green-7);
  box-shadow: var(--shadow-raised);
  margin: 0 0 22px;
}

.cw-ledger__cell {
  padding: 18px 20px 16px;
  border-right: 1px solid var(--green-7);
  min-width: 0;
}

.cw-ledger__cell:last-child {
  border-right: none;
}

.cw-ledger__label {
  color: var(--brass-3);
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cw-ledger__value {
  color: var(--paper-2);
  font-size: var(--type-display-2);
  margin: 6px 0 2px;
  font-variant-numeric: lining-nums tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cw-ledger__sub {
  margin: 0;
  font-size: 12.5px;
  font-style: italic;
  color: var(--green-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---- window chips + the "as of" line ---- */
.cw-admin__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 20px;
  margin-bottom: 26px;
}

.cw-admin__asof {
  margin: 0;
  font-size: 13px;
  font-style: italic;
}

/* ---- the docket: what needs an operator ---- */
.cw-docket {
  margin-bottom: 30px;
}

.cw-docket__heading {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 10px;
}

.cw-docket__badge {
  font-size: 11px;
  padding: 1px 7px;
  color: var(--paper-2);
  background: var(--oxblood-7);
}

.cw-docket__clear {
  margin: 0;
  padding: 14px 0;
  border-top: var(--border-double);
  border-bottom: var(--border-hairline);
  font-style: italic;
  color: var(--green-7);
}

.cw-docket__list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: var(--border-double);
}

.cw-docket__row {
  display: grid;
  grid-template-columns: 52px 56px minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 16px;
  padding: 12px 0;
  border-bottom: var(--border-hairline);
}

.cw-docket__numero {
  font-size: 15px;
  font-style: italic;
  color: var(--text-accent);
}

.cw-docket__count {
  font-size: var(--type-title);
  text-align: right;
  font-variant-numeric: lining-nums tabular-nums;
}

.cw-docket__row.is-bad .cw-docket__count {
  color: var(--oxblood-7);
}

.cw-docket__row.is-warn .cw-docket__count {
  color: var(--brass-7);
}

.cw-docket__label {
  font-size: var(--type-body);
  color: var(--text-body);
}

.cw-docket__link {
  color: var(--text-link);
  text-decoration: none;
  white-space: nowrap;
}

.cw-docket__link:hover {
  text-decoration: underline;
}

/* ---- panels ---- */
.cw-admin__pulse,
.cw-admin__onboarding {
  margin-bottom: 28px;
}

/* The count beside a list page's title ("Customers 12"), in brass and a
   size down, the way the ledger's figures sit under their labels. */
.cw-admin__title {
  display: flex;
  align-items: baseline;
  gap: 14px;
}

.cw-admin__count {
  font-size: var(--type-title);
  color: var(--text-accent);
  font-variant-numeric: lining-nums;
}

.cw-card__over .cw-admin__count {
  margin-left: 10px;
  font-size: var(--type-small);
}

/* Inside the admin panels a heading opens a band under a figure or a table
   ("Queues", "Stacks"), so it takes the same air the Activity tab's panel
   headings do. */
.cw-admin__panels .cw-activity__heading {
  margin: 20px 0 8px;
}

.cw-admin__panels {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 24px;
  margin-bottom: 28px;
  align-items: start;
}

.cw-admin__panels > .cw-card {
  min-width: 0;
}

.cw-admin__panel-link {
  color: var(--text-link);
  text-decoration: none;
}

.cw-admin__panel-link:hover {
  text-decoration: underline;
}

/* Self-improve panel: a PR row offers three ways out -- GitHub, Merge,
   Close. On a phone the stacked table's Actions cell is only as wide as
   the card, and wrapping those into two lines reads as an accident. One
   swipeable row is the same answer as the tab bar, docs contents and
   admin index. */
.cw-si-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

@media (max-width: 860px) {
  .cw-si-actions {
    flex-wrap: nowrap;
    min-width: 0;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
  }

  .cw-si-actions::-webkit-scrollbar {
    display: none;
  }

  .cw-si-actions > * {
    flex: 0 0 auto;
  }
}

.cw-stats--four {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

.cw-stat__value.is-bad {
  color: var(--oxblood-7);
}

/* The panels' own small tables: the queue list, the sweeps list. */
.cw-table--compact tbody td {
  padding: 7px 10px;
  font-size: var(--type-small);
}

.cw-table--compact tbody td:first-child {
  padding-left: 0;
}

.cw-table--compact tbody td:last-child {
  padding-right: 0;
}

.cw-table--compact .cw-row-sub {
  font-family: var(--font-body);
  max-width: 44ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---- kill switches as tags ---- */
.cw-switches {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.cw-switch-tag {
  gap: 7px;
  color: var(--green-7);
  background: var(--green-1);
  border-color: var(--green-3);
}

.cw-switch-tag__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--green-6);
}

.cw-switch-tag.is-off {
  color: var(--oxblood-7);
  background: var(--oxblood-1);
  border-color: var(--oxblood-6);
  text-decoration: line-through;
}

.cw-switch-tag.is-off .cw-switch-tag__dot {
  background: var(--oxblood-6);
}

/* ---- the sweeps list, folded ---- */
/* ---- admin panel index ----
   Desktop does not need it: the panels are two columns and a scroll away.
   A phone gets ten cards stacked down 7,600px, so the index appears there
   and stays put, as one swipeable line -- the same answer as the dashboard
   tabs and the docs contents. */
.cw-admin__index {
  display: none;
}

@media (max-width: 860px) {
  .cw-admin__index {
    display: flex;
    flex-wrap: nowrap;
    min-width: 0;
    gap: 0 var(--space-5);
    position: sticky;
    top: 0;
    z-index: 3;
    margin-bottom: var(--space-4);
    padding: 10px 0;
    background: var(--surface-page);
    border-bottom: var(--border-hairline);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
  }

  .cw-admin__index::-webkit-scrollbar {
    display: none;
  }

  /* Italic and lower case, against the uppercase links beside it. Two jobs:
     it says this strip jumps WITHIN the page, where the admin tab bar
     directly above it moves BETWEEN pages -- two identical-looking rows of
     small caps would otherwise sit on top of each other -- and it takes
     enough width that the fade at the right edge lands on a label rather
     than on the blank space after it, which read as "that is all of them"
     when there are ten. */
  .cw-admin__index-label {
    flex: 0 0 auto;
    align-self: center;
    white-space: nowrap;
    font-family: var(--font-body);
    font-style: italic;
    font-size: var(--type-small);
    color: var(--text-muted);
    padding-right: var(--space-4);
    border-right: var(--border-faint);
  }

  .cw-admin__index a {
    flex: 0 0 auto;
    white-space: nowrap;
    font-family: var(--font-body);
    font-size: var(--type-label);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--text-muted);
    text-decoration: none;
    min-height: 44px;
    min-width: 44px;
    display: inline-flex;
    align-items: center;
  }

  .cw-admin__index a:hover {
    color: var(--text-display);
  }
}

.cw-crons {
  margin-top: 18px;
  border-top: var(--border-faint);
  padding-top: 10px;
}

.cw-crons summary {
  cursor: pointer;
  list-style: none;
}

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

.cw-crons summary::before {
  content: '▸ ';
  color: var(--text-accent);
}

.cw-crons[open] summary::before {
  content: '▾ ';
}

.cw-crons table {
  margin-top: 8px;
}

.cw-crons tr.is-overdue td {
  color: var(--oxblood-7);
}

/* ---- the subscription mix ---- */
.cw-ratio-bar--mix {
  margin-bottom: 8px;
}

.cw-ratio-bar__part--progress {
  background: var(--brass-5);
}

.cw-ratio-bar__part--neutral {
  background: var(--ink-4);
}

.cw-ratio-bar__part--faint {
  background: var(--paper-4);
}

.cw-ratio-bar__part + .cw-ratio-bar__part {
  border-left: 2px solid var(--surface-card);
}

.cw-legend {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  font-size: 13px;
  color: var(--text-muted);
}

.cw-legend li {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.cw-legend__swatch {
  width: 10px;
  height: 10px;
  display: inline-block;
}

.cw-legend__swatch.is-good {
  background: var(--green-6);
}

.cw-legend__swatch.is-progress {
  background: var(--brass-5);
}

.cw-legend__swatch.is-bad {
  background: var(--oxblood-6);
}

.cw-legend__swatch.is-neutral {
  background: var(--ink-4);
}

.cw-legend__swatch.is-faint {
  background: var(--paper-4);
}

/* ---- facts: a label/value list (the money panel, the admin show pages) ---- */
.cw-facts {
  margin: 0;
}

.cw-facts__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 16px;
  align-items: baseline;
  padding: 9px 0;
  border-bottom: var(--border-faint);
}

.cw-facts__row:last-child {
  border-bottom: none;
}

.cw-facts dt {
  color: var(--text-muted);
  font-size: var(--type-small);
}

.cw-facts dd {
  margin: 0;
  text-align: right;
  color: var(--text-body);
  overflow-wrap: anywhere;
}

/* Span evidence: a fact whose value is a query, not a number. The default
   row puts the value right-aligned in its own column, which is right for
   "Attempts: 3" and unreadable for eighty characters of SQL -- so stack the
   value under its label and let it run the full width of the card. */
.cw-facts--stacked .cw-facts__row {
  grid-template-columns: minmax(0, 1fr);
  gap: 4px;
}

.cw-facts--stacked dd {
  text-align: left;
  white-space: pre-wrap;
}

.cw-facts__row.is-bad dd {
  color: var(--oxblood-7);
}

/* ---- fleet: the stacks ladder and the status badge rows ---- */
.cw-funnel--tight {
  gap: 6px 12px;
}

.cw-funnel--tight .cw-funnel__value {
  font-size: var(--type-body);
}

.cw-funnel--wide {
  grid-template-columns: minmax(180px, auto) 48px 52px minmax(60px, 1fr);
}

.cw-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.cw-badges .cw-badge .cw-mono {
  font-size: 11px;
}

/* ---- admin show pages: the record's head ---- */
.cw-admin-record__head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px 24px;
  align-items: end;
  margin: 18px 0 28px;
}

@media (max-width: 860px) {
  .cw-ledger {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .cw-ledger__cell:nth-child(3n) {
    border-right: none;
  }

  .cw-ledger__cell:nth-child(-n + 3) {
    border-bottom: 1px solid var(--green-7);
  }

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

  .cw-funnel--wide {
    grid-template-columns: minmax(120px, auto) 40px 44px minmax(60px, 1fr);
  }
}

@media (max-width: 560px) {
  .cw-ledger {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .cw-ledger__cell {
    padding: 14px 14px 12px;
    border-right: 1px solid var(--green-7);
    border-bottom: 1px solid var(--green-7);
  }

  .cw-ledger__cell:nth-child(2n) {
    border-right: none;
  }

  .cw-ledger__cell:nth-last-child(-n + 2) {
    border-bottom: none;
  }

  .cw-ledger__value {
    font-size: var(--type-title);
  }

  .cw-docket__row {
    grid-template-columns: 40px 44px minmax(0, 1fr);
    gap: 10px;
  }

  .cw-docket__link {
    grid-column: 3;
  }

  /* The tight strip is a list on a phone (see .cw-stats--tight above);
     four figures are no different. */
  .cw-stats--four {
    grid-template-columns: minmax(0, 1fr);
  }

  .cw-funnel--wide {
    grid-template-columns: minmax(0, 1fr) 40px 44px;
  }

  .cw-funnel--wide .cw-funnel__track {
    grid-column: 1 / -1;
  }

  .cw-admin-record__head {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ---- admin list and record pages ---- */
.cw-admin__lead {
  margin: -8px 0 24px;
  max-width: var(--content-measure);
}

.cw-admin__strip {
  margin-bottom: 28px;
}

/* A date standing where a figure would: a size down, so "11 Sep 2026" sits
   on the strip's baseline without running into the next cell. */
.cw-stat__value--date {
  font-size: var(--type-title);
}

.cw-admin .cw-actions {
  flex-direction: row;
  flex-wrap: wrap;
  gap: 10px;
}

/* One charge on the invoice page: its id, state and amount on a line, the
   refund form under it. */
.cw-admin__charge {
  padding: 12px 0;
  border-bottom: var(--border-faint);
}

.cw-admin__charge:last-child {
  border-bottom: none;
}

.cw-admin__charge-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  margin-bottom: 10px;
}

.cw-admin__charge-amount {
  margin-left: auto;
  color: var(--text-display);
}

.cw-admin__refund {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0;
}

.cw-admin__refund .cw-input {
  width: 200px;
  max-width: 100%;
}

/* The sweeps list's summary is a control like any other (see the touch
   target block above), so on a phone or under a finger it grows to the
   minimum instead of staying one line of small caps. */
@media (max-width: 560px), (pointer: coarse) {
  .cw-crons summary {
    display: flex;
    align-items: center;
    min-height: 44px;
  }
}

/* ==========================================================================
   Proof — the live figures, on the home page as a three-up band and on
   /proof as all six. Both were written against classes this stylesheet never
   defined, so they rendered as a run of plain text; they are the dashboard's
   own stats strip in the marketing page's larger type.
   ========================================================================== */
.cw-proof-strip {
  margin-top: var(--space-7);
}

.cw-proof-strip__figures {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border-top: var(--border-double);
  border-bottom: var(--border-hairline);
}

.cw-proof-strip__figure {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
  padding: 18px 20px 20px;
  border-right: 1px solid var(--rule-faint);
}

.cw-proof-strip__figure:first-child {
  padding-left: 0;
}

.cw-proof-strip__figure:last-child {
  border-right: none;
}

.cw-proof-strip__value {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  font-size: var(--type-display-2);
  line-height: 1;
  color: var(--text-display);
  font-variant-numeric: lining-nums tabular-nums;
}

.cw-proof-strip__figure .cw-label {
  color: var(--text-muted);
}

.cw-proof-strip__link {
  white-space: nowrap;
}

/* ---- /proof: the same figures, all six ---- */
.cw-proof-figures {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin: 36px 0 0;
  border-top: var(--border-double);
}

.cw-proof-figures__item {
  min-width: 0;
  padding: 20px 24px 22px;
  border-right: 1px solid var(--rule-faint);
  border-bottom: var(--border-hairline);
}

.cw-proof-figures__item:nth-child(3n) {
  border-right: none;
}

.cw-proof-figures .cw-label {
  display: block;
  color: var(--text-accent);
}

.cw-proof-figures__value {
  margin: 8px 0 0;
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  font-size: var(--type-display-1);
  line-height: 1;
  color: var(--text-display);
  font-variant-numeric: lining-nums tabular-nums;
}

@media (max-width: 860px) {
  .cw-proof-figures {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .cw-proof-figures__item:nth-child(3n) {
    border-right: 1px solid var(--rule-faint);
  }

  .cw-proof-figures__item:nth-child(2n) {
    border-right: none;
  }
}

@media (max-width: 560px) {
  .cw-proof-strip__figures {
    grid-template-columns: minmax(0, 1fr);
  }

  .cw-proof-strip__figure {
    flex-direction: row;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 0;
    border-right: none;
    border-bottom: 1px solid var(--rule-faint);
  }

  .cw-proof-strip__figure:last-child {
    border-bottom: none;
  }

  .cw-proof-figures {
    grid-template-columns: minmax(0, 1fr);
  }

  .cw-proof-figures__item,
  .cw-proof-figures__item:nth-child(3n) {
    padding: 14px 0 16px;
    border-right: none;
  }
}

/* ---- setup readiness (Repo Mappings tab) ----
   One block per BLOCKER, not per project: a repository is named inside the
   group it is stuck in, and the action is the group's. Severity is carried
   by a left rule -- oxblood for blocked, brass for worth-checking -- rather
   than by a badge, so two groups read as one list with a spine. */
.cw-readiness {
  margin-bottom: 28px;
}

/* Title and Dismiss share the head's baseline. */
.cw-readiness__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}

.cw-readiness__dismiss {
  flex: none;
}

/* Dismissed: one line, no rule under it, no padding below. The card is
   still here and still says what is outstanding -- it has just stopped
   taking up the top of the tab. */
.cw-readiness--dismissed {
  padding: 16px 32px;
}

.cw-readiness--dismissed .cw-readiness__head {
  padding-bottom: 0;
  margin-bottom: 0;
  border-bottom: none;
}

.cw-readiness--dismissed .cw-card__title {
  font-size: var(--type-small);
  font-weight: var(--weight-medium);
}

.cw-readiness__allclear {
  font-size: var(--type-small);
  color: var(--text-body);
  margin: 4px 0 0;
}

.cw-readiness__tick {
  color: var(--green-6);
  margin-right: 6px;
}

.cw-readiness__groups {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.cw-readiness__group {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 24px;
  padding: 2px 0 2px 16px;
  border-left: 3px solid var(--rule-faint);
}

.cw-readiness__group--blocked {
  border-left-color: var(--oxblood-6);
}

.cw-readiness__group--warn {
  border-left-color: var(--brass-5);
}

.cw-readiness__body {
  min-width: 0;
}

.cw-readiness__severity {
  display: block;
  color: var(--text-muted);
}

.cw-readiness__group--blocked .cw-readiness__severity {
  color: var(--oxblood-7);
}

.cw-readiness__headline {
  font-size: var(--type-small);
  color: var(--text-body);
  margin: 6px 0 0;
}

/* The repositories the group is about: supporting evidence under the
   sentence, not a list to act on row by row. */
.cw-readiness__projects {
  font-size: var(--type-label);
  color: var(--text-muted);
  margin: 6px 0 0;
  word-break: break-word;
}

.cw-readiness__group .cw-btn {
  flex: none;
}

/* Everything that IS working, in one line under the rule. */
.cw-readiness__foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin-top: 22px;
  padding-top: 14px;
  border-top: var(--border-hairline);
}

.cw-readiness__tally {
  font-size: var(--type-small);
  color: var(--text-muted);
  margin: 0;
}

.cw-readiness__ready {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
}

.cw-readiness__ready li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 7px 0;
  border-bottom: 1px solid var(--rule-faint);
  font-size: var(--type-small);
}

.cw-readiness__ready li:last-child {
  border-bottom: none;
}

.cw-readiness__ready-count {
  font-size: var(--type-label);
  color: var(--text-muted);
  white-space: nowrap;
}

/* The tab-bar mark. The whole of readiness above the fold is this dot: it
   says "look in there" and nothing else. Nothing renders when there is
   nothing to report -- a permanent green tick would train the eye past it. */
.cw-tab-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-left: 6px;
  vertical-align: 1px;
  text-indent: -9999px;
  overflow: hidden;
}

.cw-tab-dot--blocked {
  background: var(--oxblood-6);
}

.cw-tab-dot--warn {
  background: var(--brass-5);
}

@media (max-width: 560px) {
  /* The action drops under the sentence and spans the card: a 44px target
     rather than a word squeezed against the right edge. */
  .cw-readiness__group {
    flex-direction: column;
    gap: 14px;
  }

  .cw-readiness__group .cw-btn {
    width: 100%;
    min-height: 44px;
  }

  .cw-readiness__foot {
    flex-direction: column;
    gap: 8px;
  }
}

/* README badge card (RepoMappingPage.vue). The badge itself is the example,
   shown before the snippet that makes it: the card asks someone to put an
   image at the top of their repository, and a URL is not a preview. */
.cw-readme__example {
  margin: 16px 0 0;
}

.cw-readme__example img {
  display: block;
  height: 20px;
  width: auto;
}

.cw-readme__lead {
  max-width: 52ch;
}

/* Wrapped rather than scrolled: the snippet is one long line and a person
   copying it by hand has to see all of it, phone included. */
.cw-readme__snippet {
  margin: 14px 0 0;
  padding: 12px 14px;
  background: var(--surface-inset);
  border: var(--border-faint);
  color: var(--text-body);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.cw-readme__snippet code {
  font: inherit;
}

.cw-readme__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-top: 16px;
}

.cw-readme__status {
  margin: 12px 0 0;
  font-size: 13px;
  font-style: italic;
  color: var(--text-muted);
}

.cw-readme__status a {
  font-style: normal;
}

/* ---- self-improvement docket (admin) ----
   One row per issue rather than per round, so the row has to carry five
   things at once: which issue, what state, how much budget is left, its
   pull request and when it last moved. A grid, because those columns have
   to line up down the docket for "three attempts and gave up" to be
   readable at a glance -- which was the whole complaint about the three
   flat lists this replaced. */
.cw-si-figures {
  display: flex;
  flex-wrap: wrap;
  gap: 18px 32px;
  padding: 14px 18px;
  margin-bottom: 14px;
  background: var(--surface-inset);
  border: var(--border-faint);
}

.cw-si-figure {
  display: flex;
  flex-direction: column;
}

.cw-si-figure__value {
  font-family: var(--font-display);
  font-size: 26px;
  font-weight: 600;
  line-height: 1.12;
  color: var(--text-display);
}

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

.cw-si-filter {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 14px;
}

.cw-si-filter__chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 12px;
  font-family: var(--font-body);
  font-size: var(--type-label);
  font-weight: 600;
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-body);
  background: transparent;
  border: 1px solid var(--rule-hairline);
  cursor: pointer;
}

.cw-si-filter__chip:hover {
  border-color: var(--brass-5);
}

.cw-si-filter__chip.is-active {
  color: var(--text-on-inverse);
  background: var(--green-8);
  border-color: var(--green-8);
}

.cw-si-docket {
  border-top: var(--border-faint);
}

/* Two columns, not a row of three children: the rail runs down the whole
   row while the head and the expanded detail STACK in the second column.
   Laid out as a flex row instead, an open detail becomes the head's
   sibling and the two halve the row between them -- the head's five
   columns collapse until a title wraps a word to a line, and the detail's
   until a reason wraps a character to one. */
.cw-si-row {
  display: grid;
  grid-template-columns: 3px minmax(0, 1fr);
  border-bottom: var(--border-faint);
}

/* The rail is the state, read down the edge of the docket before any word
   is: a column of oxblood is a bad week. It spans both rows so it runs the
   full height of an OPEN row too; closed, the second row is empty and
   measures nothing. */
.cw-si-rail {
  grid-column: 1;
  grid-row: span 2;
  width: 3px;
}

.cw-si-rail--not_started {
  background: var(--rule-faint);
}

.cw-si-rail--queued,
.cw-si-rail--building {
  background: var(--brass-5);
}

.cw-si-rail--built {
  background: var(--green-7);
}

.cw-si-rail--build_failed {
  background: var(--oxblood-6);
}

/* The whole row is the disclosure control: an issue's rounds are what the
   page is for, and a chevron-sized target for them would be a joke. */
.cw-si-row__head {
  grid-column: 2;
  display: grid;
  grid-template-columns: 62px minmax(0, 1fr) 176px 172px 76px;
  align-items: start;
  gap: 14px;
  width: 100%;
  padding: 13px 16px;
  font: inherit;
  text-align: left;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}

.cw-si-row__head:hover {
  background: var(--surface-inset);
}

.cw-si-row__number {
  font-size: 13px;
  color: var(--text-muted);
  padding-top: 2px;
}

.cw-si-row__body {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.cw-si-row__title {
  color: var(--text-display);
  line-height: 1.3;
}

/* Bucket, backlog and the last round's reason, in one line of small print:
   the reason is the single most useful thing on a failed row, and clamping
   it here is deliberate -- the unclamped copy is one click away, under
   The rounds. */
.cw-si-row__note {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 10px;
  font-size: 13px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cw-si-row__state {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
}

.cw-si-row__rounds,
.cw-si-row__when {
  font-size: 13px;
}

.cw-si-row__when {
  text-align: right;
}

.cw-si-chip {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  font-size: var(--type-label);
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  white-space: nowrap;
}

.cw-si-chip--not_started {
  color: var(--text-muted);
  background: var(--surface-inset);
}

.cw-si-chip--queued,
.cw-si-chip--building {
  color: var(--brass-7);
  background: var(--brass-1);
}

.cw-si-chip--built {
  color: var(--green-8);
  background: var(--green-1);
}

.cw-si-chip--build_failed {
  color: var(--oxblood-7);
  background: var(--oxblood-1);
}

/* The attempt budget as MAX_ATTEMPTS squares, in the order the rounds ran
   and coloured by how each ended. An outline is a round not taken. */
.cw-si-pips {
  display: inline-flex;
  gap: 5px;
}

.cw-si-pip {
  width: 11px;
  height: 11px;
  border: 1px solid var(--rule-hairline);
}

.cw-si-pip--empty {
  background: transparent;
}

.cw-si-pip--opened_pr,
.cw-si-pip--filed_issue {
  background: var(--green-6);
  border-color: var(--green-6);
}

.cw-si-pip--refused {
  background: var(--brass-3);
  border-color: var(--brass-3);
}

.cw-si-pip--errored {
  background: var(--oxblood-6);
  border-color: var(--oxblood-6);
}

.cw-si-pip--running {
  background: var(--brass-1);
  border-color: var(--brass-5);
}

.cw-si-detail {
  grid-column: 2;
  padding: 4px 16px 18px 76px;
  background: var(--surface-inset);
}

.cw-si-rounds {
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
}

.cw-si-round {
  display: grid;
  grid-template-columns: 22px 172px minmax(0, 1fr) 76px;
  align-items: start;
  gap: 12px;
  padding: 8px 0;
  border-top: var(--border-faint);
}

.cw-si-round__ordinal {
  font-size: 13px;
  color: var(--text-faint);
}

.cw-si-round__outcome {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.cw-si-round__when {
  font-size: 13px;
  text-align: right;
}

.cw-si-budget {
  margin: 12px 0 0;
  font-size: 13px;
  font-style: italic;
}

.cw-si-footnote {
  margin: 14px 0 0;
  font-size: 13px;
  font-style: italic;
}

/* A phone has no room for five columns: the row stacks, and the state,
   budget and pull request sit under the title rather than beside it. */
@media (max-width: 860px) {
  /* A finger, not a cursor: the docket's one row of controls has to meet
     the 44px target floor the responsive suite holds every admin page to. */
  .cw-si-filter__chip {
    min-height: 44px;
    padding: 9px 13px;
  }

  .cw-si-row__head {
    grid-template-columns: 54px minmax(0, 1fr) auto;
    gap: 8px 12px;
  }

  .cw-si-row__body {
    grid-column: 2 / -1;
  }

  .cw-si-row__state,
  .cw-si-row__pr {
    grid-column: 2 / -1;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
  }

  .cw-si-row__when {
    grid-column: 3;
    grid-row: 1;
  }

  .cw-si-row__note {
    white-space: normal;
  }

  .cw-si-detail {
    padding-left: 16px;
  }

  .cw-si-round {
    grid-template-columns: 22px minmax(0, 1fr);
  }

  .cw-si-round__when {
    grid-column: 2;
    text-align: left;
  }
}
