/* Gantry Broadsheet — self-contained, phone-first, no framework or remote assets. */

:root {
  color-scheme: light dark;
  --paper: #edf1ed;
  --card: #e7ece7;
  --card-face: #f2f5f1;
  --rule: #c9d4cb;
  --ink: #161c18;
  --text-2: #49564d;
  --text-3: #59665d;
  --ok: #1e7a4e;
  --ok-bg: rgba(30, 122, 78, .12);
  --red: #c8371e;
  --red-bg: rgba(200, 55, 30, .10);
  --warn: #7d400a;
  --warn-bg: rgba(200, 113, 30, .12);
  --blue: #2b5fa3;
  --blue-bg: rgba(43, 95, 163, .10);
  --track: #e0e7e1;
  --shadow: 0 12px 34px rgba(27, 39, 30, .08);
  --serif: ui-serif, "New York", Georgia, serif;
  --sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", sans-serif;
  --mono: ui-monospace, "SF Mono", Menlo, monospace;
  /* The narrowest a column of copy may be squeezed to before whatever shares its row — a status
     pill, a money figure, a timestamp — is dealt a line of its own instead. See "head rows". */
  --copy-min: 20ch;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper: #131715;
    --card: #1a1f1c;
    --card-face: #181d1a;
    --rule: #2c342f;
    --ink: #e7ece7;
    --text-2: #a6b1a9;
    --text-3: #9aa69d;
    --ok: #4cb584;
    --ok-bg: rgba(76, 181, 132, .14);
    --red: #e05a3f;
    --red-bg: rgba(224, 90, 63, .14);
    --warn: #d0873a;
    --warn-bg: rgba(208, 135, 58, .14);
    --blue: #6c97ce;
    --blue-bg: rgba(108, 151, 206, .14);
    --track: #202622;
    --shadow: 0 14px 40px rgba(0, 0, 0, .22);
  }
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }
html { min-height: 100%; -webkit-text-size-adjust: 100%; }
body {
  min-height: 100%;
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 14px/1.45 var(--sans);
  -webkit-font-smoothing: antialiased;
}
button, input, select { font: inherit; }
button, a, summary { -webkit-tap-highlight-color: transparent; }
button:focus-visible, a:focus-visible, summary:focus-visible, input:focus-visible, select:focus-visible, [role="slider"]:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
}

.top {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 7px;
  min-height: calc(58px + env(safe-area-inset-top));
  padding: max(12px, env(safe-area-inset-top)) 20px 9px;
  border-bottom: 1px solid var(--rule);
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
}
.brand-lockup { display: grid; line-height: 1; }
.masthead { font: italic 600 16px/1 var(--serif); letter-spacing: -.2px; }
.spacer { flex: 1; }
.utility {
  min-width: 44px;
  min-height: 44px;
  padding: 0 9px;
  border: 1px solid transparent;
  border-radius: 22px;
  background: transparent;
  color: var(--text-2);
  font-size: 12px;
  font-weight: 650;
  cursor: pointer;
}
.utility:hover { border-color: var(--rule); color: var(--ink); }
.utility:disabled { cursor: wait; opacity: .45; }

main {
  width: min(100%, 760px);
  margin: 0 auto;
  padding: 20px 20px calc(104px + env(safe-area-inset-bottom));
}
.loading-state { padding-top: 12px; }

/* ------------------------------------------------------------------------------ how text wraps
   Three kinds of string, one rule each, so no column has to be patched per selector.

   An IDENTIFIER carries no spaces to break at — a run id, a bucket, a provider ref, an email, a
   request hash, a machine token, a rendered rate. It wraps ANYWHERE, which also makes its
   min-content width one character: any column holding one needs a floor of its own (see "head
   rows"), or it will be squeezed to that.

   PROSE wraps at words, which is the initial value and therefore has no rule here.

   A NUMBER the reader compares down a column — a money figure, a bandwidth, a clock time, a
   countdown — never wraps, and the row that holds one gives it its width or a line of its own. */
h1, h2, h3, p,
.row-title, .row-detail, .run-title, .run-timeline, .run-rate, .run-max, .run-terminate-status,
.workload-fact strong, .request-label, .auto-refusal, .read-grant, .transfer-line, .params-drift,
.approval-facts dd, .approval-meta, .param-key, .param-value, .baseline-ref,
.disk-orphan-copy .row-title, .budget-identity h2, .budget-available-amount,
.budget-blocked-status, .budget-review-row dd, .budget-ledger-note, .budget-ledger-time,
.notification-item-key, .notification-facts dd {
  overflow-wrap: anywhere;
}
.pill, .burn-fact, .capacity-window, .budget-expiry, .disk-orphan-cost,
.notification-head .js-relative-time {
  white-space: nowrap;
}

/* ------------------------------------------------------------------------------------ head rows
   Every row here is a column of copy — a name, a detail line — beside something that cannot be
   narrowed. The copy column is what must give, and `flex: 1` resolves to `flex-basis: 0`, so with
   an identifier's one-character min-content it gives all the way down: a 40-character run id
   rendered three characters per line beside a pill that kept its full width. The copy keeps a real
   minimum instead, and the row wraps, so the pill or the figure takes the next line. */
.workload-head, .finding-row, .resource-row, .history-row, .claim-row, .notification-head,
.budget-card-head {
  flex-wrap: wrap;
}
.finding-copy, .resource-copy, .history-copy, .claim-copy, .budget-identity {
  flex: 1 1 auto;
  min-width: min(100%, var(--copy-min));
}
.finding-row > .row-value, .resource-row > .row-value, .history-row > .row-value,
.claim-row > .row-value {
  margin-left: auto;
}

.screen-head { margin: 0 0 17px; }
.screen-head-row { display: flex; align-items: end; gap: 12px; }
.screen-head-row > div:first-child { flex: 1; min-width: 0; }

.screen-head h1, .loading-state h1 {
  margin: 0;
  font: 700 30px/1.05 var(--serif);
  letter-spacing: -.8px;
}
.heavy-rule { height: 2px; margin-top: 12px; background: var(--ink); }
.muted { color: var(--text-2); }
.faint { color: var(--text-3); }
.small { font-size: 12px; }
.stale-read-alert {
  margin: 0 0 16px;
  padding: 12px;
  border: 1px solid var(--warn);
  border-radius: 12px;
  background: var(--warn-bg);
  color: var(--warn);
}
.stale-read-alert p { margin: 6px 0 12px; }
body[data-stale="true"] main { filter: saturate(.75); }
.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.tabular { font-variant-numeric: tabular-nums; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.tabbar {
  position: fixed;
  z-index: 30;
  right: 0;
  bottom: 0;
  left: 0;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  width: min(100%, 760px);
  min-height: calc(68px + env(safe-area-inset-bottom));
  margin: auto;
  padding: 6px 12px calc(6px + env(safe-area-inset-bottom));
  border: 0;
  border-top: 1px solid var(--rule);
  border-radius: 0;
  background: color-mix(in srgb, var(--card-face) 94%, transparent);
  box-shadow: 0 -1px 12px rgba(20, 28, 23, .05);
  -webkit-backdrop-filter: blur(20px);
  backdrop-filter: blur(20px);
}
.tabbar a {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: 56px;
  border-radius: 13px;
  color: var(--text-3);
  font-size: 12px;
  font-weight: 650;
  text-decoration: none;
}
.tabbar a.active { color: var(--ink); }
.tabbar svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.7; }
.pending-badge:not(:empty) {
  position: absolute;
  top: 4px;
  /* Off the icon's top-right corner, and never past the tab's own edge: on a narrow tab the badge
     would otherwise sit over its neighbour. */
  left: min(calc(50% + 12px), calc(100% - 24px));
  display: grid;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  place-items: center;
  border: 2px solid var(--card-face);
  border-radius: 9px;
  background: var(--red);
  color: #fff;
  font-size: 12px;
  line-height: 1;
}

.burn-hero { padding: 7px 0 19px; }
.spend-summary { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.spend-summary .workload-fact strong { font-size: clamp(18px, 5vw, 30px); }
.burn-scope { margin: 5px 0 0; color: var(--text-2); font-size: 12px; font-variant-numeric: tabular-nums; }
.burn-fixed { margin-top: 12px; color: var(--text-2); }
.burn-fixed-line { font: 650 17px/1.2 var(--serif); font-variant-numeric: tabular-nums; }
.burn-fixed-amount, .burn-fixed-pending { color: var(--ink); font-weight: 750; }
.burn-fixed-pending { font-family: var(--mono); font-size: 13px; letter-spacing: .3px; }
.burn-fixed-source { margin-top: 3px; color: var(--text-2); font-size: 12px; line-height: 1.35; font-variant-numeric: tabular-nums; }
.burn-facts { display: flex; flex-wrap: wrap; margin: 3px 0 0; padding: 0; color: var(--text-2); font-size: 12px; font-variant-numeric: tabular-nums; list-style: none; }
.burn-fact + .burn-fact::before { content: "·"; margin: 0 6px; color: var(--text-3); }

.banner {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 0 0 14px;
  padding: 12px 12px;
  border: 1px solid var(--rule);
  border-radius: 12px;
  font-size: 12px;
}
.banner::before { content: ""; flex: 0 0 8px; width: 8px; height: 8px; margin-top: 4px; border-radius: 50%; background: currentColor; }
.banner-copy { flex: 1; min-width: 0; }
.banner-detail { margin-top: 2px; line-height: 1.4; }
.banner.warn { border-color: color-mix(in srgb, var(--warn) 35%, var(--rule)); background: var(--warn-bg); color: var(--warn); }
.banner.ok { border-color: color-mix(in srgb, var(--ok) 30%, var(--rule)); background: var(--ok-bg); color: var(--ok); }
.banner.info { background: var(--blue-bg); color: var(--blue); }
.banner strong { color: inherit; }
.banner.action { cursor: pointer; }

.section { margin-top: 19px; }
.section-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 3px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--ink);
}
.section-head h2 { flex: 1; margin: 0; font: 650 15px/1.2 var(--serif); }
.section-count { color: var(--text-3); font: 12px/1 var(--mono); }

.report-block { margin-top: 16px; }
.report-meta { display: flex; align-items: center; gap: 8px; margin: 6px 0 3px; color: var(--text-3); font-size: 12px; }
.finding-row, .resource-row, .history-row, .claim-row {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 52px;
  padding: 9px 0;
  border-bottom: 1px solid var(--rule);
}
.finding-row { align-items: flex-start; }
.row-title { font-size: 12px; font-weight: 650; }
.row-detail { margin-top: 2px; color: var(--text-2); font-size: 12px; line-height: 1.35; }
.row-value { flex: 0 0 auto; text-align: right; font: 650 12px/1.2 var(--mono); font-variant-numeric: tabular-nums; }
.row-value small { display: block; margin-top: 4px; color: var(--text-3); font: 12px/1.1 var(--sans); }
.run-terminate { grid-area: terminate; display: flex; align-items: center; justify-content: flex-end; gap: 12px; min-width: 0; }
.run-terminate-button {
  flex: 0 0 auto;
  min-height: 34px;
  padding: 7px 12px;
  border: 1px solid color-mix(in srgb, var(--red) 38%, var(--rule));
  border-radius: 18px;
  background: transparent;
  color: var(--red);
  font-size: 12px;
  font-weight: 750;
  cursor: pointer;
}
.run-terminate-button.confirm { background: var(--red); color: #fff; }
.run-terminate-button:disabled { cursor: wait; opacity: .7; }
.run-terminate-button.terminal, .run-terminate-button.externally-removed { border-color: var(--rule); color: var(--text-2); cursor: default; }
.run-terminate-status { flex: 1; min-width: 0; color: var(--text-2); font-size: 12px; line-height: 1.4; }
.run-terminate-status.uncertain, .run-terminate-status.recorded { color: var(--warn); }
.run-terminate-status.failed { color: var(--red); }
.run-terminate-status.terminal, .run-terminate-status.externally-removed { color: var(--ok); }
.storage-row {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr) auto;
  align-items: start;
  min-height: 70px;
  column-gap: 12px;
  row-gap: 4px;
}
/* The head row is placed by hand; every child after it auto-flows onto a full-width row of its own,
   so two sibling lines can never be dealt the same rect. */
.storage-row > * { grid-column: 2 / -1; }
.storage-row > .provider-mark { grid-row: 1; grid-column: 1; margin-top: 1px; }
.storage-row > .resource-copy { grid-row: 1; grid-column: 2; }
.storage-row > .row-value { grid-row: 1; grid-column: 3; white-space: nowrap; }
.storage-row > .row-detail { margin-top: 0; }
.storage-baseline-held { color: var(--warn); }
.capacity-commitment-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas:
    "copy window"
    "summary summary";
  align-items: start;
  min-height: 88px;
  padding-top: 12px;
  padding-bottom: 12px;
  column-gap: 12px;
  row-gap: 8px;
}
.capacity-commitment-row > .resource-copy { grid-area: copy; }
.capacity-window { grid-area: window; min-width: 123px; color: var(--text-2); font: 650 12px/1.3 var(--mono); font-variant-numeric: tabular-nums; text-align: right; }
.capacity-window-end { display: block; }
.commitment-summary { grid-area: summary; display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; min-width: 0; }
.capacity-commitment-row .row-value { min-width: 0; text-align: left; }
.finding-row.is-warn { margin-right: -8px; margin-left: -8px; padding-right: 8px; padding-left: 8px; background: var(--warn-bg); }
.overflow-note { margin: 8px 0; color: var(--warn); font-size: 12px; }

.provider-mark {
  display: grid;
  flex: 0 0 22px;
  width: 22px;
  height: 22px;
  place-items: center;
  border-radius: 6px;
  background: var(--blue-bg);
  color: var(--blue);
  font: 700 12px/1 var(--sans);
  text-transform: lowercase;
}
.provider-mark.aws { background: rgba(192, 114, 31, .16); color: #a75b13; }
.provider-mark.gcp { background: rgba(61, 123, 192, .16); color: #326da9; font-size: 12px; text-transform: none; }
.provider-mark.lambda { background: rgba(122, 104, 214, .16); color: #725dcc; font: 700 15px/1 var(--serif); text-transform: none; }
.provider-mark.modal { background: rgba(46, 155, 102, .16); color: #258658; font-size: 12px; }
.provider-mark.r2, .provider-mark.s3, .provider-mark.gcs { font-size: 12px; }
.resource-row.drift { margin-right: -8px; margin-left: -8px; padding-right: 8px; padding-left: 8px; background: var(--warn-bg); }
.resource-row.prepaid-idle { margin-right: -8px; margin-left: -8px; padding-right: 8px; padding-left: 8px; background: var(--warn-bg); }
.unpriced { color: var(--warn); }

.pill {
  display: inline-flex;
  align-items: center;
  min-height: 20px;
  padding: 2px 8px;
  border-radius: 12px;
  font-size: 12px;
  font-weight: 750;
  letter-spacing: .55px;
  text-transform: uppercase;
}
.pill.ok, .pill.approved, .pill.active { background: var(--ok-bg); color: var(--ok); }
.pill.warn, .pill.terminating { background: var(--warn-bg); color: var(--warn); }
.pill.denied { background: var(--red-bg); color: var(--red); }
.pill.info, .pill.scheduled { background: var(--blue-bg); color: var(--blue); }
.pill.expired, .pill.unknown { background: var(--track); color: var(--text-2); }

.approval-deck {
  display: flex;
  gap: 12px;
  margin: 0 -20px;
  padding: 2px 20px 12px;
  overflow-x: auto;
  overscroll-behavior-inline: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.approval-deck::-webkit-scrollbar { display: none; }
.approval-card {
  flex: 0 0 min(100%, 540px);
  min-width: 0;
  padding: 17px 16px 16px;
  overflow: hidden;
  border: 1px solid var(--rule);
  border-radius: 18px;
  background: var(--card-face);
  box-shadow: var(--shadow);
  scroll-snap-align: center;
}
.approval-card.terminal { opacity: .72; }
.approval-top { display: flex; align-items: flex-start; gap: 9px; }
.approval-identity { flex: 1; min-width: 0; }
.approval-action { font-size: 13px; font-weight: 700; }
.approval-provider { margin-top: 2px; color: var(--text-2); font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 1.1px; }
.ttl { color: var(--red); font: 700 12px/1.3 var(--mono); font-variant-numeric: tabular-nums; }

/* Multi-user v1 (#105): the Mine / Everyone board scope toggle. */
.board-scope { display: flex; align-items: center; justify-content: flex-end; gap: 12px; flex-wrap: wrap; margin: 0 0 14px; }
.board-scope-group { display: inline-flex; border: 1px solid var(--rule); border-radius: 999px; overflow: hidden; background: var(--card-face); }
.board-scope-btn { border: 0; background: transparent; color: var(--text-2); font: 700 12px/1 var(--sans); letter-spacing: .4px; padding: 7px 14px; cursor: pointer; }
.board-scope-btn.active { background: var(--ink); color: var(--paper); }
.board-scope-btn:focus-visible { outline: 2px solid var(--blue); outline-offset: -2px; }
.ttl.checking { color: var(--warn); }
.quote-block { margin: 20px 0 14px; text-align: center; }
.quote-number { font: 700 54px/.95 var(--serif); font-variant-numeric: tabular-nums; letter-spacing: -2px; }
.quote-number .per { margin-left: 3px; font: italic 500 15px/1 var(--serif); letter-spacing: 0; }
.quote-source { max-width: 470px; margin: 8px auto 0; color: var(--text-2); font-size: 12px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; }
.launch-quote { margin: 25px 0 20px; }
/* The amount and its label lead line one; the scope clause wraps below rather than being clipped
   by the card's `overflow-x: hidden` ancestor. */
.request-maximum { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: center; gap: 3px; }
.request-label { min-width: 0; color: var(--text-2); font: 650 clamp(15px, 4.4vw, 18px)/1.1 var(--sans); letter-spacing: -.2px; }
.request-amount { flex: 0 0 auto; font: 700 clamp(38px, 11vw, 50px)/1 var(--serif); font-variant-numeric: tabular-nums; letter-spacing: -1.6px; }
.request-rate { margin-top: 8px; color: var(--text-2); font: 600 17px/1.2 var(--serif); font-variant-numeric: tabular-nums; }
.authorization-box { margin: 0 0 12px; padding: 12px 12px; border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }
.authorization-box .label { color: var(--text-3); font-size: 12px; font-weight: 700; letter-spacing: 1.1px; text-transform: uppercase; }
.authorization-box .value { margin-top: 3px; font: 700 17px/1.2 var(--serif); font-variant-numeric: tabular-nums; }
.divergence { margin: 9px 0; padding: 7px 9px; border-radius: 8px; background: var(--warn-bg); color: var(--warn); font-size: 12px; font-weight: 700; text-align: center; }
.auto-refusal { margin: 9px 0; padding: 8px 12px; border-radius: 8px; background: var(--warn-bg); color: var(--warn); font: 12px/1.5 var(--mono); text-align: left; }
.read-grant { margin: 9px 0; padding: 8px 12px; border-radius: 8px; background: var(--warn-bg); color: var(--warn); font: 12px/1.5 var(--mono); text-align: left; }
.params-drift { margin: 9px 0; padding: 8px 12px; border-radius: 8px; background: var(--warn-bg); color: var(--warn); font: 12px/1.5 var(--mono); text-align: left; }
.reason { margin: 14px 0; padding-left: 12px; border-left: 2px solid var(--red); font: italic 500 15px/1.4 var(--serif); }
.approval-summary { margin-top: 12px; }
.approval-facts { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 4px 12px; margin: 12px 0; }
.approval-facts dt { color: var(--text-3); font-size: 12px; font-weight: 700; text-transform: uppercase; }
.approval-facts dd { min-width: 0; margin: 0; color: var(--text-2); }
.technical-evidence { margin: 12px 0; border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }
.technical-evidence > summary { min-height: 44px; padding: 12px 2px; color: var(--text-2); font-weight: 700; cursor: pointer; }
.technical-evidence .approval-meta { margin: 12px 0 12px; }
.param-table { margin: 12px 0 14px; border-top: 1px solid var(--rule); }
.param-row { display: grid; grid-template-columns: minmax(90px, .42fr) minmax(0, 1fr); gap: 9px; padding: 7px 0; border-bottom: 1px solid var(--rule); }
.param-key { color: var(--text-3); font: 12px/1.4 var(--mono); }
.param-value { color: var(--text-2); font: 12px/1.4 var(--mono); white-space: pre-wrap; }
.approval-meta { margin-bottom: 12px; color: var(--text-3); font: 12px/1.4 var(--mono); }
.deck-position { display: flex; align-items: center; justify-content: center; gap: 8px; min-height: 25px; color: var(--text-3); font: 12px/1 var(--mono); }
.deck-dots { display: flex; gap: 5px; }
.deck-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--rule); }
.deck-dot.active { background: var(--ink); }

/* The approval controls are drawn on the Approvals deck, which contains its own overflow by
   scrolling sideways, and on the full-width run card, where nothing contains it. On both, the grid
   items must be allowed to shrink below the launch-window select's longest option. */
.decision-actions { display: grid; gap: 9px; }
.decision-actions > * { min-width: 0; }
/* Owner-set launch-window picker. Minimal layout only;
   polish is the designer pass. */
.launch-window-choice { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; }
.launch-window-label { font-size: 12px; letter-spacing: .04em; text-transform: uppercase; opacity: .72; }
.launch-window-select {
  flex: 1 1 auto;
  min-width: 0;
  max-width: 100%;
  padding: 7px 9px;
  border-radius: 8px;
  border: 1px solid var(--rule);
  background: var(--card);
  color: inherit;
  font: inherit;
}
.approve-slider {
  position: relative;
  height: 56px;
  overflow: hidden;
  border: 1px solid var(--rule);
  border-radius: 28px;
  background: var(--track);
  touch-action: none;
  user-select: none;
}
.slider-label { position: absolute; inset: 0; display: grid; place-items: center; padding-left: 34px; color: var(--text-2); font-size: 12px; font-weight: 700; letter-spacing: .4px; pointer-events: none; }
.slider-thumb {
  position: absolute;
  top: 3px;
  left: 3px;
  display: grid;
  width: 48px;
  height: 48px;
  min-height: 0;
  padding: 0;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: var(--red);
  color: #fff;
  box-shadow: 0 5px 14px rgba(135, 36, 20, .25);
  cursor: grab;
  transform: translateX(0);
  transition: transform .2s cubic-bezier(.2, .75, .25, 1);
}
.slider-thumb.dragging { cursor: grabbing; transition: none; }
.slider-thumb::after { content: "→"; font: 700 20px/1 var(--sans); }
.approve-slider.disabled { opacity: .52; pointer-events: none; }
.deny-button, .outline-button {
  width: 100%;
  min-height: 44px;
  padding: 12px 14px;
  border: 1px solid var(--rule);
  border-radius: 22px;
  background: transparent;
  color: var(--text-2);
  font-weight: 700;
  cursor: pointer;
}
.deny-button { color: var(--red); border-color: color-mix(in srgb, var(--red) 34%, var(--rule)); }
.deny-button:disabled, .outline-button:disabled { cursor: wait; opacity: .46; }
.decision-result { min-height: 56px; padding: 12px; border-radius: 12px; background: var(--track); }
.decision-result.approved { background: var(--ok-bg); color: var(--ok); }
.decision-result.denied, .decision-result.expired { background: var(--red-bg); color: var(--red); }
.decision-result .result-title { font-weight: 750; text-transform: uppercase; letter-spacing: .8px; }
.decision-result .result-detail { margin-top: 4px; font-size: 12px; }
.action-outcome { margin-top: 8px; padding: 9px 12px; border-radius: 9px; font-size: 12px; }
.action-outcome.ok { background: var(--ok-bg); color: var(--ok); }
.action-outcome.failed { background: var(--red-bg); color: var(--red); }
.action-outcome.uncertain { background: var(--warn-bg); color: var(--warn); }

.history-row { align-items: flex-start; }
.history-row .pill { margin-top: 1px; }
.history-price { margin-top: 4px; color: var(--text-2); font: 12px/1.35 var(--mono); }
.history-who { margin-top: 3px; color: var(--text-3); font-size: 12px; }

.empty-state { padding: 27px 12px; color: var(--ok); text-align: center; }
.empty-state strong { display: block; font: 650 18px/1.25 var(--serif); }
.empty-state span { display: block; margin-top: 5px; color: var(--text-2); font-size: 12px; }

.baseline-card { padding: 16px 14px; border: 1px solid color-mix(in srgb, var(--red) 30%, var(--rule)); border-radius: 14px; background: var(--card-face); }
.baseline-card .section-title { margin: 0 0 4px; font: 650 15px/1.2 var(--serif); }
.baseline-list { margin: 12px 0; }
.baseline-row { display: flex; align-items: center; gap: 12px; min-height: 40px; padding: 6px 2px; border-top: 1px solid var(--rule); cursor: pointer; }
.baseline-row input { width: 18px; height: 18px; flex: 0 0 18px; accent-color: var(--red); }
.baseline-ref { font: 12px/1.3 var(--mono); color: var(--ink); }
.confirm-button { width: 100%; min-height: 44px; padding: 12px 14px; border: 1px solid var(--red); border-radius: 22px; background: var(--red); color: #fff; font-weight: 700; cursor: pointer; }
.confirm-button:disabled { cursor: wait; opacity: .46; }

/* #78 orphan-disk one-tap: a broker-tagged residue list + the reap-all action, styled like the baseline card. */
.disk-orphans-card { padding: 16px 14px; border: 1px solid color-mix(in srgb, var(--red) 30%, var(--rule)); border-radius: 14px; background: var(--card-face); }
.disk-orphan-list { margin: 12px 0; }
.disk-orphan-row { display: flex; align-items: center; gap: 12px; min-height: 44px; padding: 8px 2px; border-top: 1px solid var(--rule); }
.disk-orphan-copy { flex: 1 1 auto; min-width: 0; }
.disk-orphan-copy .row-title { font: 12px/1.3 var(--mono); }
.disk-orphan-cost { flex: 0 0 auto; font: 650 12px/1.2 var(--mono); color: var(--red); }

.meter { height: 6px; overflow: hidden; border-radius: 3px; background: var(--track); }
.meter > span { display: block; height: 100%; background: var(--ok); }
.meter > span.warn { background: var(--warn); }
.meter > span.danger { background: var(--red); }

.new-budget-button {
  flex: 0 0 auto;
  min-height: 44px;
  padding: 9px 14px;
  border: 1px solid var(--ink);
  border-radius: 22px;
  background: var(--ink);
  color: var(--paper);
  font-size: 12px;
  font-weight: 750;
  cursor: pointer;
}
.budget-lede { margin: -8px 0 18px; color: var(--text-2); font-size: 12px; }
.budget-list { display: grid; gap: 13px; }
.budget-card {
  min-width: 0;
  padding: 16px;
  overflow: hidden;
  border: 1px solid var(--rule);
  border-radius: 17px;
  background: var(--card-face);
}
.budget-card-head {
  display: flex;
  align-items: start;
  gap: 9px;
}
.budget-identity h2 { margin: 0; font: 700 15px/1.25 var(--serif); }
.budget-expiry { color: var(--text-3); font: 12px/1.35 var(--mono); font-variant-numeric: tabular-nums; }
.budget-expiry.unavailable { max-width: 92px; font-family: var(--sans); white-space: normal; text-align: right; }
.budget-available { margin-top: 22px; text-align: center; font-family: var(--serif); font-variant-numeric: tabular-nums; }
.budget-available-amount { font-size: clamp(32px, 10vw, 44px); font-weight: 700; line-height: .98; letter-spacing: -1.5px; }
.budget-available-label { color: var(--text-2); font-size: clamp(14px, 4.2vw, 17px); font-style: italic; font-weight: 550; white-space: nowrap; }
.budget-approved { margin: 8px 0 12px; color: var(--text-2); font-size: 12px; font-variant-numeric: tabular-nums; text-align: center; }
.budget-card-blocked { border-color: var(--warn); }
.budget-blocked-status { margin: 14px 0 4px; color: var(--warn); font-size: 13px; font-weight: 700; text-align: center; }
.budget-meter { height: 8px; border-radius: 4px; }
.budget-reset { margin-top: 7px; color: var(--text-3); font: 12px/1.35 var(--mono); font-variant-numeric: tabular-nums; text-align: right; }
.budget-warning { display: grid; gap: 2px; margin-top: 13px; padding: 12px 12px; border-radius: 12px; background: var(--warn-bg); color: var(--warn); }
.budget-warning strong { font-size: 12px; }
.budget-warning span { font-size: 12px; line-height: 1.4; }
.end-budget-button { margin-top: 14px; color: var(--red); border-color: color-mix(in srgb, var(--red) 30%, var(--rule)); }
.budget-empty { margin-bottom: 3px; }

.budget-composer { margin-bottom: 17px; padding: 16px; border: 1px solid var(--rule); border-radius: 17px; background: var(--card-face); }
.budget-form h2, .budget-review h2 { margin: 0 0 15px; font: 700 19px/1.2 var(--serif); }
.budget-field { margin-top: 13px; }
.budget-field > label { display: block; margin: 0 0 6px; color: var(--text-2); font-size: 12px; font-weight: 700; }
.budget-field input, .budget-field select {
  display: block;
  width: 100%;
  min-width: 0;
  min-height: 48px;
  padding: 12px 12px;
  border: 1px solid var(--rule);
  border-radius: 12px;
  background: var(--paper);
  color: var(--ink);
  font-size: 16px;
}
.budget-field input[aria-invalid="true"], .budget-field select[aria-invalid="true"] { border-color: var(--red); }
.budget-field-help, .budget-field-error { margin-top: 5px; font-size: 12px; line-height: 1.35; }
.budget-field-help { color: var(--text-3); }
.budget-field-error { color: var(--red); font-weight: 650; }
.budget-form-actions { display: grid; grid-template-columns: minmax(0, .75fr) minmax(0, 1.25fr); gap: 9px; margin-top: 18px; }
.budget-primary-button, .end-budget-button {
  width: 100%;
  min-height: 44px;
  padding: 12px 13px;
  border: 1px solid var(--ink);
  border-radius: 22px;
  font-weight: 750;
  cursor: pointer;
}
.budget-primary-button { background: var(--ink); color: var(--paper); }
.end-budget-button { background: transparent; }
.budget-primary-button:disabled, .end-budget-button:disabled { cursor: wait; opacity: .46; }
.budget-review-list { margin: 0; }
.budget-review-scope { margin: -4px 0 13px; color: var(--text-2); font-size: 12px; line-height: 1.45; }
.budget-review-row { display: grid; grid-template-columns: minmax(88px, .4fr) minmax(0, 1fr); gap: 12px; padding: 9px 0; border-bottom: 1px solid var(--rule); }
.budget-review-row dt { color: var(--text-3); font-size: 12px; }
.budget-review-row dd { min-width: 0; margin: 0; color: var(--ink); font-size: 12px; font-weight: 650; }
.budget-submit-error { margin-top: 13px; padding: 12px 12px; border-radius: 12px; background: var(--red-bg); color: var(--red); font-size: 12px; font-weight: 650; }
.budget-composition { margin-top: 5px; color: var(--text-2); font-size: 12px; line-height: 1.4; }

.budget-ledger { margin-top: 24px; }
.budget-ledger-empty { margin: 0; padding: 18px 2px; color: var(--text-2); font-size: 12px; }
.budget-ledger-note { margin: 0 0 6px; color: var(--text-3); font-size: 12px; line-height: 1.5; }
.budget-ledger-row {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr) auto;
  grid-template-areas:
    "provider copy state"
    "provider cost cost"
    ". time time";
  align-items: start;
  gap: 5px 9px;
  min-width: 0;
  min-height: 82px;
  padding: 12px 0;
  border-bottom: 1px solid var(--rule);
}
.budget-ledger-row > .provider-mark { grid-area: provider; }
.budget-ledger-copy { grid-area: copy; min-width: 0; }
.budget-ledger-row > .pill { grid-area: state; }
.budget-ledger-cost { grid-area: cost; display: flex; flex-wrap: wrap; align-items: baseline; gap: 3px 7px; min-width: 0; }
.budget-ledger-estimate { color: var(--ink); font: 700 13px/1.3 var(--serif); font-variant-numeric: tabular-nums; }
.budget-ledger-reserved { color: var(--text-3); font-size: 12px; font-variant-numeric: tabular-nums; }
.budget-ledger-reserved::before { content: "· "; }
.budget-ledger-time { grid-area: time; color: var(--text-3); font: 12px/1.4 var(--mono); font-variant-numeric: tabular-nums; }

.login-main { display: grid; min-height: 100vh; padding: max(44px, env(safe-area-inset-top)) 20px max(36px, env(safe-area-inset-bottom)); place-items: center; }
.login-card { width: min(100%, 390px); text-align: center; }
.login-wordmark { margin: 0; font: italic 600 44px/.95 var(--serif); letter-spacing: -1.8px; }
.login-card h1 { margin: 12px 0 0; font: 650 24px/1.2 var(--serif); }
.login-rule { width: 48px; height: 2px; margin: 21px auto; background: var(--red); }
.btn-google {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  width: 100%;
  min-height: 50px;
  padding: 12px 16px;
  border-radius: 25px;
  background: var(--ink);
  color: var(--paper);
  font-size: 13px;
  font-weight: 700;
  text-decoration: none;
}
.btn-google svg { flex: 0 0 18px; padding: 2px; border-radius: 50%; background: #fff; }
.fallback { margin-top: 18px; }
.fallback summary { min-height: 44px; padding: 12px; color: var(--text-2); font-size: 12px; text-decoration: underline; cursor: pointer; list-style: none; }
.fallback summary::-webkit-details-marker { display: none; }
.fallback form { margin-top: 5px; text-align: left; }
.fallback label { display: block; margin: 0 0 6px; color: var(--text-3); font-size: 12px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; }
input[type="password"] {
  width: 100%;
  min-height: 48px;
  margin-bottom: 9px;
  padding: 12px 14px;
  border: 1px solid var(--rule);
  border-radius: 12px;
  background: var(--card-face);
  color: var(--ink);
}
.login-footnote { max-width: 300px; margin: 24px auto 0; color: var(--text-3); font-size: 12px; line-height: 1.5; }
.login-error { margin: 12px 0 0; padding: 12px 12px; border-radius: 12px; background: var(--red-bg); color: var(--red); font-size: 12px; }

.toast {
  position: fixed;
  z-index: 60;
  right: 16px;
  bottom: calc(82px + env(safe-area-inset-bottom));
  left: 16px;
  width: fit-content;
  max-width: calc(100vw - 32px);
  margin: auto;
  padding: 12px 14px;
  border-radius: 12px;
  background: var(--ink);
  color: var(--paper);
  box-shadow: var(--shadow);
  font-size: 12px;
  opacity: 0;
  pointer-events: none;
  transform: translateY(8px);
  transition: opacity .18s ease, transform .18s ease;
}
.toast.show { opacity: .96; transform: translateY(0); }

@media (min-width: 700px) {
  main { padding-top: 28px; }
  .approval-deck { margin-right: 0; margin-left: 0; padding-right: 0; padding-left: 0; }
  .approval-card { flex-basis: 540px; }
  body:not([data-page="login"]) main { padding-bottom: 118px; }
}

@media (max-width: 600px) {
  .banner { gap: 9px; padding: 12px 12px; }
  /* Five tab labels, none of which may be clipped: on a phone the strip gives each tab the width
     of its own word rather than an equal fifth, which is narrower than "Notifications" and left it
     lying over its neighbour. */
  .tabbar { grid-template-columns: repeat(5, auto); }
  /* A parameter key is one unbroken token, and no phone column is wide enough to hold the longest
     one beside its value: the key leads its own line rather than breaking mid-word. */
  .param-row { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .banner strong { display: block; line-height: 1.3; }
  .capacity-commitment-row .row-value small { line-height: 1.25; }
  .run-terminate { align-items: stretch; flex-direction: column; }
  .run-terminate-button { align-self: flex-end; }
}

@media (orientation: landscape) and (max-height: 540px) {
  .login-main { padding-top: 20px; padding-bottom: 20px; place-items: start center; }
  .approval-card { flex-basis: min(76vw, 540px); }
}

@media (max-width: 390px) {
  .top { padding-right: 14px; padding-left: 14px; }
  main { padding-right: 16px; padding-left: 16px; }
  .tabbar { padding-right: 2px; padding-left: 2px; }
  /* A head row's fixed part takes a line of its own here rather than squeezing the copy beside it,
     and the longest status pill may take two lines rather than none. */
  .workload-head .pill { white-space: normal; }
  .storage-row { grid-template-columns: 22px minmax(0, 1fr); }
  .storage-row > .row-value { grid-row: 2; grid-column: 2; text-align: left; }
  .capacity-commitment-row { grid-template-columns: minmax(0, 1fr); grid-template-areas: "copy" "window" "summary"; }
  .capacity-window { min-width: 0; text-align: left; }
  .approval-deck { margin-right: -16px; margin-left: -16px; padding-right: 16px; padding-left: 16px; }
  .spend-summary { grid-template-columns: 1fr; gap: 8px; }
  .quote-number { font-size: 48px; }
  .utility { padding: 0 6px; }
  .budget-card, .budget-composer { padding-right: 13px; padding-left: 13px; }
  .budget-card-head { gap: 8px; }
  .budget-expiry { font-size: 12px; }
}

@media (max-width: 360px) {
  /* A tab label is one unbreakable word, so the strip's narrowest single row is the five words laid
     end to end — 340 px in the fallback sans an engine picks when the Apple UI stack is absent, past
     the 320 px screen. Neither give is available: a label may not be clipped, and the reflow
     contract holds every leaf label at 12 px or more. So the strip takes a second row here, three
     tabs then two, and `main` reserves its height. */
  .tabbar { grid-template-columns: repeat(3, auto); }
  body:not([data-page="login"]) main { padding-bottom: calc(160px + env(safe-area-inset-bottom)); }
}

@media (max-width: 340px) {
  .budget-form-actions { grid-template-columns: 1fr; }
  .budget-available-label { display: block; margin-top: 5px; white-space: normal; }
  .budget-review-row { grid-template-columns: 76px minmax(0, 1fr); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { scroll-behavior: auto !important; transition-duration: .01ms !important; animation-duration: .01ms !important; }
}

/* Fixed backdrop blurs are disproportionately expensive on phone GPUs while scrolling. The same
   surfaces stay visually solid on the phone-first layout without forcing continuous recompositing. */
@media (max-width: 800px) {
  .top {
    background: var(--paper);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .tabbar {
    background: var(--card-face);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

/* Let the browser defer layout/paint for long bounded ledgers until rows approach the viewport. */
@supports (content-visibility: auto) {
  .resource-row, .history-row, .budget-ledger-row {
    content-visibility: auto;
    contain-intrinsic-size: auto 72px;
  }
  .budget-card {
    content-visibility: auto;
    contain-intrinsic-size: auto 310px;
  }
}

/* --------------------------------------------------------------- notification inbox (#41) */
.notification-list { margin-top: 8px; }
.notification-row {
  padding: 13px 0 14px;
  border-bottom: 1px solid var(--rule);
}
.notification-row.unread { border-left: 2px solid var(--blue); padding-left: 12px; margin-left: -14px; }
.notification-row.focused { background: var(--blue-bg); border-radius: 12px; padding-left: 12px; padding-right: 12px; }
.notification-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 4px;
}
.notification-head .spacer { flex: 1; }
.notification-head .unread-dot {
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--blue);
}
.notification-kind {
  color: var(--text-3);
  font: 650 12px/1 var(--mono);
  letter-spacing: .04em;
  text-transform: uppercase;
}
.notification-head .js-relative-time { color: var(--text-3); font: 12px/1 var(--mono); }
.notification-title { font: 650 13px/1.3 var(--serif); color: var(--ink); }
.notification-body { margin-top: 4px; color: var(--text-2); font-size: 12px; line-height: 1.4; white-space: pre-line; }
.notification-items { display: grid; gap: 8px; white-space: normal; }
.notification-item + .notification-item { padding-top: 8px; border-top: 1px solid var(--rule); }
.notification-item-key { color: var(--ink); font: 650 12px/1.3 var(--mono); }
.notification-item-summary, .notification-item-rest, .notification-line { margin: 3px 0 0; }
.notification-item-more > summary { display: flex; align-items: center; min-height: 44px; color: var(--text-2); font-weight: 700; cursor: pointer; }
.notification-facts { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 3px 12px; margin: 9px 0 0; font-size: 12px; }
.notification-facts dt { color: var(--text-3); font-weight: 700; }
.notification-facts dd { margin: 0; }
.severity-critical { color: var(--red); }
.severity-warning, .severity-action_required { color: var(--warn); }
.notification-actions { display: flex; align-items: center; gap: 14px; margin-top: 9px; }
.notification-link { color: var(--blue); font: 650 12px/1 var(--sans); text-decoration: none; }
.notification-link:hover { text-decoration: underline; }
.notification-mark {
  padding: 0;
  border: 0;
  background: none;
  color: var(--text-2);
  font: 650 12px/1 var(--sans);
  cursor: pointer;
}
.notification-mark:hover { color: var(--ink); }
.workload-card { margin-top: 12px; padding: 14px; border: 1px solid var(--rule); border-radius: 14px; background: var(--card-face); }
.workload-head { display: flex; align-items: flex-start; gap: 12px; }
.workload-head .pill { margin-left: auto; }
.workload-fact { display: grid; gap: 2px; min-width: 0; }
.workload-fact-label { color: var(--text-3); font-size: 12px; font-weight: 700; text-transform: uppercase; }
.workload-detail-link, .storage-action { display: inline-block; margin-top: 12px; color: var(--blue); font-size: 12px; font-weight: 700; }
.storage-costs { display: flex; flex-wrap: wrap; gap: 12px 24px; grid-column: 2 / -1; width: 100%; }
.storage-warning { display: grid; grid-column: 2 / -1; gap: 3px; padding: 9px 12px; border-radius: 9px; background: var(--warn-bg); color: var(--warn); font-size: 12px; }
.storage-warning.critical { background: var(--red-bg); color: var(--red); }
.storage-evidence, .storage-action, .storage-refusal { grid-column: 2 / -1; }
.budget-refusal { display: grid; gap: 4px; }
.budget-refusal-evidence { font-family: var(--mono); font-size: 12px; }
.workload-fact strong { font: 650 14px/1.25 var(--serif); }
.workload-warning { display: grid; gap: 3px; margin-top: 12px; padding: 9px 12px; border-radius: 9px; background: var(--warn-bg); color: var(--warn); font-size: 12px; }
.workload-warning.critical { background: var(--red-bg); color: var(--red); }
.workload-warning.info { background: var(--blue-bg); color: var(--blue); }

/* The ONE run card. Field order is fixed — identity, timeline, decision, money, owner actions — so
   two runs are compared down a column rather than hunted for. A request still awaiting the owner
   leads the list and carries the accent rule that says so. */
.ceiling-hero .burn-scope { margin-top: 9px; }
.ceiling-none { margin: 0; color: var(--text-2); font-size: 12px; line-height: 1.45; }
.run-list { margin-top: 21px; }
.run-card.is-pending { border-color: color-mix(in srgb, var(--blue) 42%, var(--rule)); border-left-width: 3px; }
.run-title { font: 650 13px/1.3 var(--mono); }
.run-shape { text-transform: none; }
.run-timeline {
  margin-top: 10px;
  color: var(--text-2);
  font: 12px/1.6 var(--mono);
  font-variant-numeric: tabular-nums;
}
.run-timeline-stamp { color: var(--ink); }
.run-timeline-gap, .run-timeline-zone { color: var(--text-3); }
.run-timeline-hard { color: var(--warn); font-weight: 700; }
.run-decision { margin-top: 10px; display: grid; gap: 2px; }
.run-decided-by { color: var(--ink); font-size: 12px; font-weight: 650; }
.run-rate, .run-max { color: var(--text-2); font-size: 12px; line-height: 1.4; font-variant-numeric: tabular-nums; }
.run-money { margin-top: 10px; color: var(--text-2); font-size: 12px; font-variant-numeric: tabular-nums; }
.run-money-amount { color: var(--ink); font: 700 15px/1.2 var(--serif); }
.run-money.is-zero { color: var(--text-3); }
.run-card .decision-actions { margin-top: 13px; }
.runs-elsewhere { margin: 21px 0 0; font-size: 12px; }
.runs-elsewhere a { color: var(--blue); font-weight: 700; }
/* The TRANSFER line of an approval card: the other half of the money, beside compute, never folded
   into it. `transfer-unknown` is the honest no-declaration/no-rate state and must never read as $0. */
.transfer-line { margin: 9px 0; padding: 8px 12px; border-radius: 8px; background: var(--card-face); border: 1px solid var(--rule); font: 12px/1.5 var(--mono); text-align: left; }
.transfer-line.transfer-unknown { color: var(--text-3); }
.transfer-line.transfer-dominated { border-color: color-mix(in srgb, var(--warn) 35%, var(--rule)); background: var(--warn-bg); color: var(--warn); }
.transfer-head { font-size: 12px; color: var(--ink); }
.transfer-line.transfer-dominated .transfer-head { color: var(--warn); }
.transfer-amount { font-size: 13px; font-weight: 800; }
.transfer-breakdown { color: var(--text-2); }
.transfer-line.transfer-dominated .transfer-breakdown { color: var(--warn); }
.transfer-flag { margin-top: 5px; font-weight: 700; }

/* ---------------------------------------------------------------------------------------------
   PULL TO REFRESH — the trailing block, owned with public/pwa-pull-refresh.js.
   In standalone (home-screen) mode iOS Safari shows no reload control, so the document-top drag is
   the owner's reload. `overscroll-behavior-y: contain` is what stops iOS bouncing the whole document
   under the gesture; the gesture itself never calls preventDefault, so native scrolling is untouched.
   --------------------------------------------------------------------------------------------- */
html, body { overscroll-behavior-y: contain; }

.pull-refresh {
  position: fixed;
  top: calc(56px + env(safe-area-inset-top));
  left: 0;
  right: 0;
  z-index: 19;
  width: max-content;
  max-width: calc(100% - 24px);
  margin: 0 auto;
  padding: 7px 14px;
  display: flex;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--rule);
  border-radius: 20px;
  background: var(--card-face);
  box-shadow: var(--shadow);
  color: var(--text-2);
  font-size: 12px;
  font-weight: 650;
  opacity: 0;
  pointer-events: none;
  transition: opacity 120ms linear;
}
.pull-refresh[data-state="idle"] { visibility: hidden; }
.pull-refresh[data-state="pulling"] { opacity: .55; }
.pull-refresh[data-state="ready"] { opacity: 1; border-color: var(--blue); color: var(--ink); }
.pull-refresh[data-state="busy"] { opacity: 1; color: var(--ink); }

.pull-refresh-spinner {
  width: 13px;
  height: 13px;
  flex: none;
  border: 2px solid var(--rule);
  border-top-color: var(--blue);
  border-radius: 50%;
}
.pull-refresh[data-state="busy"] .pull-refresh-spinner { animation: pull-refresh-spin 720ms linear infinite; }
@keyframes pull-refresh-spin { to { transform: rotate(360deg); } }

/* Reduced motion: the indicator still says what it is doing, it just does not move or spin. */
@media (prefers-reduced-motion: reduce) {
  .pull-refresh { transition: none; }
  .pull-refresh[data-state="busy"] .pull-refresh-spinner { animation: none; border-top-color: var(--blue); }
}
