/* ============================================================================
   Refocus X — Design Pack · components.css
   The visual component library. Load AFTER tokens.css:

     <link rel="stylesheet" href="/design-pack/tokens.css">
     <link rel="stylesheet" href="/design-pack/components.css">

   Everything here uses tokens — there is not one literal colour, radius or
   shadow below. If a component needs a value that isn't a token, that is a gap
   in tokens.css; fix it there, not here.

   Where a source app had several versions of the same component (three toggle
   switches, four badge styles, two stat bars), one canonical version is kept
   and the divergences are noted in DECISIONS.md.

   CONTENTS
     1  Buttons            8  Stats                15  Overlays & panels
     2  Cards              9  Badges & pills       16  Tabs
     3  Fields             10 Tables               17  Copy-to-clipboard
     4  Switches           11 Expandable rows      18  Success card
     5  Segmented control  12 Event / log list     19  PIN & OTP entry
     6  Info balloon       13 Empty/loading/error  20  Recipient-page bits
     7  Chips & tags       14 Pager                21  Dashboard cards
   ============================================================================ */


/* ══ 1 · BUTTONS ══════════════════════════════════════════════════════════ */

.rx-btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 20px; border-radius: var(--rx-radius-sm);
  font-family: inherit; font-size: var(--rx-text-md); font-weight: 600;
  border: 1.5px solid transparent; cursor: pointer; text-decoration: none;
  transition: background .15s, border-color .15s, opacity .15s;
  white-space: nowrap;
}
.rx-btn:disabled, .rx-btn[aria-disabled="true"] { opacity: .4; cursor: not-allowed; }

.rx-btn-primary { background: var(--rx-ink); color: var(--rx-on-ink); border-color: var(--rx-ink); }
.rx-btn-primary:hover:not(:disabled) { background: var(--rx-ink-hover); }

.rx-btn-outline { background: var(--rx-surface-card); color: var(--rx-ink); border-color: var(--rx-border); }
.rx-btn-outline:hover:not(:disabled) { border-color: var(--rx-ink); }

.rx-btn-ghost { background: none; color: var(--rx-ink-muted); border-color: transparent; }
.rx-btn-ghost:hover:not(:disabled) { background: var(--rx-surface-sunken); color: var(--rx-ink); }

.rx-btn-danger { background: var(--rx-danger); color: var(--rx-on-danger); border-color: var(--rx-danger); }
.rx-btn-danger:hover:not(:disabled) { opacity: .9; }

/* The DESTRUCTIVE tier — unscoped, irreversible. Deliberately a different,
   darker red so it cannot be confused with an ordinary delete. */
.rx-btn-destroy { background: var(--rx-danger-strong); color: var(--rx-on-danger); border-color: var(--rx-danger-strong); }
.rx-btn-destroy:hover:not(:disabled) { opacity: .9; }

/* Quiet danger — for a dangerous action sitting among ordinary row actions.
   Grey and dashed at rest so it never invites a mis-click; red and solid on
   hover so it is unmistakable once you mean it. */
.rx-btn-danger-quiet {
  background: none; color: var(--rx-ink-subtle);
  border: 1px dashed var(--rx-border); padding: 5px 10px; font-size: .82rem; font-weight: 500;
}
.rx-btn-danger-quiet:hover {
  color: var(--rx-danger); border-color: var(--rx-danger); border-style: solid;
}

.rx-btn-sm { padding: 6px 12px; font-size: var(--rx-text-sm); }


/* ══ 1b · PAGE HEADER ═════════════════════════════════════════════════════ */
/* Every screen names itself. The title size comes from the page-width
   modifier (see tokens.css) so a form and a list are visibly different kinds
   of page without anyone choosing a number. */

.rx-page-header {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin-bottom: 24px;
}
.rx-page-title {
  font-size: var(--rx-page-title, var(--rx-title));
  font-weight: 700; margin: 0 0 3px; color: var(--rx-ink); line-height: 1.2;
}
.rx-page-sub { font-size: var(--rx-text); color: var(--rx-ink-muted); margin: 0; }
/* Right-hand side: actions, a refresh control, a last-updated stamp. */
.rx-page-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }


/* ══ 2 · CARDS ════════════════════════════════════════════════════════════ */

.rx-card {
  background: var(--rx-surface-card); border: 1px solid var(--rx-border);
  border-radius: var(--rx-radius-lg); box-shadow: var(--rx-shadow-sm);
  padding: 22px 24px;
}
.rx-card-title { font-size: 15px; font-weight: 600; margin: 0 0 4px; color: var(--rx-ink); }
.rx-card-sub   { font-size: var(--rx-text-sm); color: var(--rx-ink-muted); margin: 0 0 20px; line-height: 1.5; }

/* Sectioned card — one card, several groups divided by rules. */
.rx-card-sectioned { padding: 0; overflow: hidden; }
.rx-card-section   { padding: 22px 26px; border-bottom: 1px solid var(--rx-border); }
.rx-card-section:last-of-type { border-bottom: none; }
.rx-section-title {
  font-size: var(--rx-text-sm); font-weight: 700; letter-spacing: .4px; text-transform: uppercase;
  color: var(--rx-ink-subtle); margin-bottom: 14px;
}

/* Severity edges — reads at a glance without reading the words. */
.rx-card-warn    { border-left: 3px solid var(--rx-warn-strong); }
.rx-card-danger  { border-left: 3px solid var(--rx-danger); }
.rx-card-destroy { border-left: 3px solid var(--rx-danger-strong); }

/* Danger zone — for a destructive block inside an otherwise ordinary page. */
.rx-danger-zone { border-color: var(--rx-danger); }
.rx-danger-zone .rx-section-title { color: var(--rx-danger-strong); }


/* ══ 3 · FIELDS ═══════════════════════════════════════════════════════════ */

.rx-fields { display: flex; flex-direction: column; gap: 16px; }
.rx-field  { margin-bottom: 18px; }
.rx-field:last-child { margin-bottom: 0; }

.rx-field label {
  display: block; font-size: var(--rx-text); font-weight: 500;
  color: var(--rx-ink-muted); margin-bottom: 6px;
}
.rx-field label .rx-muted { color: var(--rx-ink-subtle); font-weight: 400; }

/* Checkboxes and radios are EXCLUDED — otherwise a checkbox nested in a field
   gets stretched to the full form width, which looks broken. */
.rx-field input:not([type="checkbox"]):not([type="radio"]),
.rx-field textarea,
.rx-field select {
  width: 100%; padding: 10px 14px; font-family: inherit; font-size: var(--rx-text-md);
  background: var(--rx-surface-card); color: var(--rx-ink);
  border: 1px solid var(--rx-border); border-radius: var(--rx-radius);
  outline: none; transition: border-color .15s, box-shadow .15s; appearance: none;
}
.rx-field input:not([type="checkbox"]):not([type="radio"]):focus,
.rx-field textarea:focus,
.rx-field select:focus {
  border-color: var(--rx-ink); box-shadow: var(--rx-focus-ring);
}
.rx-field textarea { resize: vertical; min-height: 72px; }
.rx-field-hint {
  display: block; font-size: var(--rx-text-xs); color: var(--rx-ink-subtle);
  margin-top: 5px; line-height: 1.5; font-weight: 400;
}
.rx-field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-items: start; }
@media (max-width: 560px) { .rx-field-row { grid-template-columns: 1fr; } }

/* Native select arrow removed above — supply our own. */
.rx-field select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%2352525b' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 14px center; padding-right: 36px;
}

/* Save status — one element, three states, beside the button.
   Never a toast: put it where the user is already looking. */
.rx-save-row    { display: flex; align-items: center; gap: 12px; margin-top: 24px; }
.rx-save-status { font-size: var(--rx-text-sm); color: var(--rx-ink-subtle); }
.rx-save-status.ok  { color: var(--rx-accent-text); }
.rx-save-status.err { color: var(--rx-danger); }


/* ══ 4 · SWITCHES ═════════════════════════════════════════════════════════ */
/* ONE canonical toggle. The source app had three (38×22 ink-filled, 40×22
   ink-filled, 38×22 green-filled) — this is the green one, because "on" reading
   as green is a stronger signal than "on" reading as dark. */

.rx-switch { position: relative; display: inline-block; width: 38px; height: 22px; flex-shrink: 0; vertical-align: middle; }
.rx-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.rx-switch-slider {
  position: absolute; inset: 0; background: var(--rx-border);
  border-radius: var(--rx-radius-pill); cursor: pointer; transition: background .2s;
}
.rx-switch-slider::before {
  content: ''; position: absolute; width: 16px; height: 16px; left: 3px; top: 3px;
  background: var(--rx-surface-card); border-radius: 50%;
  transition: transform .2s; box-shadow: 0 1px 3px rgba(0,0,0,.25);
}
.rx-switch input:checked + .rx-switch-slider { background: var(--rx-accent-ui); }
.rx-switch input:checked + .rx-switch-slider::before { transform: translateX(16px); }
.rx-switch input:focus-visible + .rx-switch-slider { box-shadow: var(--rx-focus-ring); }

/* Label + description on the left, switch on the right. */
.rx-switch-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 10px 0; }
.rx-switch-row:not(:last-child) { border-bottom: 1px solid var(--rx-surface-sunken); }
.rx-switch-label { font-size: var(--rx-text-md); font-weight: 500; color: var(--rx-ink); }
.rx-switch-desc  { font-size: 12.5px; color: var(--rx-ink-subtle); margin-top: 2px; max-width: 460px; }


/* ══ 5 · SEGMENTED CONTROL ════════════════════════════════════════════════ */
/* Two-or-three-way mode selector. Each option carries a title AND a one-line
   explanation — a mode the user cannot distinguish is a mode they will pick
   wrong. */

.rx-segmented { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 8px; }
.rx-segment {
  display: flex; align-items: center; gap: 10px; padding: 12px 14px;
  border: 1.5px solid var(--rx-border); border-radius: var(--rx-radius);
  background: var(--rx-surface-card); cursor: pointer; font-family: inherit; text-align: left;
  transition: border-color .15s, background .15s;
}
.rx-segment:hover { border-color: var(--rx-ink-subtle); }
.rx-segment.on    { border-color: var(--rx-ink); background: var(--rx-surface-sunken); }
.rx-segment-icon  { font-size: var(--rx-title-sm); flex-shrink: 0; }
.rx-segment strong { display: block; font-size: var(--rx-text); color: var(--rx-ink); }
.rx-segment small  { display: block; font-size: var(--rx-text-xs); color: var(--rx-ink-subtle); margin-top: 2px; font-weight: 400; }


/* ══ 6 · INFO BALLOON ═════════════════════════════════════════════════════ */
/* The grey explanatory block that sits under a control and changes with the
   selection. Use it wherever a choice has consequences the user cannot infer
   from the label — it is the cheapest way to prevent a wrong choice. */

.rx-balloon {
  margin-top: 8px; padding: 10px 14px;
  background: var(--rx-surface-sunken); border-radius: var(--rx-radius);
  font-size: var(--rx-text-sm); color: var(--rx-ink-muted); line-height: 1.6;
}
.rx-balloon strong { color: var(--rx-ink); }

.rx-balloon-info   { background: var(--rx-surface-sunken); border-left: 3px solid var(--rx-info); }
.rx-balloon-warn   { background: var(--rx-surface-sunken); border-left: 3px solid var(--rx-warn); }
.rx-balloon-danger { background: var(--rx-danger-soft);    border-left: 3px solid var(--rx-danger); }


/* ══ 7 · CHIPS & TAGS ═════════════════════════════════════════════════════ */

/* Filter chip — selection is inversion. */
.rx-chip {
  background: var(--rx-surface-card); border: 1px solid var(--rx-border);
  border-radius: var(--rx-radius-pill); padding: 5px 14px;
  font-family: inherit; font-size: var(--rx-text-sm); font-weight: 500;
  color: var(--rx-ink-muted); cursor: pointer; transition: all .15s;
}
.rx-chip:hover { border-color: var(--rx-ink-subtle); color: var(--rx-ink); }
.rx-chip.on    { background: var(--rx-ink); color: var(--rx-on-ink); border-color: var(--rx-ink); }
.rx-chip-group { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.rx-chip-group-label {
  font-size: var(--rx-text-xs); font-weight: 600; text-transform: uppercase;
  letter-spacing: .5px; color: var(--rx-ink-subtle); margin-right: 4px;
}

/* Tag input — a bordered box that behaves like one field but holds many
   values (recipients, domains, extensions). Click anywhere to focus. */
.rx-tags {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  padding: 8px 10px; min-height: 42px; cursor: text;
  background: var(--rx-surface-card);
  border: 1px solid var(--rx-border); border-radius: var(--rx-radius);
  transition: border-color .15s, box-shadow .15s;
}
.rx-tags:focus-within { border-color: var(--rx-ink); box-shadow: var(--rx-focus-ring); }
.rx-tags input {
  border: none; outline: none; background: transparent; flex: 1; min-width: 140px;
  padding: 2px 4px; font-family: inherit; font-size: var(--rx-text-md); color: var(--rx-ink);
}
.rx-tag {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--rx-surface-sunken); border: 1px solid var(--rx-border);
  border-radius: var(--rx-radius-pill); padding: 3px 8px 3px 11px;
  font-size: var(--rx-text-sm); font-weight: 500; color: var(--rx-ink); white-space: nowrap;
}
.rx-tag-x { background: none; border: none; cursor: pointer; color: var(--rx-ink-subtle); font-size: var(--rx-text-md); line-height: 1; padding: 0; }
.rx-tag-x:hover { color: var(--rx-danger); }
.rx-tag.invalid { border-color: var(--rx-danger); color: var(--rx-danger); }

/* Preset blocks — pick-one from a small fixed set (5 / 10 / 20 / Unlimited). */
.rx-presets { display: flex; gap: 8px; flex-wrap: wrap; }
.rx-preset {
  flex: 1; min-width: 64px; padding: 10px 12px; text-align: center;
  font-family: inherit; font-size: var(--rx-text); font-weight: 600;
  background: var(--rx-surface-card); color: var(--rx-ink-muted);
  border: 1.5px solid var(--rx-border); border-radius: var(--rx-radius-sm);
  cursor: pointer; transition: all .12s;
}
.rx-preset:hover { border-color: var(--rx-ink-subtle); color: var(--rx-ink); }
.rx-preset.on    { background: var(--rx-ink); color: var(--rx-on-ink); border-color: var(--rx-ink); }


/* ══ 8 · STATS ════════════════════════════════════════════════════════════ */

.rx-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 14px; }
.rx-stat {
  background: var(--rx-surface-card); border: 1px solid var(--rx-border);
  border-radius: var(--rx-radius); padding: 16px 18px;
}
.rx-stat-value { font-size: var(--rx-title-lg); font-weight: 700; line-height: 1; color: var(--rx-ink); }
.rx-stat-label { font-size: 12.5px; color: var(--rx-ink-subtle); margin-top: 6px; }
.rx-stat-sub   { font-size: var(--rx-text-xs); color: var(--rx-ink-subtle); margin-top: 3px; }
.rx-stat-value.good { color: var(--rx-accent-text); }
.rx-stat-value.warn { color: var(--rx-warn); }
.rx-stat-value.bad  { color: var(--rx-danger); }

/* Compact inline variant, for a filter bar or a header. */
.rx-stat-pills { display: flex; gap: 16px; flex-wrap: wrap; }
.rx-stat-pill {
  background: var(--rx-surface-card); border: 1px solid var(--rx-border);
  border-radius: var(--rx-radius-sm); padding: 10px 16px;
  display: flex; align-items: center; gap: 8px; font-size: var(--rx-text);
}
.rx-stat-pill .rx-stat-value { font-size: var(--rx-title-sm); }
.rx-stat-pill .rx-stat-label { margin-top: 0; color: var(--rx-ink-muted); }


/* ══ 9 · BADGES & PILLS ═══════════════════════════════════════════════════ */

.rx-badge {
  display: inline-flex; align-items: center; padding: 2px 8px;
  border-radius: 4px; font-size: var(--rx-text-xs); font-weight: 600; white-space: nowrap;
}
.rx-badge-mono { font-family: var(--rx-mono); }

.rx-badge-neutral { background: var(--rx-surface-sunken); color: var(--rx-ink-muted); }
.rx-badge-active  { background: var(--rx-tint-green);  color: var(--rx-tint-green-ink); }
.rx-badge-info    { background: var(--rx-tint-blue);   color: var(--rx-tint-blue-ink); }
.rx-badge-purple  { background: var(--rx-tint-purple); color: var(--rx-tint-purple-ink); }
.rx-badge-warn    { background: var(--rx-tint-orange); color: var(--rx-tint-orange-ink); }
.rx-badge-pending { background: var(--rx-tint-amber);  color: var(--rx-tint-amber-ink); }
.rx-badge-danger  { background: var(--rx-danger-soft); color: var(--rx-danger-strong); }

/* Role / provenance pill — a quieter, outlined variant for metadata. */
.rx-pill {
  display: inline-flex; align-items: center; gap: 5px;
  background: var(--rx-surface-sunken); border: 1px solid var(--rx-border);
  border-radius: var(--rx-radius-pill); padding: 3px 10px;
  font-size: .85rem; color: var(--rx-ink);
}
.rx-pill-x { background: none; border: none; cursor: pointer; color: var(--rx-ink-muted); font-size: 15px; line-height: 1; padding: 0; }
.rx-pill-x:hover { color: var(--rx-danger); }


/* ══ 10 · TABLES ══════════════════════════════════════════════════════════ */
/* Grid-based list table, for rows that expand. (For a plain sortable data
   table use the rx-table engine instead — it does sort/paginate/resize/CSV.) */

.rx-table-wrap {
  border: 1px solid var(--rx-border); border-radius: var(--rx-radius);
  overflow: hidden; background: var(--rx-surface-card);
}
.rx-table-head {
  background: var(--rx-surface-sunken); font-weight: 600;
  color: var(--rx-ink-subtle); text-transform: uppercase;
  font-size: var(--rx-text-xs); letter-spacing: .4px;
}
.rx-table-head, .rx-table-row { display: grid; gap: 10px; padding: 10px 14px; align-items: center; }
.rx-table-row { border-top: 1px solid var(--rx-border); font-size: var(--rx-text); }
.rx-table-row:hover { background: var(--rx-surface-sunken); }
.rx-table-row.selected { background: var(--rx-surface-sunken); }

/* Sticky header for long lists. */
.rx-table-head.sticky { position: sticky; top: var(--rx-header-h); z-index: var(--rx-z-sticky); }


/* ══ 11 · EXPANDABLE ROWS ═════════════════════════════════════════════════ */

.rx-exp-row { border-top: 1px solid var(--rx-border); }
.rx-exp-main { display: grid; gap: 10px; padding: 12px 14px; align-items: center; cursor: pointer; }
.rx-exp-main:hover { background: var(--rx-surface-sunken); }
.rx-exp-row.open > .rx-exp-main { background: var(--rx-surface-sunken); }
.rx-exp-chevron { color: var(--rx-ink-subtle); transition: transform .18s; display: inline-block; }
.rx-exp-row.open .rx-exp-chevron { transform: rotate(90deg); }
.rx-exp-body { display: none; padding: 14px 18px 18px; background: var(--rx-surface-sunken); }
.rx-exp-row.open .rx-exp-body { display: block; }
.rx-exp-title {
  font-size: var(--rx-text-xs); font-weight: 700; text-transform: uppercase;
  letter-spacing: .04em; color: var(--rx-ink-subtle); margin: 0 0 8px;
}
/* Left edge marks a row whose children matched the current filter — filtering
   a nested list without showing WHICH child matched is disorienting. */
.rx-exp-row.matched > .rx-exp-main { border-left: 3px solid var(--rx-info); }


/* ══ 12 · EVENT / LOG LIST ════════════════════════════════════════════════ */

.rx-events { display: flex; flex-direction: column; gap: 2px; }
.rx-event {
  background: var(--rx-surface-card); border: 1px solid var(--rx-border);
  border-radius: var(--rx-radius-sm); padding: 13px 16px;
  display: grid; grid-template-columns: 36px 1fr auto; gap: 12px;
  align-items: center; cursor: pointer; transition: border-color .12s, background .12s;
}
.rx-event:hover  { border-color: var(--rx-ink-subtle); background: var(--rx-surface-sunken); }
.rx-event.active { border-color: var(--rx-ink); background: var(--rx-surface-sunken); }
.rx-event-icon {
  width: 32px; height: 32px; border-radius: var(--rx-radius-sm);
  display: flex; align-items: center; justify-content: center;
  font-size: 15px; flex-shrink: 0; background: var(--rx-surface-sunken);
}
.rx-event-body  { min-width: 0; }
.rx-event-title { font-size: var(--rx-text); font-weight: 600; color: var(--rx-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rx-event-meta  { font-size: var(--rx-text-sm); color: var(--rx-ink-muted); margin-top: 2px; display: flex; gap: 12px; flex-wrap: wrap; }
.rx-event-time  { font-family: var(--rx-mono); font-size: var(--rx-text-xs); color: var(--rx-ink-subtle); white-space: nowrap; text-align: right; }

/* Vertical timeline — for a single item's history. */
.rx-timeline-item { position: relative; padding-left: 32px; padding-bottom: 18px; }
.rx-timeline-item:last-child { padding-bottom: 0; }
.rx-timeline-item::before {
  content: ''; position: absolute; left: 10px; top: 22px; bottom: 0;
  width: 2px; background: var(--rx-border);
}
.rx-timeline-item:last-child::before { display: none; }
.rx-timeline-dot {
  position: absolute; left: 0; top: 0; width: 22px; height: 22px;
  border-radius: 50%; background: var(--rx-surface-sunken);
  display: flex; align-items: center; justify-content: center; font-size: var(--rx-text-sm);
}
.rx-timeline-label { font-size: var(--rx-text); font-weight: 600; }
.rx-timeline-desc  { font-size: var(--rx-text-sm); color: var(--rx-ink-muted); line-height: 1.45; margin-top: 2px; }
.rx-timeline-time  { font-size: var(--rx-text-xs); color: var(--rx-ink-subtle); margin-top: 3px; }


/* ══ 13 · EMPTY / LOADING / ERROR ═════════════════════════════════════════ */
/* Same geometry, different icon and copy — so the page never jumps between
   states. (rx-table.js has these built in.) */

.rx-state {
  background: var(--rx-surface-card); border: 1px solid var(--rx-border);
  border-radius: var(--rx-radius); padding: 48px 24px; text-align: center;
}
.rx-state-icon  { font-size: 36px; margin-bottom: 12px; }
.rx-state-title { font-size: var(--rx-text-lg); font-weight: 600; margin-bottom: 6px; color: var(--rx-ink); }
.rx-state-sub   { font-size: var(--rx-text); color: var(--rx-ink-muted); }

.rx-spinner {
  width: 24px; height: 24px; margin: 0 auto 12px;
  border: 2.5px solid var(--rx-border); border-top-color: var(--rx-ink);
  border-radius: 50%; animation: rxspin .7s linear infinite;
}
.rx-spinner-lg { width: 40px; height: 40px; border-width: 3px; }
@keyframes rxspin { to { transform: rotate(360deg); } }


/* ══ 14 · PAGER ═══════════════════════════════════════════════════════════ */

.rx-pager { display: flex; align-items: center; justify-content: center; gap: 14px; padding: 16px 0 4px; }
.rx-pager-btn {
  background: var(--rx-surface-card); border: 1px solid var(--rx-border);
  border-radius: var(--rx-radius-sm); padding: 6px 14px;
  font-family: inherit; font-size: var(--rx-text); color: var(--rx-ink); cursor: pointer;
}
.rx-pager-btn:hover:not(:disabled) { background: var(--rx-surface-sunken); }
.rx-pager-btn:disabled { opacity: .4; cursor: not-allowed; }
.rx-pager-info { font-size: var(--rx-text); color: var(--rx-ink-subtle); }


/* ══ 15 · OVERLAYS & PANELS ═══════════════════════════════════════════════ */

/* Centred modal. */
.rx-backdrop {
  position: fixed; inset: 0; z-index: var(--rx-z-modal);
  background: var(--rx-scrim);
  display: none; align-items: center; justify-content: center; padding: 20px;
}
.rx-backdrop.open { display: flex; }
.rx-dialog {
  background: var(--rx-surface-card); border-radius: var(--rx-radius-lg);
  box-shadow: var(--rx-shadow-modal); max-width: 520px; width: 100%;
  max-height: 90vh; display: flex; flex-direction: column; overflow: hidden;
}
.rx-dialog-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 20px 24px 16px; border-bottom: 1px solid var(--rx-border); flex: 0 0 auto;
}
.rx-dialog-title { font-size: var(--rx-text-lg); font-weight: 700; }
.rx-dialog-sub   { font-size: var(--rx-text-sm); color: var(--rx-ink-muted); margin-top: 2px; }
.rx-dialog-body  { padding: 18px 24px; overflow-y: auto; flex: 1 1 auto; }
.rx-dialog-foot  {
  padding: 14px 24px 20px; border-top: 1px solid var(--rx-border);
  display: flex; justify-content: flex-end; gap: 10px; flex: 0 0 auto;
}
.rx-dialog-x {
  width: 32px; height: 32px; border-radius: var(--rx-radius-sm);
  border: 1.5px solid var(--rx-border); background: none; cursor: pointer;
  font-size: var(--rx-text-lg); color: var(--rx-ink-muted); flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
}
.rx-dialog-x:hover { border-color: var(--rx-ink); color: var(--rx-ink); }

/* Slide-in detail panel — the list-plus-detail pattern. The overlay is a
   SEPARATE element that cross-fades, so it never intercepts clicks while
   hidden. */
.rx-panel-overlay {
  position: fixed; inset: 0; z-index: var(--rx-z-modal);
  background: var(--rx-scrim-soft); opacity: 0; pointer-events: none; transition: opacity .2s;
}
.rx-panel-overlay.open { opacity: 1; pointer-events: all; }
.rx-panel {
  position: fixed; top: 0; right: 0; bottom: 0; width: 420px; max-width: 100vw;
  background: var(--rx-surface-card); border-left: 1px solid var(--rx-border);
  box-shadow: -4px 0 24px rgba(0,0,0,.08);
  transform: translateX(100%); transition: transform .22s cubic-bezier(.4,0,.2,1);
  display: flex; flex-direction: column; z-index: calc(var(--rx-z-modal) + 1);
}
.rx-panel.open { transform: translateX(0); }
.rx-panel-wide { width: 560px; }
.rx-panel-head { display: flex; align-items: center; justify-content: space-between; padding: 20px 20px 16px; border-bottom: 1px solid var(--rx-border); flex-shrink: 0; }
.rx-panel-body { flex: 1; overflow-y: auto; padding: 20px; display: flex; flex-direction: column; gap: 16px; }
.rx-panel-foot { padding: 16px 20px; border-top: 1px solid var(--rx-border); flex-shrink: 0; display: flex; flex-direction: column; gap: 8px; }

/* Key/value rows inside a detail panel. mono for identifiers and timestamps. */
.rx-kv        { display: flex; flex-direction: column; gap: 2px; }
.rx-kv-label  { font-size: var(--rx-text-xs); color: var(--rx-ink-muted); }
.rx-kv-value  { font-size: var(--rx-text); font-weight: 500; word-break: break-all; }
.rx-kv-value.mono { font-family: var(--rx-mono); }

/* Edge tab that opens a drawer — a persistent affordance that costs no
   layout space. */
.rx-drawer-tab {
  position: fixed; right: 0; top: 50%; transform: translateY(-50%);
  z-index: calc(var(--rx-z-header) - 1);
  background: var(--rx-ink); color: var(--rx-on-ink);
  border: none; border-radius: var(--rx-radius) 0 0 var(--rx-radius);
  padding: 14px 8px; cursor: pointer; font-family: inherit; font-size: var(--rx-text-sm);
  font-weight: 600; writing-mode: vertical-rl; display: flex; align-items: center; gap: 8px;
}
.rx-drawer-tab:hover { background: var(--rx-ink-hover); }


/* ══ 16 · TABS ════════════════════════════════════════════════════════════ */

.rx-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--rx-border); margin-bottom: 28px; overflow-x: auto; }
.rx-tab {
  padding: 8px 16px; font-family: inherit; font-size: var(--rx-text); font-weight: 500;
  background: none; border: none; border-bottom: 2px solid transparent;
  color: var(--rx-ink-subtle); cursor: pointer; margin-bottom: -1px;
  transition: color .15s; white-space: nowrap;
}
.rx-tab:hover  { color: var(--rx-ink-muted); }
.rx-tab.active { color: var(--rx-ink); border-bottom-color: var(--rx-ink); }
.rx-tab-panel { display: none; }
.rx-tab-panel.active { display: block; }


/* ══ 17 · COPY-TO-CLIPBOARD ═══════════════════════════════════════════════ */

.rx-copy-box {
  display: flex; align-items: center; gap: 8px;
  background: var(--rx-surface-page); border: 1px solid var(--rx-border);
  border-radius: var(--rx-radius); padding: 10px 14px;
}
.rx-copy-text {
  flex: 1; font-family: var(--rx-mono); font-size: var(--rx-text);
  color: var(--rx-ink); word-break: break-all; text-align: left;
}
.rx-copy-btn {
  background: var(--rx-ink); color: var(--rx-on-ink); border: none;
  border-radius: var(--rx-radius-sm); padding: 7px 14px;
  font-family: inherit; font-size: var(--rx-text-sm); font-weight: 600;
  cursor: pointer; white-space: nowrap;
}
.rx-copy-btn:hover { background: var(--rx-ink-hover); }
.rx-copy-btn.copied { background: var(--rx-accent-ui); }


/* ══ 18 · SUCCESS CARD ════════════════════════════════════════════════════ */

.rx-success {
  background: var(--rx-surface-card); border: 1px solid var(--rx-border);
  border-radius: var(--rx-radius-lg); box-shadow: var(--rx-shadow);
  padding: 40px 32px; text-align: center;
}
.rx-success-icon  { font-size: 48px; margin-bottom: 16px; }
.rx-success-title { font-size: 22px; font-weight: 700; margin-bottom: 8px; }
.rx-success-sub   { font-size: var(--rx-text-md); color: var(--rx-ink-muted); margin-bottom: 28px; }


/* ══ 19 · PIN & OTP ENTRY ═════════════════════════════════════════════════ */
/* One box per digit. Reads as a code rather than a password, and gives the
   user a visible sense of how many characters are expected. */

.rx-pin { display: flex; gap: 10px; justify-content: center; }
.rx-pin-digit {
  width: 46px; height: 56px; text-align: center;
  font-family: var(--rx-mono); font-size: 24px; font-weight: 500;
  color: var(--rx-ink); background: var(--rx-surface-card);
  border: 1.5px solid var(--rx-border); border-radius: var(--rx-radius);
  outline: none; transition: border-color .15s, box-shadow .15s;
  -moz-appearance: textfield;
}
.rx-pin-digit::-webkit-outer-spin-button,
.rx-pin-digit::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.rx-pin-digit:focus  { border-color: var(--rx-ink); box-shadow: var(--rx-focus-ring); }
.rx-pin-digit.filled { border-color: var(--rx-ink); }
.rx-pin.error .rx-pin-digit { border-color: var(--rx-danger); }
@media (max-width: 420px) {
  .rx-pin { gap: 6px; }
  .rx-pin-digit { width: 38px; height: 48px; font-size: 20px; }
}


/* ══ 20 · RECIPIENT-PAGE BITS ═════════════════════════════════════════════ */
/* For public pages that load no shell. Deliberately minimal. */

.rx-step { display: none; }
.rx-step.active { display: block; }

.rx-msg { padding: 12px 14px; border-radius: var(--rx-radius); font-size: var(--rx-text); line-height: 1.55; }
.rx-msg-info   { background: var(--rx-surface-sunken); color: var(--rx-ink-muted); border-left: 3px solid var(--rx-info); }
.rx-msg-error  { background: var(--rx-danger-soft); color: var(--rx-danger-strong); border-left: 3px solid var(--rx-danger); }
.rx-msg-note   { background: var(--rx-surface-sunken); color: var(--rx-ink); border-left: 3px solid var(--rx-accent-ui); }

/* File row — one file with icon, name, size and an action. */
.rx-file-row {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  background: var(--rx-surface-page); border: 1px solid var(--rx-border);
  border-radius: var(--rx-radius-sm);
}
.rx-file-icon { font-size: var(--rx-title-sm); flex-shrink: 0; }
.rx-file-info { flex: 1; min-width: 0; }
.rx-file-name { font-size: var(--rx-text); font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rx-file-size { font-size: var(--rx-text-xs); color: var(--rx-ink-subtle); }

/* Agreement box — a scrollable terms block with a checkbox gate. */
.rx-agree {
  border: 1px solid var(--rx-border); border-radius: var(--rx-radius);
  padding: 14px 16px; background: var(--rx-surface-page);
  max-height: 180px; overflow-y: auto; font-size: 12.5px;
  color: var(--rx-ink-muted); line-height: 1.6;
}
.rx-agree-check { display: flex; align-items: flex-start; gap: 10px; cursor: pointer; margin-top: 12px; }
.rx-agree-check input { margin-top: 2px; width: 16px; height: 16px; flex-shrink: 0; accent-color: var(--rx-ink); cursor: pointer; }
.rx-agree-check span { font-size: var(--rx-text); color: var(--rx-ink); line-height: 1.5; }


/* ══ 21 · DASHBOARD CARDS ═════════════════════════════════════════════════ */
/* Chrome for a movable/resizable widget. The rx-dashboard engine supplies the
   markup; this is what it looks like. */

.rx-dash-bar  { display: flex; justify-content: flex-end; gap: 8px; margin-bottom: 10px; }
.rx-dash-card {
  background: var(--rx-surface-card); border: 1px solid var(--rx-border);
  border-radius: var(--rx-radius-lg); box-shadow: var(--rx-shadow-sm);
  height: 100%; display: flex; flex-direction: column; overflow: hidden;
}
.rx-dash-head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 11px 16px; border-bottom: 1px solid var(--rx-border);
  cursor: move; flex: none;              /* drag handle — body text stays selectable */
}
.rx-dash-title { font-size: var(--rx-text-md); font-weight: 600; color: var(--rx-ink); }
.rx-dash-grip  { color: var(--rx-ink-subtle); font-size: var(--rx-text-md); letter-spacing: -2px; user-select: none; }
.rx-dash-body  { padding: 16px; flex: 1; overflow: auto; }
/* Override GridStack's default so a popover opened in a card isn't clipped. */
.grid-stack-item-content { overflow: visible !important; }
/* Fallback when the grid library is absent — still a usable page. */
.rx-dash-fallback { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 16px; }
