/**
 * Backup & Restore workspace — 1.0.30
 * Shared grammar (rail / detail / kpi / tabs / dialog) lives in cx-base.css.
 * Only what is Backup's alone is below; every class here is bk-.
 */
.bk-spooler { display: grid; gap: var(--sp-3); }
.bk-spooler-state { display: flex; align-items: center; gap: var(--sp-2); font-weight: 600; }
.bk-spooler-reason { color: var(--cx-fg-muted); font-size: 12.5px; line-height: 1.5; overflow-wrap: anywhere; }
.bk-spooler-reason[data-tone="danger"] { color: var(--danger); }
.bk-grains { display: flex; flex-wrap: wrap; gap: 6px; }
.bk-note-toggle { display: inline-flex; align-items: center; gap: 4px; }
.bk-note-body { margin-top: 6px; padding: 8px 10px; border: 1px solid var(--cx-hairline); border-radius: var(--cx-r-md); background: var(--cx-muted); font-size: 12.5px; white-space: pre-wrap; overflow-wrap: anywhere; }
.bk-token { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; background: var(--cx-muted); border: 1px solid var(--cx-hairline); border-radius: var(--cx-r-md); padding: 10px 12px; color: var(--cx-fg); user-select: all; overflow-wrap: anywhere; }
#backup-root.is-refreshing #bk-refresh svg { animation: cx-rotate 1s linear infinite; }
@media (prefers-reduced-motion: reduce) { #backup-root.is-refreshing #bk-refresh svg { animation: none; } }

/* Task 12 (view-restores.js / view-agents.js) -- carried over from
   additions.css's legacy-prefixed equivalents, renamed to `bk-*` because these
   two files are held to the legacy-prefix shell guard in full. Same colours,
   same box model; `.bk-tl-*` (the recovery-timeline source marker) has no
   rule here, matching its legacy `tl-*` predecessor, which never had one
   either -- it is an identity marker for the DOM, not a paint class. */
.bk-status {
  display: inline-block; padding: 2px 8px; border-radius: 4px;
  font-size: 12px; font-weight: 600; text-transform: uppercase;
}
.bk-rp-ok { color: var(--success); }
.bk-rp-warn { color: var(--warning); }
.bk-rp-bad { color: var(--danger); }
.bk-rp-none { color: var(--text-3); }
.bk-small { font-size: 11px; margin-top: 2px; }
.bk-muted { color: var(--text-3); font-size: 13px; }
.bk-err { color: var(--danger); font-size: 12px; }
.bk-phase {
  display: inline-block; padding: 2px 8px; border-radius: 4px;
  font-size: 12px; font-weight: 600; text-transform: uppercase;
  background: var(--bg-elevated); color: var(--text-2);
}
.bk-phase-ok { background: var(--success-bg); color: var(--success); }
.bk-phase-bad { background: var(--danger-bg); color: var(--danger); }
.bk-phase-busy { background: var(--accent-dim); color: var(--accent); }
.bk-phase-warn { background: var(--warning-bg); color: var(--warning); }
.bk-phase-none { background: var(--bg-elevated); color: var(--text-3); }
.bk-instance {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  /* A table cell in this family does not wrap by default, and
     host:port plus a state chip plus a Copy button does not fit a
     narrow column -- wrapping inside the cell is what keeps the table
     off a horizontal scrollbar at 390px. */
  white-space: normal;
}
.bk-instance-addr {
  font-family: var(--font-mono, monospace); font-size: 12px; color: var(--text-1);
  background: var(--bg-elevated); border-radius: 3px; padding: 1px 5px;
  /* An address is one token an operator pastes; breaking it mid-host
     makes it unreadable, so it is allowed to overflow its own box. */
  word-break: break-all;
}
.bk-instance .bk-copy { padding: 1px 6px; font-size: 11px; }
.bk-instance .bk-small { flex-basis: 100%; margin-top: 0; }

/* Task 12 (view-agents.js) -- carried over from additions.css's
   the legacy `activity*` rules (the Recent Backups / Backup Agents rows). */
.bk-activity { list-style: none; margin: 0; padding: 0; max-width: 860px; }
.bk-activity-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 7px 0; border-bottom: 1px solid var(--cx-hairline);
}
.bk-activity-row:last-child { border-bottom: none; }
.bk-activity-main {
  flex: 1 1 auto; min-width: 0; font-size: 13px; color: var(--text-1);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The metas group (target, last contact, Revoke) may shrink to the row and
   wrap inside it. It was `flex: 0 0 auto` with unwrappable metas, so on a
   phone it dropped to its own line still wider than the row and the card cut
   the Revoke button off (S3-17 F5: at 360 px the row ended at x=321 and Revoke
   sat at x=337-485). `max-width: 100%` caps it at the row, `flex-wrap` lets the
   button move to its own line, and a meta longer than the row is ellipsised. */
.bk-activity-metas {
  display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px;
  margin-left: auto; flex: 0 1 auto; min-width: 0; max-width: 100%;
}
.bk-activity-meta {
  font-size: 12px; color: var(--text-3); white-space: nowrap;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis;
}
@media (max-width: 640px) { .bk-activity-row { gap: 6px; } }

/* ============================================================
   Carried from additions.css's BACKUP & RESTORE block at cutover
   (Task 13a). Selectors renamed off the legacy prefix onto bk-;
   declarations verbatim.
   ============================================================ */
/* The legacy `muted` rule's declarations (additions.css:5878) are byte-identical
   to .bk-muted above (line 32, Task 12) -- reused, not duplicated.
   The legacy `sr-only` rule (additions.css:6278) is not carried: cx-base.css
   already provides `.cx-root .sr-only`; the markup renames to that
   instead (controller ruling, task-13a-brief.md). */
.bk-table .bk-empty {
    text-align: center;
    color: var(--text-3);
    padding: 32px;
}
.bk-coverage {
    margin-top: 4px;
    font-size: 12px;
    line-height: 1.4;
    font-weight: 400;
    text-transform: none;
    white-space: normal;
    max-width: 34ch;
    /* A database name is up to 63 bytes and carries no spaces, so it is one
       unbreakable token: without this it sets the cell's min-content width
       and pushes the whole 9-column table wider. Measured at 390px -- the
       coverage line added 18px to a table already scrolling inside its
       container, and `overflow-wrap: anywhere` takes that to 0. `anywhere`
       rather than `break-word` because only `anywhere` is honoured when
       min-content is being computed, which is exactly the calculation
       causing the widening. */
    overflow-wrap: anywhere;
}
.bk-coverage-ok { color: var(--text-3); }
.bk-coverage-gap { color: var(--warning); }
.bk-coverage-gap strong { font-weight: 600; }
.bk-coverage-count { color: var(--text-3); }
.bk-modal-backdrop {
    position: fixed; inset: 0; background: rgba(0, 0, 0, 0.6);
    display: flex; align-items: center; justify-content: center; z-index: 9999;
}
.bk-modal-card {
    background: var(--bg-card); border: 1px solid var(--border);
    border-radius: 12px; padding: 24px;
    /* `min-width` always beats `max-width`, so `min-width: 400px` held the
       card at 400px inside a 320px viewport and pushed the page into a
       horizontal scroll -- WCAG 1.4.10 -- on a dialog that takes a BYOK
       passphrase. `min()` lets it shrink with the viewport while keeping
       400px wherever there is room. */
    min-width: min(400px, 100%); max-width: 90vw;
}
.bk-modal-card h3 { margin: 0 0 16px 0; color: var(--text-1); }
.bk-modal-card label { display: block; color: var(--text-2); margin-bottom: 6px; font-size: 13px; }
.bk-modal-card input[type="password"] {
    width: 100%; padding: 10px 12px; border-radius: 6px;
    background: var(--bg-elevated); border: 1px solid var(--border);
    color: var(--text-1); font-family: monospace;
}
.bk-modal-warning {
    color: var(--text-2); font-size: 12px; margin: 12px 0;
    background: rgba(211, 158, 87, 0.08); border-left: 3px solid var(--accent);
    padding: 8px 12px; border-radius: 4px;
}
.bk-modal-actions {
    display: flex; gap: 12px; justify-content: flex-end; margin-top: 16px;
}
.bk-modal-wide { min-width: min(520px, 100%); max-width: 640px; }
.bk-form-body { display: flex; flex-direction: column; gap: 10px; max-height: 60vh; overflow-y: auto; }
.bk-form-body label { display: block; color: var(--text-2); font-size: 13px; margin-top: 4px; }
.bk-form-body input[type="text"],
.bk-form-body input[type="password"],
.bk-form-body input[type="number"],
.bk-form-body select,
.bk-form-body textarea {
    width: 100%; padding: 8px 10px; border-radius: 6px;
    background: var(--bg-elevated); border: 1px solid var(--border);
    color: var(--text-1); font-size: 13px;
}
.bk-form-body input[type="checkbox"] { width: auto; margin-right: 6px; }
.bk-hint {
    display: block;
    font-size: 11px;
    color: var(--text-3);
    margin-top: 2px;
    overflow-wrap: anywhere;
}
.bk-gfs-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; margin-top: 8px; }
.bk-gfs-grid label { display: flex; flex-direction: column; gap: 4px; font-size: 11px; text-transform: uppercase; }
.bk-stg-cfg { padding: 8px 0; border-top: 1px dashed var(--border); margin-top: 8px; }
.bk-pitr-unavailable {
    margin-top: 12px;
    padding: var(--sp-3) var(--sp-4);
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    color: var(--text-3);
    font-size: 12px;
    line-height: 1.5;
}
.bk-pitr-unavailable-heading {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-2);
    margin-bottom: 8px;
    letter-spacing: .5px;
}
.bk-pitr-unavailable p { margin: 0 0 8px; }
.bk-pitr-unavailable p:last-child { margin-bottom: 0; }
.bk-ah-badge {
    font-size: 11px;
    font-weight: 600;
    padding: 1px var(--sp-2);
    border-radius: var(--radius-md);
    border: 1px solid transparent;
    white-space: nowrap;
}
/* Fix round 1: the five tones missed by the class-only census (task-13a-
   report.md). `.bk-ah-badge bk-ah-<tone>` is built dynamically --
   `'bk-ah-' + st.tone` -- by `drSiteWindowStateFor` (format.js) and
   `drReplicationStateFor` (format.js, read by dialogs.js's
   `_renderEvidencePack`), so no complete `bk-ah-ok`-shaped token was ever
   literal text in the family for the original census to find; it saw only
   the dangling legacy `ah-` prefix and filed it as an unstyled hook. Moved
   verbatim, selector renamed only, same as every other rule in this file. */
.bk-ah-ok {
    color: var(--success);
    background: var(--success-bg);
    border-color: var(--success-border);
}
.bk-ah-warn {
    color: var(--warning);
    background: var(--warning-bg);
    border-color: var(--warning-border);
}
.bk-ah-bad {
    color: var(--danger);
    background: var(--danger-bg);
    border-color: var(--danger-border);
}
.bk-ah-not-applicable {
    color: var(--text-3);
    background: var(--bg-elevated);
    border-color: var(--border);
}
.bk-ah-unknown {
    color: var(--info);
    background: var(--info-bg);
    border-color: var(--info-border);
}
.bk-ah-pending {
    color: var(--text-3);
    background: transparent;
    border-color: var(--border);
    border-style: dashed;
}
.bk-objbrowse { margin: var(--sp-2) 0; }
.bk-objbrowse-list {
    max-height: 220px; overflow-y: auto;
    border: 1px solid var(--border); border-radius: var(--r-lg);
    padding: var(--sp-2); margin-top: var(--sp-2);
    background: var(--bg-elevated);
    display: flex; flex-direction: column; gap: 2px;
}
.bk-objbrowse-list .bk-check { font-size: 12px; }
.bk-objbrowse-list code {
    color: var(--text-3); font-family: var(--font-mono); margin-right: 4px;
}
.bk-token-box {
    width: 100%; resize: vertical;
    font-family: var(--font-mono); font-size: 12px; line-height: 1.5;
    color: var(--text-1); background: var(--bg-card);
    border: 1px solid var(--border-mid); border-radius: var(--r-lg);
    padding: var(--sp-2); white-space: pre-wrap; word-break: break-all;
}
.bk-token-box:focus { outline: none; border-color: var(--accent); }
.bk-attention {
    background: var(--accent-dim);
    border: 1px solid var(--border-accent);
    border-radius: var(--cx-r-md); padding: 14px 16px; margin-bottom: 16px;
}
.bk-attention-title {
    font-size: 12px; font-weight: 700; letter-spacing: .5px;
    text-transform: uppercase; color: var(--accent); margin-bottom: 8px;
}
.bk-attention ul { margin: 0; padding-left: 18px; }
.bk-attention li { color: var(--text-2); font-size: 13px; margin-bottom: 4px; }
.bk-allgood {
    background: var(--success-bg);
    border: 1px solid var(--success-border);
    border-radius: var(--cx-r-md); padding: 12px 16px; margin-bottom: 16px;
    color: var(--text-2); font-size: 13px;
}
.bk-check {
    display: flex !important; align-items: center; gap: 8px;
    margin: 10px 0; font-size: 13px; color: var(--text-2); cursor: pointer;
}
.bk-check input { width: auto !important; margin: 0; }
.bk-modal-note {
    margin-top: 10px; font-size: 12px; color: var(--text-3); line-height: 1.5;
}
.bk-modal-card select {
    width: 100%; padding: 9px 12px; border-radius: 6px; margin-bottom: 12px;
    background: var(--bg-elevated); border: 1px solid var(--border); color: var(--text-1);
}
.bk-target-row {
    display: flex;
    flex-direction: column;
    gap: 7px;
    padding: 10px 0;
    border-bottom: 1px solid var(--border);
    min-width: 0;
}
.bk-target-row:last-child { border-bottom: none; }
.bk-target-row .bk-ah-badge,
.bk-target-row .cx-badge {
    display: inline-flex;
    align-items: center;
    line-height: 16px;
    flex: 0 0 auto;
}
.bk-scope-unknown { font-size: 12px; flex: 0 0 auto; }
.bk-pitr-point {
    border: 1px solid var(--border);
    border-radius: var(--cx-r-md);
    padding: 10px 12px;
    margin: 8px 0;
}
.bk-pitr-point legend { font-size: 12px; color: var(--text-3); padding: 0 4px; }
.bk-pitr-timeline {
    border: 1px solid var(--border);
    border-radius: var(--cx-r-md);
    padding: 10px 12px;
    margin: 8px 0;
}
.bk-pitr-timeline legend { font-size: 12px; color: var(--text-3); padding: 0 4px; }
.bk-pitr-timeline-opt {
    display: block;
    margin: 6px 0;
    cursor: pointer;
    color: var(--text-2);
    font-size: 13px;
}
.bk-pitr-timeline-opt input { width: auto; margin-right: 6px; vertical-align: middle; }
.bk-pitr-timeline-stale { color: var(--warning); font-weight: 600; }
/* Two id-selector rules additions.css's class-only census (task-13a-
   css-map.md) did not list: it enumerated legacy-prefixed CLASS occurrences, and
   these are legacy-prefixed ID selectors -- the restore modal's database
   multi-select and its object-filter input, both still live in
   dialogs.js's `_openRestoreModal`. Leaving them behind would have
   unstyled a <select multiple> and a disabled <input> the moment the
   sed below ran -- the exact defect class this module exists to
   guard against (a bare control taking the UA's white background on
   a dark page). Discovered by cross-referencing every family-emitted
   token against additions.css's actual selectors, not by re-reading
   the map. */
#bk-restore-databases {
    width: 100%;
    background: var(--bg-elevated);
    color: var(--text-1);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 6px;
    font-size: 13px;
    /* The sheet's `*, ::before, ::after { box-sizing: border-box }` reset
       collapses a `<select multiple size=N>`: the UA sizes it to N rows as
       CONTENT height and border-box then subtracts the padding and border
       from that rather than adding to them. Measured in a real browser --
       the picker painted at 14px, ONE clipped line, while size=4 and four
       options were present. The DOM read perfectly; only the screenshot
       showed the grey sliver, which is the fifth time this module has
       needed a painted result rather than a DOM read.
       Fixed with an explicit height range, NOT by switching to
       content-box: that was tried and measured 604px against every sibling
       control's 590px, overflowing the form body -- one control 14px wider
       than the rest of the dialog. Width has to keep the reset's behaviour;
       only the height is stated here. Roughly four rows, scrolling beyond,
       which keeps the dialog usable at 390px where the whole card is
       388px wide. */
    height: auto;
    min-height: 5.8em;
    max-height: 11em;
}
#bk-restore-databases option { padding: 3px 4px; }
#bk-restore-objects:disabled {
    opacity: 0.55;
    cursor: not-allowed;
}

/* Detail KPI strip: the visible reason an absent figure carries (a bare
   dash is unreachable by touch or keyboard and reads as "em dash"). */
.bk-kpi-reason { font-size: 12px; line-height: 1.3; }
/* Connection line: the target's connection is gone (warning), or the
   connection list could not be read (muted -- a failed read, not absence). */
.bk-conn-removed { color: var(--warning); }
.bk-conn-unread { color: var(--cx-fg-subtle); font-style: italic; }
/* The target names no connection: a configuration fact, said in muted prose. */
.bk-conn-none { color: var(--cx-fg-subtle); }
/* The detail head's sub line is monospace for host:port; a sentence there
   ("no connection recorded", "control plane") is prose, not an identifier. */
.cx-detail-sub.bk-conn-prose { font-family: inherit; }

/* Detail head actions. Without wrap, a disabled Restore plus its reason
   squeezed the kebab to 16px at 390px (measured), below the 28px control
   it is meant to be; the ancestors clip, so it could be pushed out of
   reach. The buttons keep their size and the reason takes its own line
   after the kebab. Scoped to #backup-root so the Connections head is
   unchanged. */
#backup-root .cx-detail-actions { flex-wrap: wrap; justify-content: flex-end; row-gap: 4px; }
#backup-root .cx-detail-actions > .cx-btn { flex-shrink: 0; }
.bk-restore-reason { flex-basis: 100%; order: 1; font-size: 12px; text-align: right; }

/* The workspace notice (#bk-notice): a refusal or failure the operator must
   be able to read and act on, which stays until dismissed or replaced. It
   replaced alert(), which blocked the page and could offer no next step. */
.bk-notice-host:empty { display: none; }
.bk-notice-host { margin: var(--sp-3) 0 0; }
.bk-notice {
    display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between;
    gap: var(--sp-3); padding: var(--sp-3) var(--sp-4);
    border: 1px solid var(--danger-border); background: var(--danger-bg);
    border-radius: var(--cx-r-md); color: var(--text-2); font-size: var(--text-xs);
}
.bk-notice[data-kind="warning"] { border-color: var(--warning-border); background: var(--warning-bg); }
.bk-notice[data-kind="success"] { border-color: var(--success-border); background: var(--success-bg); }
.bk-notice[data-kind="info"] { border-color: var(--info-border); background: var(--info-bg); }
.bk-notice-text { flex: 1 1 260px; min-width: 0; }
.bk-notice-title { font-weight: var(--font-semibold); color: var(--text-1); margin-bottom: var(--sp-1); }
.bk-notice-body { margin: 0; line-height: 1.55; overflow-wrap: anywhere; }
.bk-notice-more { margin: var(--sp-1) 0 0; color: var(--text-3); line-height: 1.55; }
.bk-notice-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }

/* A form modal's refusal region: the backend's words, inside the dialog,
   above its buttons (screenshot 9 printed them in an alert over the form). */
.bk-form-error:empty { display: none; }
.bk-form-error { margin-top: var(--sp-3); }
/* A refusal is not a note: the danger tone, as the #bk-notice error kind. */
.bk-form-refusal { margin-bottom: 0; }
.bk-attention.bk-form-refusal { background: var(--danger-bg); border-color: var(--danger-border); }
.bk-form-refusal .bk-attention-title { color: var(--danger); }
.bk-form-refusal p { margin: 0; color: var(--text-2); font-size: var(--text-xs); line-height: 1.55; overflow-wrap: anywhere; }

/* A failed read: "Could not load <what> — <reason>" and a Retry, never a
   skeleton that stays. */
.bk-load-failed { flex-wrap: wrap; justify-content: space-between; }
.bk-load-failed-text { flex: 1 1 240px; min-width: 0; }
.bk-load-failed-reason { overflow-wrap: anywhere; }
.bk-retry { flex-shrink: 0; }
td.cx-error .bk-retry { margin-left: var(--sp-2); }

/* The live RPO hint under the RPO field of "Edit recovery objectives". */
.bk-rpo-hint:empty { display: none; }
.bk-rpo-hint { margin-top: var(--sp-1); }
.bk-rpo-hint-box {
    padding: var(--sp-2) var(--sp-3); border: 1px solid var(--warning-border);
    background: var(--warning-bg); border-radius: var(--cx-r-md);
}
.bk-rpo-hint-text { margin: 0 0 var(--sp-2); color: var(--text-1); font-size: var(--text-xs); line-height: 1.5; }
.bk-rpo-hint-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

/* Backups tab: a run's own actions (Restore, Delete…). They WRAP rather than
   widen the row: in an auto-layout table that already scrolls at 390px, a
   second button side by side would push the column wider still; wrapped,
   the cell's minimum is its widest button. */
.bk-row-actions { display: flex; flex-wrap: wrap; gap: var(--sp-1); justify-content: flex-end; }
.bk-row-actions > .cx-btn { flex-shrink: 0; }
/* A disabled Delete…'s reason, visible (a disabled button takes no focus and
   no touch hover): on its own line under the buttons. */
.bk-row-reason { flex-basis: 100%; text-align: right; font-size: 12px; }
/* One note above the runs table for a reason every row shares. */
.bk-table-note { margin: 0 0 var(--sp-2); color: var(--text-2); font-size: 12.5px; line-height: 1.5; }

/* Per-target retention (BR-1b): the always-kept note under the effective
   policy, the schedule dialog's "keeps at least" floor, the all-zero
   warning and the Clear row in "Change retention…". */
.bk-ret-note { margin: var(--sp-2) 0; color: var(--text-3); font-size: 12px; line-height: 1.5; }
.bk-ret-floor:empty { display: none; }
.bk-ret-floor { display: block; margin: 0 0 var(--sp-2); }
.bk-ret-zero-box { margin: var(--sp-2) 0 0; }
.bk-ret-clear-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); justify-content: flex-start; margin-top: var(--sp-2); }
.bk-ret-clear-warn { flex: 1 1 220px; }
/* How the policy reaches the backups (enforced_by): the headline, and the
   label over a configured-but-not-applied grid. */
.bk-ret-enforced { margin: 0 0 var(--sp-2); color: var(--text-1); font-size: 13px; line-height: 1.5; }
.bk-ret-sub { margin: 0 0 var(--sp-1); color: var(--text-3); font-size: 12px; }
.bk-ret-not-applied { margin: 0 0 var(--sp-2); color: var(--text-2); font-size: 13px; }

/* "Delete backup run": the run's facts, and the second confirmation the
   backend asks for when this is the target's last restorable run. */
.bk-run-delete-facts { margin: var(--sp-2) 0 var(--sp-3); }
.bk-run-delete-last { margin-top: var(--sp-3); }

/* A deleted run (a tombstone kept for its history): who deleted it and when,
   under its neutral "Deleted" chip; and, in Restores, a restore whose source
   backup was deleted says so beside the run id. */
.bk-deleted-line { margin-top: var(--sp-1); color: var(--text-3); font-size: 12px; line-height: 1.4; overflow-wrap: anywhere; }
/* "Every backup of this target was deleted": a sentence, not a dash. */
.bk-all-deleted { margin: 0 0 var(--sp-2); color: var(--text-2); font-size: 13px; line-height: 1.5; }
.bk-source-deleted { font-size: 12px; white-space: nowrap; }
/* BiharOne #12: freshness reasons can be sentence-length. At phone width a
   right-aligned definition value must wrap inside the card, never widen the
   bento column and push the status/reason off-screen. */
@media (max-width: 700px) {
  #backup-root .cx-dl-row { align-items: flex-start; }
  #backup-root .cx-dl-row > dt { flex: 0 1 42%; min-width: 0; }
  #backup-root .cx-dl-row > dd {
    flex: 0 1 58%;
    min-width: 0;
    max-width: 58%;
    white-space: normal;
    overflow-wrap: anywhere;
  }
}

/* A restore's Data Masking reading (F-DDM-RESTORE), in the Restores table
   and the Run restore dialog. Toned by data-tone; `unknown` is muted, never
   the success colour, because an unassessed restore is not a safe one. */
.bk-mask { font-size: 12px; line-height: 1.45; color: var(--text-2); min-width: 180px; max-width: 320px; }
.bk-mask-line + .bk-mask-line { margin-top: 2px; }
.bk-mask[data-tone="unknown"] { color: var(--text-3); }
.bk-mask[data-tone="ok"] { color: var(--success); }
.bk-mask[data-tone="info"] { color: var(--info); }
.bk-mask[data-tone="warn"] { color: var(--warning); }
.bk-mask[data-tone="danger"] {
    color: var(--danger); background: var(--danger-bg);
    border: 1px solid var(--danger-border); border-radius: 6px; padding: 6px 8px;
}
.bk-mask-exec .bk-mask { max-width: none; padding: 8px 12px; border-radius: 6px; border: 1px solid var(--border); }
.bk-mask-exec .bk-mask[data-tone="warn"] { background: var(--warning-bg); border-color: var(--warning-border); }
.bk-mask-choice { border: 1px solid var(--border); border-radius: 6px; padding: 8px 12px; margin: 0; }
.bk-mask-choice legend { padding: 0 4px; font-size: 13px; color: var(--text-1); font-weight: 600; }

/* Database-node agent surface (forward-port of the 1.0.32 Section I GUI).
   The markup is built by the pure helpers in modules/backup/format.js. Agent
   text (hostnames, member names, notes) is arbitrary, so every text-bearing
   rule here wraps instead of widening the page, and the tables stack into
   label/value cards under 481px using each cell's data-label. */
.bk-pending-failed, .bk-target-nodes-failed { color: var(--warning); }
.bk-overview-card { border: 1px solid var(--border); border-radius: 8px; padding: 12px 16px; margin-bottom: 16px; }
.bk-overview-card h4 { margin: 0 0 8px; font-size: 14px; color: var(--text-1); }
.bk-nodes-card .bk-muted, .bk-nodes-card .bk-empty { margin: 0; overflow-wrap: anywhere; }
.bk-node-table-wrap { overflow-x: auto; }
.bk-node-table { width: 100%; }
.bk-node-table td { overflow-wrap: anywhere; vertical-align: top; }
.bk-node-actions { white-space: nowrap; }
.bk-node-actions .cx-btn + .cx-btn { margin-left: 6px; }
.bk-pairing-code {
    font-family: monospace; font-size: 15px; font-weight: 600; letter-spacing: .08em;
    padding: 2px 6px; border-radius: 4px; background: var(--bg-elevated); color: var(--text-1);
}
.bk-node-identity { display: grid; grid-template-columns: max-content 1fr; gap: 4px 12px; margin: 8px 0; font-size: 13px; }
.bk-node-identity dt { color: var(--text-3); }
.bk-node-identity dd { margin: 0; overflow-wrap: anywhere; }
.bk-target-nodes { display: block; font-size: 12px; margin-top: 6px; overflow-wrap: anywhere; }
.bk-refusals { margin: 8px 0; padding-left: 18px; color: var(--text-2); font-size: 13px; overflow-wrap: anywhere; }
.bk-arch-step { margin-top: 12px; padding-top: 8px; border-top: 1px dashed var(--border); }
.bk-arch-step p { overflow-wrap: anywhere; }
.bk-arch-wait { color: var(--text-2); font-size: 13px; }
.bk-run-warning { margin-top: 4px; font-size: 12px; color: var(--warning); overflow-wrap: anywhere; }
.bk-restore-agent p { margin: 0 0 6px; }
.bk-restore-agent-note { overflow-wrap: anywhere; }
@media (max-width: 480px) {
    .bk-node-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
    .bk-node-table, .bk-node-table tbody, .bk-node-table tr, .bk-node-table td { display: block; width: 100%; }
    .bk-node-table tr { border: 1px solid var(--border); border-radius: 6px; padding: 6px 10px; margin-bottom: 8px; }
    .bk-node-table td[data-label]::before {
        content: attr(data-label); display: block; font-size: 11px; text-transform: uppercase; color: var(--text-3);
    }
    .bk-node-actions { white-space: normal; }
}

/* Database nodes waiting for approval: the banner (a status region on every
   view) and the Agents-view card it points at. The banner wraps instead of
   widening the page; its Review / Retry button keeps its size. */
.bk-pending-banner[hidden] { display: none; }
.bk-pending-banner {
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3);
    margin: var(--sp-3) 0 0; padding: var(--sp-2) var(--sp-4);
    border: 1px solid var(--info-border); background: var(--info-bg); color: var(--text-1);
    border-radius: var(--cx-r-md); font-size: 13px; overflow-wrap: anywhere;
}
.bk-pending-banner .cx-btn { flex-shrink: 0; }
#bk-pending-nodes { margin-bottom: var(--sp-4); }
#bk-pending-nodes:focus { outline: none; }
#bk-pending-nodes:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.bk-pairing-code-large { display: inline-block; font-size: 22px; letter-spacing: .12em; padding: 6px 12px; margin: 4px 0 8px; }

/* Nodes & archiving. The card is wider than the plain form dialogs (a table of
   nodes sits inside it) but never wider than the phone: `.bk-modal-wide` caps
   at 640px with a 100% floor, so on a 360px screen the card is 360px and its
   padding, not the page, takes the squeeze. Content wraps; the body scrolls. */
#bk-nodes-modal .bk-modal-card { max-width: min(720px, calc(100vw - 16px)); box-sizing: border-box; }
#bk-nodes-modal .bk-form-body { max-height: min(70vh, 640px); }
#bk-nodes-modal h4 { margin: 8px 0 4px; font-size: 14px; color: var(--text-1); }
#bk-nodes-modal .bk-hint, #bk-nodes-modal .bk-empty, #bk-nodes-modal p { overflow-wrap: anywhere; }
#bk-nodes-modal #bk-arch-msg:empty { display: none; }
#bk-nodes-modal #bk-arch-msg { font-size: 12px; margin: 0; }
@media (max-width: 480px) {
    #bk-nodes-modal .bk-modal-card { padding: 16px 12px; }
    #bk-nodes-modal .bk-arch-step .cx-btn { width: 100%; white-space: normal; }
    .bk-pending-banner { padding: var(--sp-2) var(--sp-3); }
}

/* Patroni cluster point-in-time restore (PITR-10). Member facts are stacked
   cards, never a table: a member name and an error from its agent are
   arbitrary text, so every text rule wraps instead of widening the page. On
   a desktop the cards sit side by side; on a phone (360/390 px) they stack. */
.bk-member-cards {
    list-style: none; margin: 4px 0 0; padding: 0;
    display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 8px;
}
.bk-member-card {
    border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; min-width: 0;
    display: flex; flex-direction: column; gap: 4px; align-items: flex-start;
}
.bk-member-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; min-width: 0; }
.bk-member-name { font-weight: 600; color: var(--text-1); font-size: 13px; overflow-wrap: anywhere; }
.bk-member-facts { font-size: 12px; color: var(--text-3); overflow-wrap: anywhere; }
.bk-member-error { font-size: 12px; color: var(--danger); overflow-wrap: anywhere; }
.bk-ppitr-panel, .bk-ppitr-summary { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.bk-ppitr-headline { margin: 0; font-size: 14px; font-weight: 600; color: var(--text-1); overflow-wrap: anywhere; }
.bk-ppitr-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.bk-ppitr-note { margin: 0; font-size: 13px; color: var(--text-2); overflow-wrap: anywhere; }
.bk-ppitr-subhead { margin: 4px 0 0; font-size: 13px; color: var(--text-1); overflow-wrap: anywhere; }
/* Round-23b review 2: a long label never takes the row; on a narrow screen
   each label sits above its value, so the value has the whole width.
   drill26 review: between 481 and ~580 px the label still took 307 px and
   left the value 112-171 px, so the label column is capped at 40% of the
   plan and the stacked layout starts at 600 px. */
.bk-ppitr-plan { display: grid; grid-template-columns: fit-content(40%) minmax(0, 1fr); gap: 2px 12px; margin: 0; font-size: 13px; }
.bk-ppitr-plan dt { color: var(--text-3); overflow-wrap: anywhere; }
.bk-ppitr-plan dd { margin: 0; color: var(--text-1); overflow-wrap: anywhere; }
@media (max-width: 600px) {
    .bk-ppitr-plan { grid-template-columns: minmax(0, 1fr); gap: 0; }
    .bk-ppitr-plan dd { margin-bottom: 6px; }
}
.bk-ppitr-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.bk-ppitr-impact { margin: 0; padding-left: 18px; font-size: 13px; color: var(--text-1); }
.bk-ppitr-impact li { margin-bottom: 2px; overflow-wrap: anywhere; }
.bk-ppitr-target, .bk-ppitr-member-list { margin: 0; overflow-wrap: anywhere; }
.bk-ppitr-member-list code { margin-right: 6px; }
.bk-ppitr-members { display: flex; flex-direction: column; gap: 4px; }
.bk-ppitr-point { border: 1px solid var(--border); border-radius: 6px; padding: 8px 12px; margin: 0; min-width: 0; }
.bk-ppitr-time-row { display: flex; flex-wrap: wrap; gap: 8px; }
.bk-ppitr-field { display: flex; flex-direction: column; flex: 1 1 160px; min-width: 0; }
.bk-ppitr-field:last-child { flex: 0 1 96px; }
.bk-ppitr-refusal ul { margin-top: 6px; }
.bk-ppitr-card { margin-bottom: var(--sp-4); }
/* The server's reason the cluster restore is not offered: a sentence, so it
   wraps on its own line under the actions instead of widening the head. */
.bk-ppitr-reason { white-space: normal; overflow-wrap: anywhere; line-height: 1.4; }
/* A step waiting on the archive (archive_check): progress, said plainly. */
.bk-ppitr-waiting { margin: 0; overflow-wrap: anywhere; }
/* At a safe point: the members' own facts, under the server's sentence. */
.bk-ppitr-evidence { margin: 0; color: var(--text-2); overflow-wrap: anywhere; }
.bk-ppitr-item { display: flex; flex-direction: column; gap: 8px; padding: 10px 0; min-width: 0; }
.bk-ppitr-item + .bk-ppitr-item { border-top: 1px solid var(--border); }
#bk-ppitr-progress-modal .bk-modal-card { max-width: min(720px, calc(100vw - 16px)); box-sizing: border-box; }
#bk-ppitr-progress-modal .bk-form-body { max-height: min(70vh, 640px); }
#backup-root .cx-detail-actions > .cx-btn[data-bk-act="patroni-pitr"] { white-space: normal; flex-shrink: 1; max-width: 100%; text-align: left; }
@media (max-width: 479px) {
    .bk-member-cards { grid-template-columns: minmax(0, 1fr); }
    .bk-ppitr-field:last-child { flex: 1 1 100%; }
    #bk-ppitr-progress-modal .bk-modal-card, #bk-form-modal .bk-modal-card { padding: 16px 12px; }
}

/* W7 R1(b): Adopt existing backups. The set list is a plain group in the
   design system's border and radius, not the browser's default fieldset. */
.bk-adopt-sets {
    margin: 12px 0; padding: 4px 12px; min-width: 0;
    border: 1px solid var(--border); border-radius: var(--cx-r-md); background: var(--bg-elevated);
}
.bk-adopt-sets legend { padding: 0 6px; font-size: 12px; color: var(--text-3); }
.bk-adopt-sets .bk-check { align-items: flex-start; overflow-wrap: anywhere; }
.bk-adopt-sets .bk-check input { margin-top: 2px; }

/* W7 G4: archive settings IntelliDB is taking back out of a cluster after the
   target that enabled them was deleted (Agents view card; the banner reuses
   .bk-pending-banner). Steps wrap; the Retry button keeps its size. */
#bk-archiving-releases { margin-bottom: var(--sp-4); }
#bk-archiving-releases:focus { outline: none; }
#bk-archiving-releases:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.bk-releases { list-style: none; margin: 8px 0 0; padding: 0; }
.bk-release { border-top: 1px dashed var(--border); padding: 8px 0; overflow-wrap: anywhere; }
.bk-release:first-child { border-top: 0; }
.bk-release p { margin: 4px 0; font-size: 13px; color: var(--text-2); }
.bk-release-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.bk-release-head .cx-btn { flex-shrink: 0; }
.bk-release-steps { list-style: none; margin: 6px 0; padding: 0; font-size: 13px; }
.bk-release-step { display: flex; align-items: flex-start; gap: 6px; color: var(--text-3); margin: 2px 0; }
.bk-release-step-done { color: var(--success); }
.bk-release-step svg { flex-shrink: 0; margin-top: 2px; }

/* Round-23 review 1: the acknowledged libraries on a restore row. */
.bk-restore-ack code { overflow-wrap: anywhere; }
/* Round-23 review 9: a long library name in a warning wraps at 360 px. */
.bk-modal-card .bk-modal-warning { overflow-wrap: anywhere; }
/* S4-R117/R125/R129: the preloaded libraries a copy would refuse. Names are
   long and unbroken (pg_partman_bgw, timescaledb-2.17): each tick wraps as a
   whole, the name wraps anywhere, the buttons stack at 360 px. */
.bk-preload-ack { border: 1px solid var(--border); border-radius: 6px; padding: 8px 10px; margin: 10px 0; min-width: 0; }
.bk-preload-ack legend { padding: 0 4px; font-weight: 600; }
.bk-preload-list { list-style: none; margin: 6px 0; padding: 0; display: flex; flex-wrap: wrap; gap: 4px 14px; }
.bk-preload-list li { min-width: 0; max-width: 100%; }
.bk-preload-item { display: inline-flex; align-items: center; gap: 6px; min-height: 32px; max-width: 100%; }
.bk-preload-item code { overflow-wrap: anywhere; word-break: break-word; }
.bk-preload-ack input[type="text"] { width: 100%; box-sizing: border-box; }
.bk-preload-actions { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0; }
@media (max-width: 480px) {
    .bk-preload-actions > button { flex: 1 1 100%; white-space: normal; }
}

/* S4-R64 / S4-R79: the shared delete dialog. Owed roots are long paths: they
   wrap rather than widen the dialog on a 360 px screen. */
.bk-delete-reason { margin: 0 0 var(--sp-3); padding: 10px 12px; border: 1px solid var(--cx-hairline); border-radius: var(--cx-r-md); }
.bk-delete-reason h4, .bk-delete-anyway h4 { margin: 0 0 6px; font-size: 13.5px; }
.bk-delete-list { margin: 0 0 6px; padding-left: 18px; }
.bk-delete-list li, .bk-delete-roots code { overflow-wrap: anywhere; word-break: break-word; }
.bk-delete-roots { max-height: 192px; overflow-y: auto; }
.bk-delete-anyway input { width: 100%; max-width: 100%; box-sizing: border-box; }
.bk-delete-reason .bk-delete-turn-off { max-width: 100%; white-space: normal; }
.bk-release-offline { color: var(--danger); }
