/* =============================================================================
   COMPONENTS — reusable primitives
   Depends on tokens.css. Contains no literal colours.
   Where a class name comes from Bootstrap (.btn, .form-control, .badge) we
   restyle it in place, so existing markup and the Selenium selectors keep working.
   ========================================================================== */

/* =========================================================================
   ICON SIZING
   Safe default for any inline SVG inside an interactive element, so a new icon
   can never render at its intrinsic size and blow out the layout. Component
   rules below override it by specificity where a different size is wanted.
   ========================================================================= */

button svg,
a svg,
label svg,
summary svg {
  width: 16px;
  height: 16px;
}

/* =========================================================================
   BUTTONS
   ========================================================================= */

.btn {
  --_btn-bg: transparent;
  --_btn-fg: var(--text);
  --_btn-border: transparent;

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  padding: 0 var(--control-pad-x);
  height: var(--control-h);
  border: 1px solid var(--_btn-border);
  border-radius: var(--radius-md);
  background-color: var(--_btn-bg);
  color: var(--_btn-fg);
  font-family: inherit;
  font-size: var(--text-md);
  font-weight: var(--weight-medium);
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  user-select: none;
  transition: background-color var(--duration-fast) var(--ease),
              border-color var(--duration-fast) var(--ease),
              color var(--duration-fast) var(--ease),
              box-shadow var(--duration-fast) var(--ease);
}

.btn:hover { color: var(--_btn-fg); }

.btn:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring-shadow);
  border-color: var(--focus-ring);
}

.btn:disabled,
.btn.disabled,
.btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

.btn svg { width: 16px; height: 16px; }

/* --- Variants --- */

.btn-primary {
  --_btn-bg: var(--accent);
  --_btn-fg: var(--accent-fg);
  --_btn-border: var(--accent);
}
.btn-primary:hover { --_btn-bg: var(--accent-hover); --_btn-border: var(--accent-hover); }
.btn-primary:active { --_btn-bg: var(--accent-active); }

/* Bootstrap's success/warning/info are used across the existing markup.
   Map them onto the design system rather than leaving Bootstrap's palette. */
.btn-success {
  --_btn-bg: var(--accent);
  --_btn-fg: var(--accent-fg);
  --_btn-border: var(--accent);
}
.btn-success:hover { --_btn-bg: var(--accent-hover); --_btn-border: var(--accent-hover); }

.btn-secondary,
.btn-light,
.btn-outline-secondary {
  --_btn-bg: var(--surface);
  --_btn-fg: var(--text);
  --_btn-border: var(--border-strong);
}
.btn-secondary:hover,
.btn-light:hover,
.btn-outline-secondary:hover { --_btn-bg: var(--surface-hover); }

.btn-outline-primary {
  --_btn-bg: transparent;
  --_btn-fg: var(--accent-text);
  --_btn-border: var(--accent-border);
}
.btn-outline-primary:hover { --_btn-bg: var(--accent-soft); --_btn-fg: var(--accent-soft-fg); }

.btn-warning,
.btn-info {
  --_btn-bg: var(--surface);
  --_btn-fg: var(--text);
  --_btn-border: var(--border-strong);
}
.btn-warning:hover,
.btn-info:hover { --_btn-bg: var(--surface-hover); }

.btn-danger {
  --_btn-bg: var(--danger);
  --_btn-fg: var(--danger-fg);
  --_btn-border: var(--danger);
}
.btn-danger:hover { --_btn-bg: var(--danger-hover); --_btn-border: var(--danger-hover); }

.btn-ghost {
  --_btn-bg: transparent;
  --_btn-fg: var(--text-muted);
  --_btn-border: transparent;
}
.btn-ghost:hover { --_btn-bg: var(--surface-hover); --_btn-fg: var(--text); }

.btn-ghost-danger {
  --_btn-bg: transparent;
  --_btn-fg: var(--danger-text);
  --_btn-border: transparent;
}
.btn-ghost-danger:hover { --_btn-bg: var(--danger-soft); }

/* --- Sizes --- */

.btn-sm { height: var(--control-h-sm); padding: 0 var(--control-pad-x-sm); font-size: var(--text-sm); gap: var(--space-2); }
.btn-sm svg { width: 14px; height: 14px; }

.btn-lg { height: var(--control-h-lg); padding: 0 var(--control-pad-x-lg); font-size: var(--text-base); }

.btn-icon { width: var(--control-h); height: var(--control-h); padding: 0; }
.btn-icon.btn-sm { width: var(--control-h-sm); height: var(--control-h-sm); }

.btn-block { display: flex; width: 100%; }

/* --- Loading --- */

.btn[data-loading="true"] {
  position: relative;
  color: transparent !important;
  pointer-events: none;
}

.btn[data-loading="true"]::after {
  content: "";
  position: absolute;
  width: 14px;
  height: 14px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  color: var(--_btn-fg);
  animation: spin 0.6s linear infinite;
}

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

/* =========================================================================
   ICON BUTTON
   =========================================================================
   Square, chromeless control holding a single 16px glyph: the topbar controls,
   a table row's overflow menu, a drawer's close. These were three separate
   near-identical rules; they are one definition with the row menu differing
   only in its resting colour.
   ========================================================================= */

.icon-btn,
.row-menu-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--control-h-sm);
  height: var(--control-h-sm);
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease),
              color var(--duration-fast) var(--ease);
}

.icon-btn:hover,
.row-menu-toggle:hover { background-color: var(--surface-hover); color: var(--text); }

.icon-btn:focus-visible,
.row-menu-toggle:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 1px; }

.icon-btn svg,
.row-menu-toggle svg { width: 16px; height: 16px; }

/* Bootstrap hangs a caret on anything with .dropdown-toggle. */
.icon-btn::after,
.row-menu-toggle::after { display: none; }

/* Fingers need more room than a cursor does. */
@media (pointer: coarse) {
  .icon-btn,
  .row-menu-toggle { width: var(--tap-min); height: var(--tap-min); }
}

/* =========================================================================
   FORM CONTROLS
   ========================================================================= */

.form-label {
  display: block;
  margin-bottom: var(--space-3);
  color: var(--text);
  font-size: var(--text-md);
  font-weight: var(--weight-medium);
}

.form-control,
.form-select,
.input {
  display: block;
  width: 100%;
  min-height: var(--control-h);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  background-color: var(--surface);
  color: var(--text);
  font-family: inherit;
  font-size: var(--text-md);
  line-height: 1.4;
  transition: border-color var(--duration-fast) var(--ease),
              box-shadow var(--duration-fast) var(--ease);
  appearance: none;
}

textarea.form-control {
  min-height: 84px;
  padding: var(--space-3) var(--space-4);
  line-height: var(--leading-normal);
  resize: vertical;
}

.form-control::placeholder { color: var(--text-subtle); }

.form-control:hover,
.form-select:hover { border-color: var(--text-subtle); }

.form-control:focus,
.form-select:focus,
.input:focus {
  outline: none;
  border-color: var(--focus-ring);
  box-shadow: var(--focus-ring-shadow);
}

.form-control:disabled,
.form-select:disabled,
.form-control[readonly] {
  background-color: var(--surface-sunken);
  color: var(--text-muted);
  cursor: not-allowed;
}

.form-control.is-invalid,
.form-select.is-invalid {
  border-color: var(--danger);
  box-shadow: var(--danger-ring-shadow);
}

/* Focusing an invalid field keeps the error colour rather than reverting to the
   neutral focus ring, so the field does not look fixed just because it is active. */
.form-control.is-invalid:focus,
.form-select.is-invalid:focus {
  border-color: var(--danger);
  box-shadow: var(--danger-ring-shadow-strong);
}

.form-select {
  padding-right: var(--space-9);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%237d8698' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-4) center;
  background-size: 16px;
  cursor: pointer;
}

.form-select option { color: var(--text); background-color: var(--surface); }

.form-text {
  display: block;
  margin-top: var(--space-3);
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* Checkboxes and radios */

.form-check {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  padding: 0;
  margin-bottom: 0;
  min-height: auto;
}

/* The label fills the row so the whole thing is clickable, and it carries the
   description underneath the name when there is one. */
.form-check-label {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--text-md);
  line-height: var(--leading-snug);
  cursor: pointer;
}

.form-check-hint {
  display: block;
  margin-top: var(--space-2);
  color: var(--text-muted);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}

/* .form-check .form-check-input is Bootstrap's own rule and it sets
   margin-left: -1.5em, which is how its label-indent layout works. We lay the
   row out with flexbox instead, so that pull to the left is what dragged every
   checkbox in the app ~22px outside its own row and up against the panel edge.
   Matching Bootstrap's specificity is what it takes to undo it. */
.form-check .form-check-input,
.form-check-input {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  margin: 1px 0 0;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-xs);
  background-color: var(--surface);
  appearance: none;
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease),
              border-color var(--duration-fast) var(--ease);
}

.form-check-input[type="radio"] { border-radius: 50%; }

.form-check-input:checked {
  border-color: var(--accent);
  background-color: var(--accent);
  background-repeat: no-repeat;
  background-position: center;
  background-size: 13px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='white' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M13 4L6 11.5 3 8.5'/%3E%3C/svg%3E");
}

.form-check-input[type="radio"]:checked {
  background-size: 9px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Ccircle cx='4' cy='4' r='4' fill='white'/%3E%3C/svg%3E");
}

.form-check-input:indeterminate {
  border-color: var(--accent);
  background-color: var(--accent);
  background-repeat: no-repeat;
  background-position: center;
  background-size: 10px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='white' stroke-width='2.5' stroke-linecap='round'%3E%3Cpath d='M4 8h8'/%3E%3C/svg%3E");
}

.form-check-input:focus-visible {
  outline: none;
  border-color: var(--focus-ring);
  box-shadow: var(--focus-ring-shadow);
}

.form-check-input:disabled { opacity: 0.5; cursor: not-allowed; }

.form-check-label {
  color: var(--text);
  font-size: var(--text-md);
  cursor: pointer;
}

/* Input group (used by the share/copy rows) */

.input-group { display: flex; width: 100%; }

.input-group > .form-control {
  flex: 1 1 auto;
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

.input-group > .btn {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  margin-left: -1px;
  height: auto;
  min-height: var(--control-h);
}

.input-group > .btn:focus-visible { z-index: 2; }

/* Field with a leading icon */

.field-icon { position: relative; }

.field-icon > svg {
  position: absolute;
  top: 50%;
  left: var(--space-4);
  width: 16px;
  height: 16px;
  transform: translateY(-50%);
  color: var(--text-subtle);
  pointer-events: none;
}

.field-icon > .form-control { padding-left: var(--space-9); }

/* =========================================================================
   SURFACES
   ========================================================================= */

.card,
.panel {
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs);
}

.panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--panel-pad-y) var(--panel-pad-x);
  border-bottom: 1px solid var(--border);
}

.panel-title {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
}

.panel-subtitle {
  margin: var(--space-2) 0 0;
  color: var(--text-muted);
  font-size: var(--text-md);
}

.panel-body { padding: var(--panel-pad-x); }

.panel-footer {
  padding: var(--panel-pad-y) var(--panel-pad-x);
  border-top: 1px solid var(--border);
  background-color: var(--surface-sunken);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

/* Heading between blocks, one level below the page's <h1>: "Choose a plan"
   above a grid of cards. Sits on the 17px tier with the drawer, modal and empty
   state headings - things that title a whole region. A .panel-title is 15px
   because it labels one card inside such a region, not the region itself. */

.section-title {
  margin: 0 0 var(--gap-block);
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.01em;
}

/* Page header - the block above every page's main content */

.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-6);
  flex-wrap: wrap;
  margin-bottom: var(--gap-section);
}

.page-header__title {
  margin: 0;
  font-size: var(--text-2xl);
  line-height: var(--leading-tight);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.02em;
}

.page-header__subtitle {
  margin: var(--space-3) 0 0;
  color: var(--text-muted);
  font-size: var(--text-base);
}

.page-header__actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

/* =========================================================================
   BADGES & STATUS
   ========================================================================= */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-4);
  height: 26px;
  border-radius: var(--radius-sm);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  line-height: 1;
  white-space: nowrap;
}

.badge::before {
  content: "";
  width: 6px;
  height: 6px;
  flex-shrink: 0;
  border-radius: 50%;
  background-color: currentColor;
}

.badge--plain::before { display: none; }

/* The dot carries the full-strength hue while the label stays at the softer
   readable tier, so the status is scannable at a glance without shouting. */
.status-waiting  { background-color: var(--status-waiting-bg);  color: var(--status-waiting-fg); }
.status-sent     { background-color: var(--status-sent-bg);     color: var(--status-sent-fg); }
.status-received { background-color: var(--status-received-bg); color: var(--status-received-fg); }
.status-viewed   { background-color: var(--status-viewed-bg);   color: var(--status-viewed-fg); }
.status-expired  { background-color: var(--status-expired-bg);  color: var(--status-expired-fg); }

.status-waiting::before  { background-color: var(--status-waiting-dot); }
.status-sent::before     { background-color: var(--status-sent-dot); }
.status-received::before { background-color: var(--status-received-dot); }
.status-viewed::before   { background-color: var(--status-viewed-dot); }
.status-expired::before  { background-color: var(--status-expired-dot); }

.badge-accent  { background-color: var(--accent-soft);  color: var(--accent-soft-fg); }
.badge-neutral { background-color: var(--surface-sunken); color: var(--text-muted); }
.badge-danger  { background-color: var(--danger-soft);  color: var(--danger-soft-fg); }
.badge-success { background-color: var(--success-soft); color: var(--success-soft-fg); }
.badge-warning { background-color: var(--warning-soft); color: var(--warning-soft-fg); }

/* Monospace id chip */
.chip-id {
  display: inline-flex;
  align-items: center;
  padding: 0 var(--space-3);
  height: 22px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-subtle);
  background-color: var(--surface-sunken);
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: -0.02em;
}

/* =========================================================================
   ALERTS
   ========================================================================= */

.alert {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  margin-bottom: var(--space-5);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  font-size: var(--text-md);
}

/* Carries a trailing control, which reads better centred than top-aligned. */
.alert--inline { align-items: center; }

/* Alerts built in JavaScript wrap their glyph so it lines up with the first
   line of text the same way the template ones do. */
.alert__icon { display: flex; flex-shrink: 0; margin-top: 1px; }
.alert__icon svg { width: 16px; height: 16px; }

/* Work in progress rather than an outcome: the glyph spins. */
.alert.is-busy .alert__icon svg { animation: spin 0.9s linear infinite; }

.alert svg { width: 16px; height: 16px; margin-top: 2px; }

.alert-danger  { background-color: var(--danger-soft);  color: var(--danger-soft-fg);  border-color: var(--danger); }
.alert-success { background-color: var(--success-soft); color: var(--success-soft-fg); border-color: var(--success); }
.alert-warning { background-color: var(--warning-soft); color: var(--warning-soft-fg); border-color: var(--warning); }
.alert-info,
.alert-primary { background-color: var(--info-soft); color: var(--info-soft-fg); border-color: transparent; }

.alert p:last-child { margin-bottom: 0; color: inherit; }
/* :not(.btn) because an alert can carry a trailing action control (see .alert--inline),
   and a button in one is a button, not a link. Without the exclusion this rule - which is
   more specific than .btn-primary - repainted that control in the alert's own text colour
   and underlined it, which is what the 2FA suggestion card on the dashboard and the
   "Upgrade to Pro" notice both looked like. Prose links inside alerts are unaffected. */
.alert a:not(.btn) { color: inherit; text-decoration: underline; }

/* =========================================================================
   TOOLBAR — search / filters above a list
   ========================================================================= */

.toolbar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-bottom: var(--space-5);
}

.toolbar__search { flex: 1 1 260px; min-width: 0; max-width: 420px; }
.toolbar__spacer { flex: 1 1 auto; }

.toolbar__group {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.toolbar__group .form-select { width: auto; min-width: 130px; }

/* Active filter chips */

.filter-chips {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-bottom: var(--space-5);
}

.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2) var(--space-1) var(--space-3);
  border: 1px solid var(--accent-border);
  border-radius: var(--radius-pill);
  background-color: var(--accent-soft);
  color: var(--accent-soft-fg);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
}

.filter-chip__label { color: inherit; opacity: 0.75; }

.filter-chip__remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: inherit;
  cursor: pointer;
}

.filter-chip__remove:hover { background-color: var(--accent-border); }
.filter-chip__remove svg { width: 10px; height: 10px; }

/* =========================================================================
   DATA TABLE
   ========================================================================= */

.table-wrap {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background-color: var(--surface);
  overflow: hidden;
  box-shadow: var(--shadow-xs);
}

.table-scroll { overflow-x: auto; }

/* Fixed layout, so the columns keep their proportions no matter how long one
   parcel's description or recipient list happens to be. Without it a single
   long address widens the table until Size and the row menu are pushed off the
   edge and have to be scrolled to - the auto algorithm sizes to content, and
   text-overflow needs a constrained box to ellipsize against. */
.data-table {
  width: 100%;
  table-layout: fixed;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--text-md);
}

.data-table caption {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}

.data-table thead th {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  padding: var(--space-4) var(--space-6);
  border-bottom: 1px solid var(--border);
  background-color: var(--surface-sunken);
  color: var(--text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-align: left;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

/* Rows are tall enough that a parcel reads as an object with several
   properties, rather than as one line in a message list. */
.data-table tbody td {
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--border-subtle);
  vertical-align: middle;
}

.data-table tbody tr:last-child td { border-bottom: 0; }

.data-table tbody tr {
  transition: background-color var(--duration-fast) var(--ease);
}

.data-table tbody tr.is-clickable { cursor: pointer; }
.data-table tbody tr:hover { background-color: var(--surface-hover); }

.data-table tbody tr.is-selected { background-color: var(--accent-soft); }
.data-table tbody tr.is-selected:hover { background-color: var(--accent-soft); }

.data-table tbody tr:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: -2px;
}

/* The fixed columns. Whatever is left over is shared by the description and
   the recipients, which both truncate. */
.col-select { width: 52px; padding-right: 0 !important; }
.col-actions { width: 60px; text-align: right; }
.col-status { width: 132px; }
.col-date { width: 186px; }
.col-size { width: 104px; }

/* As the window narrows, the fixed columns give ground before the two that
   carry free text do. Size goes first - it is the least load-bearing column and
   the drawer still has it - then status and the deadline tighten up. */
@media (max-width: 1279.98px) {
  .data-table .col-size { display: none; }
}

@media (max-width: 1099.98px) {
  .col-status { width: 118px; }
  .col-date { width: 172px; }
}
.col-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* A date and a byte count are single tokens: wrapping "2026-08-29 15:35" onto
   two lines to save a few pixels makes the column harder to scan, not easier.
   Free text truncates with an ellipsis instead (see .u-truncate). */
.col-date { white-space: nowrap; }
.cell-stacked__main,
.cell-stacked__sub { overflow: hidden; text-overflow: ellipsis; }
.col-date .cell-stacked__main,
.col-date .cell-stacked__sub,
.col-num .cell-stacked__main,
.col-num .cell-stacked__sub { white-space: nowrap; }



/* Sortable header */

.th-sort {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: inherit;
  font: inherit;
  text-transform: inherit;
  letter-spacing: inherit;
}

.th-sort:hover { color: var(--text); }

.th-sort__icon {
  display: inline-flex;
  align-items: center;
  width: 12px;
  height: 12px;
  opacity: 0.35;
  transition: opacity var(--duration-fast) var(--ease);
}

.th-sort__icon svg { width: 12px; height: 12px; }
.th-sort__icon > span { display: inline-flex; }
.th-sort:hover .th-sort__icon { opacity: 0.7; }
[aria-sort="ascending"] .th-sort__icon,
[aria-sort="descending"] .th-sort__icon { opacity: 1; color: var(--accent-text); }

/* Primary cell: title over a secondary line */

/* The identity cell has to answer "which parcel is this?" at a glance, so the
   description carries real weight and the short id and delivery channels sit
   under it - together they are what a list of shipments is scanned by. */

.cell-primary { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }

.cell-primary__title {
  color: var(--text);
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  line-height: var(--leading-snug);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cell-primary__meta {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  color: var(--text-subtle);
  font-size: var(--text-xs);
}

/* The device column of the Profile session list: an icon, a name, a browser and
   sometimes a badge. .cell-primary__title clips to one line with an ellipsis, which
   is right for a parcel description and wrong here - it cut "Desktop - Chrome" to
   "Desktop - Chr" and hid the "Current session" badge entirely. This wraps instead,
   and lets the row be as tall as it needs to be. */
.device-name {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  overflow: visible;
  white-space: normal;
}

.device-name svg { flex: 0 0 auto; color: var(--text-subtle); }

/* .col-actions is 60px because everywhere else it holds an icon-only overflow
   menu. Here it holds a "Sign out" button, which is a word, and the fixed table
   layout let it spill out of the cell and put a scrollbar under the panel. */
.device-table .col-actions { width: 136px; }
.device-table .col-date { width: 168px; }
.device-table .col-ip { width: 152px; }
.device-name__label { white-space: nowrap; }

/* Which channels this parcel will actually go out on. Derived from the
   recipients already on the parcel - no new data, it was just never shown. */
.channel-set { display: inline-flex; align-items: center; gap: var(--space-2); }

.channel-set__item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: var(--radius-sm);
  background-color: var(--surface-sunken);
  color: var(--text-muted);
}

.channel-set__item svg { width: 13px; height: 13px; }


.cell-stacked { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.cell-stacked__main { color: var(--text); font-size: var(--text-md); }
.cell-stacked__sub { color: var(--text-subtle); font-size: var(--text-sm); }
.cell-stacked__sub--warn { color: var(--warning-soft-fg); }
.cell-stacked__sub--danger { color: var(--danger-soft-fg); }

/* =========================================================================
   MOBILE CARD LIST — the same rows below the table breakpoint
   ========================================================================= */

.card-list { display: flex; flex-direction: column; gap: var(--space-3); }

.record-card {
  display: flex;
  gap: var(--space-4);
  padding: var(--space-5);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background-color: var(--surface);
  box-shadow: var(--shadow-xs);
  transition: border-color var(--duration-fast) var(--ease),
              background-color var(--duration-fast) var(--ease);
}

.record-card.is-selected {
  border-color: var(--accent-border);
  background-color: var(--accent-soft);
}

.record-card__body { flex: 1 1 auto; min-width: 0; }

.record-card__head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}

/* Takes the slack, so the badge and the overflow menu stay together on the
   right instead of being spread across the row. */
.record-card__title {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.record-card__rows { display: grid; gap: var(--space-2); }

.record-card__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  font-size: var(--text-sm);
}

/* The card carries the same overflow menu as the table row, so it needs to be
   able to shrink past the title's ideal width. */
.record-card__head .dropdown { flex-shrink: 0; margin-right: calc(var(--space-3) * -1); }

.record-card__key { color: var(--text-subtle); flex-shrink: 0; }
.record-card__val { color: var(--text); text-align: right; min-width: 0; overflow: hidden; text-overflow: ellipsis; }

/* =========================================================================
   BULK ACTION BAR
   ========================================================================= */

.bulk-bar {
  position: sticky;
  bottom: var(--space-5);
  z-index: var(--z-sticky);
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
  margin-top: var(--space-5);
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background-color: var(--surface-raised);
  box-shadow: var(--shadow-lg);
  animation: bulk-in var(--duration-normal) var(--ease-out);
}

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

@keyframes bulk-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Quiet note under a list - a retention policy, a caveat. */
.list-footnote {
  margin: var(--gap-block) 0 0;
  color: var(--text-subtle);
  font-size: var(--text-xs);
  text-align: center;
}

.bulk-bar__count {
  font-weight: var(--weight-semibold);
  white-space: nowrap;
}

.bulk-bar__actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-left: auto;
}

/* =========================================================================
   PAGINATION
   ========================================================================= */

.pagination-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
  margin-top: var(--space-5);
}

.pagination-bar__info { color: var(--text-muted); font-size: var(--text-sm); }

.pagination {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0;
  margin: 0;
  list-style: none;
}

.page-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 32px;
  padding: 0 var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background-color: var(--surface);
  color: var(--text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  transition: background-color var(--duration-fast) var(--ease),
              color var(--duration-fast) var(--ease);
}

.page-link:hover { background-color: var(--surface-hover); color: var(--text); }
.page-link svg { width: 14px; height: 14px; }

.page-item.active .page-link {
  border-color: var(--accent);
  background-color: var(--accent);
  color: var(--accent-fg);
}

.page-item.disabled .page-link {
  opacity: 0.45;
  pointer-events: none;
}

.pagination__ellipsis {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  color: var(--text-subtle);
}

/* =========================================================================
   EMPTY / LOADING / ERROR STATES
   ========================================================================= */

.state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: var(--space-16) var(--space-6);
  text-align: center;
}

.state__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  margin-bottom: var(--space-5);
  border-radius: var(--radius-lg);
  background-color: var(--surface-sunken);
  color: var(--text-subtle);
}

.state__icon svg { width: 22px; height: 22px; }
.state__icon--danger { background-color: var(--danger-soft); color: var(--danger-soft-fg); }

/* Outside a .state block (which already centres its children) the badge has to
   centre itself - the extend-all card, for one. */
.state__icon--centered { margin-left: auto; margin-right: auto; }

/* The same block used as a whole page rather than as an empty list: the title
   is the page's heading, so it takes the page-heading size. */
.state--page .state__title { font-size: var(--text-2xl); letter-spacing: -0.02em; }
.state--page .state__text { font-size: var(--text-base); }

.state__code {
  margin: 0 0 var(--space-2);
  color: var(--text-subtle);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
}

.state__title {
  margin: 0 0 var(--space-2);
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
}

.state__text {
  max-width: 42ch;
  margin: 0 0 var(--space-6);
  color: var(--text-muted);
}

.state__actions { display: flex; gap: var(--space-3); flex-wrap: wrap; justify-content: center; }

/* Skeletons */

.skeleton {
  border-radius: var(--radius-sm);
  background-color: var(--surface-sunken);
  background-image: linear-gradient(
    90deg,
    transparent 0%,
    var(--surface-hover) 50%,
    transparent 100%
  );
  background-size: 200% 100%;
  animation: shimmer 1.4s ease-in-out infinite;
}

@keyframes shimmer {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}

.skeleton-text { height: 12px; }
.skeleton-text + .skeleton-text { margin-top: var(--space-2); }
.skeleton-w-25 { width: 25%; }
.skeleton-w-40 { width: 40%; }
.skeleton-w-60 { width: 60%; }
.skeleton-w-80 { width: 80%; }

/* =========================================================================
   DRAWER — right-hand detail panel
   ========================================================================= */

.drawer-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background-color: var(--overlay);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--duration-normal) var(--ease),
              visibility var(--duration-normal) var(--ease);
}

.drawer-overlay.is-open { opacity: 1; visibility: visible; }

.drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: var(--z-drawer);
  display: flex;
  flex-direction: column;
  width: min(460px, 100vw);
  background-color: var(--surface);
  border-left: 1px solid var(--border);
  box-shadow: var(--shadow-xl);
  transform: translateX(100%);
  visibility: hidden;
  transition: transform var(--duration-slow) var(--ease-out),
              visibility var(--duration-slow) var(--ease-out);
}

.drawer.is-open { transform: translateX(0); visibility: visible; }

.drawer__header {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--border);
}

.drawer__title {
  margin: 0 0 var(--space-2);
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  overflow-wrap: anywhere;
}

.drawer__meta { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }

.drawer__close { margin-left: auto; flex-shrink: 0; }

/* Lead-in text under a drawer section heading. */
.drawer-section__intro {
  margin: 0 0 var(--gap-tight);
  color: var(--text-subtle);
  font-size: var(--text-xs);
  line-height: var(--leading-normal);
}

.drawer__body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: var(--space-6);
}

/*
 * The footer holds up to four actions in a 460px drawer, and .btn never wraps its label. English
 * fits on one line; Ukrainian ("Попередній перегляд") does not, and a non-wrapping row answered
 * that by shrinking the buttons until their labels ran over each other. So: wrap instead, and no
 * button may be squeezed narrower than its own text. .u-grow's min-width:0 is the specific thing
 * that allowed the primary to collapse under its label, so it is overridden here rather than
 * changed globally - elsewhere that min-width:0 is doing its job.
 */
.drawer__footer {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-6);
  border-top: 1px solid var(--border);
  background-color: var(--surface-sunken);
}

.drawer__footer > .btn { flex: 0 0 auto; }

/* Fills the row when everything fits, keeps its full label when it has to wrap. */
.drawer__footer > .btn.u-grow { flex: 1 1 auto; min-width: max-content; }

.drawer-section + .drawer-section { margin-top: var(--space-7); }

.drawer-section__title {
  margin: 0 0 var(--space-4);
  color: var(--text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.def-list { display: grid; gap: var(--space-3); margin: 0; }

.def-list__row {
  display: grid;
  grid-template-columns: minmax(96px, 38%) 1fr;
  gap: var(--space-4);
  align-items: baseline;
  font-size: var(--text-md);
}

.def-list__key { color: var(--text-muted); }
.def-list__val { color: var(--text); overflow-wrap: anywhere; }

/* Set off from the block above it rather than sitting straight underneath. */
.def-list--spaced { margin-top: var(--gap-field); }

@media (max-width: 575.98px) {
  .drawer { width: 100vw; }
}

/* =========================================================================
   MODALS (Bootstrap markup, restyled)
   ========================================================================= */

.modal-content {
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  background-color: var(--surface);
  box-shadow: var(--shadow-xl);
}

.modal-header {
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--border);
  align-items: center;
}

.modal-title { margin: 0; font-size: var(--text-lg); font-weight: var(--weight-semibold); }

.modal-body { padding: var(--space-6); color: var(--text); }

.modal-footer {
  gap: var(--space-3);
  padding: var(--space-5) var(--space-6);
  border-top: 1px solid var(--border);
}

.modal-footer > * { margin: 0; }

.modal-backdrop { background-color: var(--overlay); }
.modal-backdrop.show { opacity: 1; }

/* Bootstrap sizes this from .modal-header with its own padding and negative
   margins, which is how it ended up 46px next to a 32px topbar control. Both
   are pinned here so the close sits on the same scale as every other icon
   button. */
.modal-header .btn-close { padding: 0; margin: 0 0 0 auto; }

.btn-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--control-h-sm);
  height: var(--control-h-sm);
  padding: 0;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%237d8698' stroke-width='1.75' stroke-linecap='round'%3E%3Cpath d='M4 4l8 8M12 4l-8 8'/%3E%3C/svg%3E")
    center / 14px no-repeat;
  opacity: 1;
  cursor: pointer;
}

.btn-close:hover { background-color: var(--surface-hover); }

/* =========================================================================
   DROPDOWN (Bootstrap markup, restyled)
   ========================================================================= */

.dropdown-menu {
  min-width: 190px;
  padding: var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background-color: var(--surface-raised);
  box-shadow: var(--shadow-lg);
  font-size: var(--text-md);
}

.dropdown-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  color: var(--text);
  cursor: pointer;
}

.dropdown-item svg { width: 15px; height: 15px; color: var(--text-subtle); }

.dropdown-item:hover,
.dropdown-item:focus {
  background-color: var(--surface-hover);
  color: var(--text);
}

.dropdown-item:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }

.dropdown-item.text-danger { color: var(--danger-text); }
.dropdown-item.text-danger svg { color: var(--danger-text); }
.dropdown-item.text-danger:hover { background-color: var(--danger-soft); color: var(--danger-soft-fg); }

.dropdown-item.disabled,
.dropdown-item:disabled { color: var(--text-subtle); pointer-events: none; opacity: 0.55; }

.dropdown-divider {
  height: 1px;
  margin: var(--space-2) 0;
  border: 0;
  background-color: var(--border);
  opacity: 1;
}

.dropdown-header {
  padding: var(--space-3) var(--space-4) var(--space-2);
  color: var(--text-subtle);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* Row menu trigger - see ICON BUTTON, which it shares a definition with. */
.row-menu-toggle { color: var(--text-subtle); }
.row-menu-toggle:hover { background-color: var(--surface-active); }

/* =========================================================================
   TOOLTIP (Bootstrap markup, restyled)
   ========================================================================= */

/* A hint that floats over the page, so it reads like the dropdowns and the
   drawer rather than like a block of the opposite theme: dark-on-light in the
   light scheme, and a raised dark panel - not a white slab - in the dark one. */
.tooltip .tooltip-inner {
  max-width: 260px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--tooltip-border);
  border-radius: var(--radius-md);
  background-color: var(--tooltip-bg);
  color: var(--tooltip-fg);
  font-size: var(--text-xs);
  font-family: var(--font-sans);
  line-height: var(--leading-snug);
  text-align: center;
  box-shadow: var(--shadow-md);
}

.tooltip .tooltip-arrow::before { border-top-color: var(--tooltip-bg); }
.tooltip.bs-tooltip-bottom .tooltip-arrow::before { border-bottom-color: var(--tooltip-bg); }
.tooltip.bs-tooltip-start .tooltip-arrow::before { border-left-color: var(--tooltip-bg); }
.tooltip.bs-tooltip-end .tooltip-arrow::before { border-right-color: var(--tooltip-bg); }
.tooltip.show { opacity: 1; }

/* =========================================================================
   TABS
   ========================================================================= */

.tabs {
  display: flex;
  gap: var(--space-2);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--space-6);
  overflow-x: auto;
}

.tab {
  position: relative;
  padding: var(--space-4) var(--space-4);
  border: 0;
  background: transparent;
  color: var(--text-muted);
  font-size: var(--text-md);
  font-weight: var(--weight-medium);
  white-space: nowrap;
  cursor: pointer;
}

.tab:hover { color: var(--text); }

.tab[aria-selected="true"] { color: var(--accent-text); }

.tab[aria-selected="true"]::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  border-radius: 2px 2px 0 0;
  background-color: var(--accent);
}

/* =========================================================================
   COPY FIELD — read-only value with a copy button
   ========================================================================= */

.copy-field { display: flex; flex-direction: column; gap: var(--space-2); }

.copy-field__label {
  color: var(--text);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

.copy-field__hint { color: var(--text-subtle); font-size: var(--text-xs); }

.copy-field .form-control {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

.copy-field + .copy-field { margin-top: var(--space-5); }

/* =========================================================================
   SEGMENTED CONTROL
   ========================================================================= */

.segmented {
  display: inline-flex;
  padding: 3px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background-color: var(--surface-sunken);
}

.segmented__option {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease),
              color var(--duration-fast) var(--ease);
}

.segmented__option:hover { color: var(--text); }

.segmented__option[aria-pressed="true"],
.segmented__option.is-active {
  background-color: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-xs);
}

.segmented__option svg { width: 15px; height: 15px; }

/* Comfortable to tap, without inflating the control on a desktop. */
@media (pointer: coarse) {
  .segmented__option { min-height: 38px; padding-inline: var(--space-5); }
}

/* =========================================================================
   FEATURE LIST & PRICING
   =========================================================================
   Shared by the landing page and the subscription page, which show the same
   plans. They live here rather than in landing.css so /subscription does not
   have to pull the whole landing stylesheet in to render four cards.
   ========================================================================= */

.feature-list { display: grid; gap: var(--space-4); padding: 0; margin: 0; list-style: none; }

.feature-list li {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-5);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background-color: var(--surface);
  font-size: var(--text-md);
  font-weight: var(--weight-medium);
}

.feature-list svg { width: 16px; height: 16px; color: var(--success-text); flex-shrink: 0; }

/* ---------------------------------------------------------------- pricing */

.pricing-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 380px));
  gap: var(--space-6);
  justify-content: center;
}

.pricing-plan {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: var(--space-9) var(--space-8);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  background-color: var(--surface);
}

.pricing-plan--featured {
  border-color: var(--accent);
  box-shadow: var(--shadow-lg);
}

.pricing-plan__tag { position: absolute; top: var(--space-5); right: var(--space-5); }

.pricing-plan__name {
  margin: 0 0 var(--space-5);
  font-size: var(--text-md);
  color: var(--text-muted);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.pricing-plan__price {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  margin: 0 0 var(--space-6);
  font-size: var(--text-4xl);
  font-weight: var(--weight-bold);
  color: var(--text);
  letter-spacing: -0.03em;
}

.pricing-plan__price small {
  font-size: var(--text-sm);
  font-weight: var(--weight-normal);
  color: var(--text-muted);
  letter-spacing: 0;
}

.pricing-plan__features {
  display: grid;
  gap: var(--space-4);
  padding: 0;
  margin: 0 0 var(--space-8);
  list-style: none;
  flex: 1 1 auto;
}

.pricing-plan__features li {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  color: var(--text-muted);
  font-size: var(--text-md);
}

.pricing-plan__features svg { width: 15px; height: 15px; margin-top: 3px; color: var(--success-text); }

/* Inside a panel the cards are one of several blocks on a settings page, not
   the hero of a marketing section: tighter, and filling the width they are
   given rather than centring in it. */
.panel .pricing-grid,
.pricing-grid--compact {
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  justify-content: stretch;
}

.pricing-grid--compact .pricing-plan { padding: var(--space-8) var(--space-7); }
.pricing-grid--compact .pricing-plan__price { font-size: var(--text-3xl); margin-bottom: var(--space-2); }

/* The monthly equivalent and the saving are what make three term prices
   comparable at a glance, so they sit directly under the headline figure. */
.pricing-plan__per {
  margin: 0 0 var(--space-2);
  color: var(--text-muted);
  font-size: var(--text-md);
}

.pricing-plan__note {
  margin: 0 0 var(--space-7);
  min-height: 26px;
  color: var(--text-subtle);
  font-size: var(--text-sm);
}

/* Same idea for the feature list: a responsive grid when it is summarising a
   plan inside a panel, a single column when it is a marketing bullet list. */
.feature-list--grid { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }

/* Row of actions closing out a form or a panel. Lives here rather than in the
   wizard stylesheet because the unlock page and the offline bundle use it too,
   and neither of those loads newParcel.css. */

.form-actions,
.wizard-actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  justify-content: flex-end;
}

/* A back/cancel style action anchors to the far side of the row. */
.form-actions .btn-ghost,
.wizard-actions .btn-ghost { margin-right: auto; }

/* An actions row inside a stacked form stands a block away from the fields it
   submits, not a field's distance: the submit button is not another field, and
   at the field gap it reads as if it were attached to the input above it. */
.stack.stack > * + .wizard-actions,
.stack.stack > * + .form-actions { margin-top: var(--space-6); }

/* Actions that open something rather than confirm a step - the download/view
   pair after a parcel unlocks. */
.form-actions--start,
.wizard-actions--start { justify-content: flex-start; }

@media (max-width: 575.98px) {
  .form-actions,
  .wizard-actions { flex-wrap: wrap; }
  .form-actions .btn,
  .wizard-actions .btn { flex: 1 1 auto; }
  .form-actions .btn-ghost,
  .wizard-actions .btn-ghost { margin-right: 0; }
}

/* =========================================================================
   SETTINGS / FORM LAYOUT
   ========================================================================= */

.form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-5);
}

.field--full { grid-column: 1 / -1; }

@media (max-width: 767.98px) {
  .form-grid { grid-template-columns: 1fr; }
}

.setting-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-7);
  flex-wrap: wrap;
  min-height: var(--control-h-lg);
}

.setting-row__label {
  margin: 0;
  color: var(--text);
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
}

/* The row's headline value rather than its name - a plan tier, a status. */
.setting-row__label--lead {
  margin-top: var(--space-2);
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
}

.setting-row__hint {
  margin: var(--space-2) 0 0;
  color: var(--text-muted);
  font-size: var(--text-md);
  max-width: 60ch;
}

/* A checkbox in a list of settings is a row, not a bare control: it gets its
   own padding so it never sits flush against the panel edge or against the
   divider above it, and the whole row is the hit target. Used by the profile's
   notification list and by the wizard's recipient options - fixing it here
   fixes both rather than either page hand-tuning a margin. */

.check-row {
  padding: var(--space-4) var(--space-4);
  margin: 0 calc(var(--space-4) * -1);
  border-radius: var(--radius-md);
  transition: background-color var(--duration-fast) var(--ease);
}

.check-row:hover { background-color: var(--surface-hover); }

/* The divider is inset to match the row padding rather than cutting the full
   width of the panel. */
.check-row + .check-row { position: relative; }

.check-row + .check-row::before {
  content: "";
  position: absolute;
  top: 0;
  left: var(--space-4);
  right: var(--space-4);
  height: 1px;
  background-color: var(--border-subtle);
}

/* An alert closing out a list of settings needs air above it. */
.check-row + .alert { margin-top: var(--gap-block); }

/* A field that holds a small value (a day count, a quantity) should not stretch
   the full width of its panel. */
.field--narrow { max-width: 240px; }

/* A select sized to its content rather than its container - used where a
   control sits inline with a label instead of stacked under one. */
.form-select--auto { width: auto; min-width: 160px; }

/* Static unit suffix on an input group ("days", "MB"). Looks like the adjacent
   button so the group reads as one control, but is not interactive. */
.input-group__unit { pointer-events: none; }

/* ------------------------------------------------------------ vault picker
   The record chooser. Lives here rather than in vault.css because two pages use
   it: the Password Manager and the New Parcel wizard's Content step. */

.vault-picker {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-height: 46vh;
  overflow-y: auto;
  margin: 0;
  padding: 0;
  list-style: none;
}

.vault-pick-row {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  cursor: pointer;
}

.vault-pick-row:hover { background-color: var(--surface-hover); }
.vault-pick-row.is-selected {
  border-color: var(--accent-border);
  background-color: var(--accent-soft);
}

.vault-pick-row .form-check-input { margin: 0; flex-shrink: 0; }

.vault-pick-row__text {
  display: flex;
  flex-direction: column;
  min-width: 0;
  gap: 1px;
}

.vault-pick-row__name {
  color: var(--text);
  font-size: var(--text-md);
  font-weight: var(--weight-medium);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.vault-pick-row__sub {
  color: var(--text-subtle);
  font-size: var(--text-xs);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Tighter toolbar for use inside a dialog, where the page gutters are absent. */
.toolbar--tight { margin-bottom: var(--gap-field); }

/* ------------------------------------------------------------------ stepper
   Moved here from newParcel.css: two flows use it now - the New Parcel wizard
   and the Password Manager's vault setup - so it belongs in the shared layer
   rather than being duplicated or re-linked per page.
   A progress track, not a row of pills. Each step is an equal share of the
   full width with a connector running between the markers, so "where am I and
   how much is left" is answered by the shape of the thing rather than by
   reading five labels. */

.stepper {
  display: flex;
  align-items: flex-start;
  padding: 0;
  margin: 0 0 var(--gap-section);
  list-style: none;
  counter-reset: step;
}

.stepper__item {
  position: relative;
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-2);
  color: var(--text-subtle);
  font-size: var(--text-md);
  font-weight: var(--weight-medium);
  text-align: center;
  transition: color var(--duration-normal) var(--ease);
}

/* The connector sits behind the markers and stops at the last step. */
.stepper__item::before {
  content: "";
  position: absolute;
  top: 15px;
  left: calc(-50% + 16px);
  width: calc(100% - 32px);
  height: 2px;
  background-color: var(--border);
  transition: background-color var(--duration-normal) var(--ease);
}

.stepper__item:first-child::before { display: none; }

.stepper__dot {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  border: 2px solid var(--border);
  border-radius: 50%;
  background-color: var(--surface);
  color: var(--text-subtle);
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
  transition: background-color var(--duration-normal) var(--ease),
              border-color var(--duration-normal) var(--ease),
              color var(--duration-normal) var(--ease);
}

.stepper__label { line-height: var(--leading-snug); }

/* Where you are. */
.stepper__item.is-active { color: var(--text); font-weight: var(--weight-semibold); }

.stepper__item.is-active .stepper__dot {
  border-color: var(--accent);
  background-color: var(--accent);
  color: var(--accent-fg);
  box-shadow: var(--focus-ring-shadow);
}

/* What you have already done. Outlined rather than filled, so a completed step
   never carries more weight than the one you are actually on. */
.stepper__item.is-done { color: var(--text-muted); }

.stepper__item.is-done .stepper__dot {
  border-color: var(--accent);
  background-color: var(--surface);
  color: var(--accent-text);
}

.stepper__item.is-done::before,
.stepper__item.is-active::before { background-color: var(--accent); }

@media (max-width: 767.98px) {
  .stepper { margin-bottom: var(--space-7); }
  .stepper__item { font-size: var(--text-xs); padding: 0; gap: var(--space-2); }
  .stepper__dot { width: 30px; height: 30px; font-size: var(--text-sm); }
  .stepper__item::before { top: 14px; left: calc(-50% + 15px); width: calc(100% - 30px); }
}

@media (max-width: 479.98px) {
  .stepper__label { display: none; }
}

/* ------------------------------------------------------------- record field
   One stored value: a fixed-width label, the value, then the actions. Used by
   the Password Manager's detail pane and by the parcel viewer, so a credential
   handed to a recipient reads exactly the way it did in the vault it came from.

   Copy sits in the same column on every row so it can be hit without aiming. */

.record-field {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-2);
  border-radius: var(--radius-md);
}

.record-field:hover { background-color: var(--surface-hover); }

.record-field__label {
  padding-top: 2px;
  color: var(--text-subtle);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.record-field__value { min-width: 0; }

.record-field__text {
  display: block;
  color: var(--text);
  font-size: var(--text-md);
  line-height: var(--leading-normal);
  white-space: pre-wrap;
  word-break: break-word;
}

/* A revealed secret is monospaced: distinguishing l from 1 matters more here
   than matching the body face. */
.record-field__text.is-masked,
.record-field:has(.is-masked) .record-field__text { font-family: var(--font-mono); }

.record-field__actions {
  display: flex;
  gap: var(--space-1);
  /* Present but recessive until the row is hovered or something in it is focused. */
  opacity: 0.55;
  transition: opacity var(--duration-fast) var(--ease);
}

.record-field:hover .record-field__actions,
.record-field:focus-within .record-field__actions { opacity: 1; }

@media (max-width: 575.98px) {
  /* Too narrow for a label column: the label takes its own line and the actions
     stop hiding, since there is no hover on a touch screen to reveal them. */
  .record-field {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "label label" "value actions";
    row-gap: var(--space-2);
  }
  .record-field__label   { grid-area: label; }
  .record-field__value   { grid-area: value; }
  .record-field__actions { grid-area: actions; opacity: 1; }
}

/* A block value inside a record field: notes, an address, a long secure note. The label sits on
   its own line because the value needs the full width to keep its line breaks readable. */
.record-field--block {
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "label label" "value actions";
  row-gap: var(--space-2);
}

.record-field--block .record-field__label   { grid-area: label; }
.record-field--block .record-field__value   { grid-area: value; }
.record-field--block .record-field__actions { grid-area: actions; align-self: start; }

.record-field__text--pre {
  display: block;
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  white-space: pre-wrap;
  word-break: break-word;
}

/* Copy confirmed. */
.icon-btn.is-done { color: var(--success-text); }

/* ------------------------------------------------------------- record mark
   The tile beside a saved record: a recognised service's own colour with its
   letters, a stable colour derived from the name when nothing is recognised, or
   the record type's glyph for things with no service behind them.

   Colours are set inline from brand-marks.js, since they come from the record. */

.record-mark {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border-radius: var(--radius-md);
  background-color: var(--surface-sunken);
  color: var(--text-muted);
  overflow: hidden;
}

.record-mark svg { width: 16px; height: 16px; }

.record-mark--letters {
  /* A hairline inset keeps a near-black brand tile from dissolving into a dark
     background, without drawing a border in the brand's own colour. */
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.12);
}

.record-mark__text {
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  letter-spacing: 0.01em;
  line-height: 1;
}

.record-mark--sm { width: 28px; height: 28px; border-radius: var(--radius-sm); }
.record-mark--sm .record-mark__text { font-size: var(--text-2xs); }
.record-mark--sm svg { width: 14px; height: 14px; }

.record-mark--lg { width: 44px; height: 44px; border-radius: var(--radius-lg); }
.record-mark--lg .record-mark__text { font-size: var(--text-base); }
.record-mark--lg svg { width: 20px; height: 20px; }

/* ---------------------------------------------------------------- record nav
   The category list. Three surfaces use it - the Password Manager, the wizard's
   record picker and the parcel a recipient opens - so it lives here rather than
   in any one page's stylesheet.

   Chips are the default, because that is the form that works everywhere: in a
   dialog, above a list, and on a phone. The vertical rail is the opt-in, and
   only where there is width for one. Written this way round so the responsive
   behaviour is one rule rather than a page re-describing a chip. */

.record-nav {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--gap-field);
}

.record-nav__item {
  display: flex;
  align-items: center;
  /* This gap is what holds the count off the end of the label. */
  gap: var(--space-3);
  flex: 0 0 auto;
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: none;
  color: var(--text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  text-align: left;
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease),
              border-color var(--duration-fast) var(--ease),
              color var(--duration-fast) var(--ease);
}

.record-nav__item:hover { background-color: var(--surface-hover); color: var(--text); }

.record-nav__item.is-active {
  border-color: var(--accent-border);
  background-color: var(--accent-soft);
  color: var(--accent-soft-fg);
  font-weight: var(--weight-semibold);
}

.record-nav__icon { display: flex; flex-shrink: 0; }
.record-nav__icon svg { width: 16px; height: 16px; }

.record-nav__label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.record-nav__count {
  flex-shrink: 0;
  color: var(--text-subtle);
  font-size: var(--text-2xs);
  font-variant-numeric: tabular-nums;
}

.record-nav__item.is-active .record-nav__count { color: inherit; }

/* Shared by the Password Manager page and the parcel wizard's picker. */
/* Rail section headings (Folders / Tags / Types); in chip mode they take a full row. */
.record-nav__heading {
  flex: 1 0 100%;
  margin: var(--space-3) 0 var(--space-1);
  padding: 0 var(--space-4);
  color: var(--text-subtle);
  font-size: var(--text-2xs);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.record-nav__heading:first-of-type { margin-top: var(--space-2); }

/* A favourite's star: in the row name, and on the toggle when it is on. */
.vault-row__star { display: inline-flex; margin-left: var(--space-2); color: var(--warning); vertical-align: -2px; }
.vault-row__star svg { width: 13px; height: 13px; fill: currentColor; }
.icon-btn.is-on { color: var(--warning); }
.icon-btn.is-on svg { fill: currentColor; }

.vault-picker__bar { display: flex; justify-content: flex-end; margin: calc(-1 * var(--space-2)) 0 var(--space-2); }


/* The rail: a full-height column of categories, for a layout with a spare
   column to give it. Below this width it stays in its chip form. */
@media (min-width: 1280px) {
  .record-nav--rail {
    flex-direction: column;
    flex-wrap: nowrap;
    gap: 2px;
    margin-bottom: 0;
  }

  .record-nav--rail .record-nav__item {
    width: 100%;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    padding: var(--space-3) var(--space-4);
  }

  /* In a rail the label grows so the count sits against the right edge; in a
     chip there is nothing to grow into and the gap does the separating. */
  .record-nav--rail .record-nav__label { flex: 1 1 auto; }
}

/* ------------------------------------------------------------- field error
   The message for one invalid control, sitting directly under it. Paired with
   .is-invalid on the control itself. */

.field-error {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin: var(--space-2) 0 0;
  color: var(--danger-text);
  font-size: var(--text-xs);
  line-height: var(--leading-snug);
}

/* A leading marker so the message reads as an error without relying on colour
   alone, which would leave it ambiguous for anyone who cannot see the red. */
.field-error::before {
  content: "";
  flex-shrink: 0;
  width: 14px;
  height: 14px;
  margin-top: 1px;
  background-color: currentColor;
  /* An exclamation in a circle, as a mask so it takes the text colour. */
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='black' d='M8 1.5A6.5 6.5 0 1 0 8 14.5 6.5 6.5 0 0 0 8 1.5Zm0 3a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4.5Zm0 6.25a.9.9 0 1 1 0 1.8.9.9 0 0 1 0-1.8Z'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* A form-text hint directly followed by an error would read as two competing
   instructions, so the hint steps back while the error is up. */
.field-error + .form-text,
.form-text:has(+ .field-error) { display: none; }

/* -------------------------------------------------------------- chip input
   Recipient entry: committed values become chips, the caret stays in a text
   area that shares the box with them. The wrapper takes the appearance of a
   form control and the real <input> inside it goes transparent, so the two
   read as one field. */

.chip-input {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--control-h);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  background-color: var(--surface);
  cursor: text;
  transition: border-color var(--duration-fast) var(--ease),
              box-shadow var(--duration-fast) var(--ease);
}

.chip-input:focus-within {
  border-color: var(--accent);
  box-shadow: var(--focus-ring-shadow);
}

.chip-input__chips {
  display: contents;
}

/* The original control, stripped of its own frame - the wrapper is the frame now. */
.chip-input .chip-input__entry.form-control {
  flex: 1 1 140px;
  width: auto;
  min-width: 120px;
  height: auto;
  min-height: 26px;
  padding: 0 var(--space-2);
  border: 0;
  background: none;
  box-shadow: none;
}

.chip-input .chip-input__entry.form-control:focus {
  border: 0;
  box-shadow: none;
}

/* The wrapper carries the invalid state so the whole field reads as wrong. */
.chip-input:has(.chip-input__entry.is-invalid) { border-color: var(--danger); }

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  max-width: 100%;
  padding: 3px 3px 3px var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background-color: var(--surface-sunken);
  color: var(--text);
  font-size: var(--text-sm);
  line-height: 1.4;
}

.chip__label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A chip that does not parse. Marked on the chip itself so a typo in the third
   of five addresses points at the third address, not at the field. */
.chip--invalid {
  border-color: var(--danger);
  background-color: var(--danger-soft);
  color: var(--danger-soft-fg);
  /* Colour alone would not carry this, so the label is underlined too. */
  text-decoration: underline wavy var(--danger);
  text-underline-offset: 3px;
}

.chip__remove {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--text-subtle);
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease),
              color var(--duration-fast) var(--ease);
}

.chip__remove svg { width: 11px; height: 11px; }

.chip__remove:hover {
  background-color: var(--surface-active);
  color: var(--text);
}

.chip--invalid .chip__remove:hover {
  background-color: var(--danger);
  color: var(--danger-fg);
}

/* A suggestion is a whole sentence, not a record name, so it wraps instead of
   being cut off - and the dialog's own header keeps its title and its count at
   opposite ends. Both are modifiers on the picker rather than a second list
   component, because the row is the same row. */
.vault-picker__bar--split { justify-content: space-between; align-items: center; }

.vault-pick-row--wrap { align-items: flex-start; }
.vault-pick-row--wrap .form-check-input { margin-top: 2px; }
.vault-pick-row--wrap .vault-pick-row__name { white-space: normal; overflow: visible; }

/* =============================================================================
   AUDIT TRAIL
   -----------------------------------------------------------------------------
   The audit modal. Built entirely from the existing tokens, so it follows the
   light/dark switch without a single hard-coded colour of its own, and reuses
   .data-table, .badge, .state, .def-list and .pagination rather than inventing
   a second table language for one panel.

   The one thing it does add is the stacked layout below 768px: an audit row has
   seven columns, and a horizontally scrolling seven-column table on a phone is a
   table nobody reads. Each cell carries a data-label (written by parcel-audit.js)
   and turns into a labelled line, which is the same information in the shape a
   narrow screen can actually take.
   ========================================================================== */

.audit__subtitle {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-2) 0 0;
  min-width: 0;
  font-size: var(--text-sm);
  color: var(--text-muted);
}

.audit__subtitle > span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------- filters ---------- */

/* A flex item of the scrollable modal content: it must keep its height while the
   table below it is what scrolls. */
.audit-filters {
  flex: 0 0 auto;
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--border);
  background-color: var(--surface-sunken);
}

.audit-filters__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: var(--space-4);
}

.audit-filters__grid .form-label {
  margin-bottom: var(--space-2);
  font-size: var(--text-xs);
  color: var(--text-muted);
}

/* The free-text box is the widest net, so it gets the widest cell it can have. */
.audit-filters__search { grid-column: span 2; }

.audit-filters__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-4);
}

/* ---------- body and states ---------- */

.audit__body { padding: 0; }

.audit-state { padding: var(--space-9) var(--space-6); }
.audit-state .skeleton-text { margin: var(--space-3) auto 0; max-width: 520px; }

.audit-table-wrap { border-radius: 0; }

/* A fixed layout with proportional columns, rather than letting the browser measure.
   Six of the seven columns hold a short, predictable value - a timestamp, a badge, an
   address - and auto layout gave each of them as much room as Details, which is the only
   column that is actually prose; email addresses ended up broken across three lines while
   the status column sat half empty. The proportions hold at every width, and min-width
   keeps them from collapsing before the stacked mobile layout takes over. */
.audit-table {
  min-width: 920px;
  table-layout: fixed;
}

.audit-table th:nth-child(1), .audit-table td:nth-child(1) { width: 9%; }   /* date   */
.audit-table th:nth-child(2), .audit-table td:nth-child(2) { width: 14%; }  /* event  */
.audit-table th:nth-child(3), .audit-table td:nth-child(3) { width: 14%; }  /* actor  */
.audit-table th:nth-child(4), .audit-table td:nth-child(4) { width: 16%; }  /* to     */
.audit-table th:nth-child(5), .audit-table td:nth-child(5) { width: 12%; }  /* status */
.audit-table th:nth-child(6), .audit-table td:nth-child(6) { width: 25%; }  /* details*/
.audit-table th:nth-child(7), .audit-table td:nth-child(7) { width: 10%; }  /* result */

.audit-table td { vertical-align: top; }

/* The timestamp is the row's identity; it is never the thing to abbreviate. */
.audit-table .col-date .cell-stacked__main,
.audit-table .col-date .cell-stacked__sub {
  overflow: visible;
  text-overflow: clip;
  white-space: nowrap;
}

.audit-row.is-failed td:first-child { box-shadow: inset 2px 0 0 var(--danger); }

.audit-row.is-expanded td { background-color: var(--surface-hover); }

.audit-row__end {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  justify-content: flex-end;
}

/* ---------- the event pill ----------
   Colour carries the category, not the outcome: the outcome has its own badge, and
   two colour systems in one row would fight. */

.audit-event {
  display: inline-block;
  max-width: 100%;
  padding: 3px var(--space-3);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  line-height: 1.5;
  background-color: var(--surface-sunken);
  color: var(--text-muted);
}

.audit-event--lifecycle { background-color: var(--accent-soft);          color: var(--accent-soft-fg); }
.audit-event--update    { background-color: var(--info-soft);            color: var(--info-soft-fg); }
.audit-event--recipient { background-color: var(--status-received-bg);   color: var(--status-received-fg); }
.audit-event--security  { background-color: var(--warning-soft);         color: var(--warning-soft-fg); }
.audit-event--access    { background-color: var(--status-waiting-bg);    color: var(--status-waiting-fg); }
.audit-event--file      { background-color: var(--status-expired-bg);    color: var(--status-expired-fg); }
.audit-event--delivery  { background-color: var(--success-soft);         color: var(--success-soft-fg); }

.audit-reconstructed { margin-left: var(--space-2); cursor: help; }

/* ---------- before -> after ---------- */

.audit-change {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.audit-change__field {
  font-size: var(--text-xs);
  color: var(--text-subtle);
}

.audit-change__pair {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--space-2);
  min-width: 0;
}

/* The old value is still readable - an audit trail is not a diff view - but the new
   one is what the row is about, so only that one is emphasised. */
.audit-change__from { color: var(--text-muted); word-break: break-word; }
.audit-change__arrow { color: var(--text-subtle); }
.audit-change__to { font-weight: var(--weight-medium); word-break: break-word; }

.audit-change__reason { color: var(--danger-text); word-break: break-word; }

/* Clamped to two lines: this is the glance-level summary, and the row that needs more than
   two lines of it is the row the reader should be opening rather than squinting at. */
.audit-change__plain {
  color: var(--text-muted);
  word-break: break-word;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ---------- the expanded panel ---------- */

.audit-expand { width: var(--control-h-sm); height: var(--control-h-sm); }
.audit-expand__icon { display: inline-flex; width: 16px; height: 16px; }
.audit-expand__icon svg { width: 16px; height: 16px; }

.audit-details-row > td { padding: 0; background-color: var(--surface-sunken); }

/* Two columns at most. Three of them left each definition list about 200px for its values,
   which is narrower than a timestamp or an email address - so the panel that exists to show
   the detail that did not fit was itself wrapping mid-word. */
.audit-details {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr));
  gap: var(--space-5);
  padding: var(--space-5) var(--space-6);
  border-top: 1px solid var(--border-subtle);
}

.audit-details__title {
  grid-column: 1 / -1;
  margin: 0;
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-subtle);
}

.audit-details__none { margin: 0; color: var(--text-muted); }

.audit-details__value {
  word-break: break-word;
  overflow-wrap: anywhere;
}

/* ---------- footer ---------- */

.audit__footer { justify-content: space-between; }
.audit__footer .pagination-bar__info { margin: 0; }

/* ---------- narrow screens ----------
   Below 768px the table stops being a grid and becomes one labelled block per
   event. Same markup, same data, same order - only the shape changes. */

@media (max-width: 767.98px) {
  .audit-filters { padding: var(--space-4); }
  .audit-filters__grid { grid-template-columns: 1fr 1fr; }
  .audit-filters__search { grid-column: 1 / -1; }

  .audit-table-wrap { overflow-x: visible; }

  .audit-table { min-width: 0; }
  .audit-table thead { display: none; }

  .audit-table tr { display: block; }

  .audit-table tbody tr.audit-row {
    padding: var(--space-4);
    border-bottom: 1px solid var(--border);
  }

  .audit-table td {
    display: flex;
    gap: var(--space-4);
    align-items: baseline;
    justify-content: space-between;
    padding: var(--space-1) 0;
    border: 0;
  }

  .audit-table td::before {
    content: attr(data-label);
    flex: 0 0 auto;
    font-size: var(--text-xs);
    color: var(--text-subtle);
  }

  /* The two cells that are their own headline rather than a labelled value. */
  .audit-table td[data-label]:nth-child(2) { justify-content: flex-start; }
  .audit-table td:nth-child(2)::before { display: none; }

  .audit-row.is-failed td:first-child { box-shadow: none; }
  .audit-row.is-failed { border-left: 2px solid var(--danger); }

  .audit-change { max-width: none; align-items: flex-end; text-align: right; }
  .audit-change__pair { justify-content: flex-end; }

  .audit-details-row > td { display: block; padding: 0; }
  .audit-details { grid-template-columns: 1fr; padding: var(--space-4); }
  .audit-details td::before { content: none; }

  .audit__footer { flex-direction: column; align-items: stretch; gap: var(--space-3); }
}

/* ------------------------------------------------------------------ plan limits
   The account-wide storage meter (paid plans) and the Free-vs-paid comparison on
   the subscription page. The meter turns amber past 90%, where a typical upload
   starts to be refused. */
.meter {
  height: 8px;
  margin: var(--space-2) 0;
  border-radius: 999px;
  background: var(--surface-sunken);
  overflow: hidden;
}

.meter__fill {
  display: block;
  height: 100%;
  max-width: 100%;
  border-radius: inherit;
  background: var(--accent);
}

.meter--warn .meter__fill { background: var(--warning); }

.plan-compare th[scope="row"] { font-weight: 500; }
.plan-compare td, .plan-compare th { white-space: normal; }


/* =========================================================================
   STORAGES (Storages page, Google Drive folder page, wizard storage choice)
   ========================================================================= */

.storage-card .setting-row__label--lead {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.storage-card__actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.storage-connection {
  border-top: 1px solid var(--border);
  display: grid;
  gap: var(--space-4);
}

.storage-facts {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: var(--space-2) var(--space-6);
  margin: 0;
}

.storage-facts dt {
  color: var(--text-muted);
  font-weight: var(--weight-medium);
}

.storage-facts dd {
  margin: 0;
  overflow-wrap: anywhere;
}

/* The disconnect confirmation: what happens, to which parcels, and "I understand". */
.storage-disconnect-confirm__body {
  display: grid;
  gap: var(--space-3);
  min-width: 0;
}

.storage-disconnect-confirm__title,
.storage-disconnect-confirm__text { margin: 0; }

.storage-disconnect-confirm__list {
  margin: 0;
  padding-left: var(--space-5);
  display: grid;
  gap: var(--space-1);
}

.storage-affected {
  list-style: none;
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background-color: var(--surface);
  display: grid;
  gap: var(--space-2);
}

.storage-affected li { overflow-wrap: anywhere; }

.storage-affected__meta {
  color: var(--text-muted);
  font-size: var(--text-sm);
  margin-left: var(--space-2);
}

.storage-affected__more { color: var(--text-muted); font-size: var(--text-sm); }

.folder-option {
  min-height: auto;
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--border);
}

/* The wizard's "where is this parcel kept" choice: one row per storage. */
.wizard-storage {
  margin: var(--space-8) 0 0;
  padding: var(--space-6) 0 0;
  border: 0;
  border-top: 1px solid var(--border);
}

.storage-choice {
  display: grid;
  gap: var(--space-3);
}

.storage-option {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  padding: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
}

.storage-option:has(input:checked) {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent);
}

.storage-option.is-disabled {
  cursor: not-allowed;
  opacity: .65;
}

.storage-option__body { display: grid; gap: var(--space-1); min-width: 0; }
.storage-option__name { font-weight: var(--weight-semibold); }
.storage-option__detail,
.storage-option__note { color: var(--text-muted); font-size: var(--text-md); overflow-wrap: anywhere; }

.storage-choice__actions {
  display: flex;
  gap: var(--space-3);
  flex-wrap: wrap;
  align-items: center;
}
