/* =========================================================
   Stellar Wholesale — reseller portal (VCD-271)
   wholesale.stellarsecurity.com (Laravel, server-rendered)

   THE SHARED LAYER. Every portal page loads this file; a page then
   adds at most one page file (sell.css, manage.css, billing.css) with
   its own layout only. Every class here is prefixed `sw-`.

   Tokens are the Stellar design system values (Stellar-Design-System.md),
   the same numbers as --se-* in eSIM-App/build and --sw-* in our reseller
   landing (Website/Wholesale-Landing/build). Everything is scoped to
   .sw-portal, so their developer can map our tokens to theirs and drop the
   markup into Blade templates without collisions. No global reset beyond
   the scoped minimum below.

   Contents
     Tokens, scoped minimum, focus, icons
     Buttons (incl. disabled, destructive), tags, status chips
     Forms: field, select, money, date range, checkbox, radio card,
            quantity stepper, notices (success, error, info), flash
     Segmented control + filter row (status dots)
     Search field + filter bar
     Shell: sidebar, top bar, menus, tab bar, More sheet
     Page head, cards, metric, wallet, dashboard, chart, Get started, meter
     Lists: result line, item cell, row actions, list note
     Table (stacks by its own width), list foot + pager
     Empty state, dialog / bottom sheet, large dialog + its content kit,
     auth, review index
   ========================================================= */

.sw-portal {
  /* Colour */
  --sw-blue:      #2761FC;
  --sw-blue-600:  #2152D4;
  --sw-ink:       #0B0C19;
  --sw-body:      #62626A;
  --sw-n200:      #D6D6E0;
  --sw-n100:      #EAEAF0;
  --sw-n50:       #F6F6FD;
  --sw-white:     #FFFFFF;
  --sw-success:   #00B252;
  --sw-error:     #E10000;
  --sw-blue-tint:    rgba(39, 97, 252, .08);
  --sw-success-tint: rgba(0, 178, 82, .10);
  --sw-error-tint:   rgba(225, 0, 0, .08);
  /* Warning (5 Oct 2026, Vlad's review): the DS had no warning colour, so a
     warning read as info. Amber, as the live portal's own notice boxes.
     #9A5B00 is 5.43:1 on white and 4.78:1 on its tint (AA for text). */
  --sw-warning:      #9A5B00;
  --sw-warning-tint: rgba(245, 158, 11, .16);

  /* Radius: cards 24, elements inside cards 16, panels 48, controls pill */
  --sw-r-panel: 48px;
  --sw-r-card:  24px;
  --sw-r-inner: 16px;
  --sw-r-pill:  999px;

  /* The only shadow in the system: floating menus */
  --sw-sh-float: 0 18px 40px rgba(11, 12, 25, .14);

  --sw-font: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  /* Identifiers and code (API pages): the DS has no mono face, so a system stack */
  --sw-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace;
  --sw-sidebar-w: 280px;
  /* The blue side panel (.sw-sidepanel) beside a form or a list: ONE width for
     the family, Webhooks and the Create API key dialog alike (Vlad, 7 Oct:
     "cramped"; was 320 / 316). Set the column with this, never a number. */
  --sw-sidepanel-w: 352px;
  --sw-topbar-h: 72px;
  /* Phone/tablet tab bar, same numbers as the eSIM app (.sa-tabbar) */
  --sw-tabbar-h: 58px;
  --sw-safe-b: env(safe-area-inset-bottom, 0px);
  --sw-gutter: 40px;

  /* Tabler chevron-down, body grey: every native <select> */
  --sw-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2362626A' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6l6 -6'/%3E%3C/svg%3E");
}

/* ---------- Scoped minimum ---------- */
body.sw-portal {
  margin: 0;
  font-family: var(--sw-font);
  font-size: 16px;
  line-height: 1.5;
  color: var(--sw-ink);
  background: var(--sw-n50);
  -webkit-font-smoothing: antialiased;
}
/* While a dialog or a bottom sheet is open the page behind does not scroll */
body.sw-portal.sw-locked { overflow: hidden; }
.sw-portal *, .sw-portal *::before, .sw-portal *::after { box-sizing: border-box; }
.sw-portal :where(h1, h2, h3, p, ul, ol, figure) { margin: 0; }
.sw-portal :where(ul, ol) { padding: 0; list-style: none; }
.sw-portal :where(h1, h2, h3) { font-weight: 700; color: var(--sw-ink); letter-spacing: 0; text-wrap: balance; }
.sw-portal :where(p) { color: var(--sw-body); }
.sw-portal :where(img) { display: block; max-width: 100%; }
.sw-portal :where(a) { color: inherit; text-decoration: none; }
.sw-portal :where(button) { font-family: inherit; }
[hidden] { display: none !important; }

/* Focus: 2px brand outline, 3px offset, on everything interactive.
   Inputs use the field ring instead (see .sw-input). */
.sw-portal :where(a, button, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--sw-blue);
  outline-offset: 3px;
}
/* On blue surfaces a blue outline disappears: switch it to white */
.sw-on-blue :where(a, button, [tabindex]):focus-visible { outline-color: #fff; }

.sw-sr-only {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.sw-skip {
  position: absolute; left: 16px; top: -100px; z-index: 100;
  background: var(--sw-blue); color: #fff; font-weight: 600; font-size: 14px;
  padding: 12px 20px; border-radius: var(--sw-r-pill);
}
.sw-skip:focus { top: 12px; }

/* Icons: Tabler outline, inline SVG, stroke inherits currentColor.
   One icon per product everywhere (eSIM-App/build/account.html, "Stellar
   apps"): eSIM = device-sim, Stellar VPN = shield-check, Stellar Antivirus =
   shield-exclamation, Stellar Protect = device-mobile. */
.sw-ic { width: 20px; height: 20px; flex: none; }

/* Review-only state switch (main.js, ?state=empty). In Blade these are
   @if / @else branches; nothing here ships as a runtime feature. */
[data-sw-state="empty"] [data-when="filled"],
[data-sw-state="filled"] [data-when="empty"],
html:not([data-sw-state]) [data-when="empty"] { display: none !important; }
[data-sw-state="empty"] .sw-filternav, [data-sw-state="empty"] .sw-list :is(.sw-filterbar, .sw-result, .sw-table thead) { display: none; }

/* =========================================================
   Buttons — pill, Poppins 600. Same names and colours as the
   reseller landing (sw-btn-primary / sw-btn-white).
   ========================================================= */
.sw-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 48px; padding: 10.5px 22.5px;
  font-family: var(--sw-font); font-size: 16px; font-weight: 600; line-height: 1.4; letter-spacing: 0;
  /* Outlines are a real border, never an inset box-shadow: a 1.5px inset
     shadow on a box at a fractional y paints 1px on one edge and 2px on the
     other (Vlad, 26 Sep). Every variant carries the same transparent border,
     so all buttons keep one size; padding is 12/24 minus the border. */
  border: 1.5px solid transparent; border-radius: var(--sw-r-pill); cursor: pointer; white-space: nowrap;
  transition: background-color .18s ease, color .18s ease, border-color .18s ease, box-shadow .18s ease;
}
.sw-btn .sw-ic { width: 20px; height: 20px; }
.sw-btn-primary { background: var(--sw-blue); color: #fff; }
.sw-btn-primary:hover { background: var(--sw-blue-600); }
/* Secondary on light surfaces: the blue-outline pill of the stellarsecurity.com
   header ("Shop", replicated in eSIM-App/build/styles.css .se-site-shop).
   Works on white and on the soft page background alike. */
.sw-btn-secondary { background: transparent; color: var(--sw-blue); border-color: var(--sw-blue); }
.sw-btn-secondary:hover { background: var(--sw-blue-tint); color: var(--sw-blue-600); }
/* Destructive (Cancel & refund in the eSIM details): the secondary pill in
   Error red. On white only: #E10000 measures 5.0:1 there and disappears on
   blue (DS §2). The confirmation button in its dialog is the same red outline (26 Sep,
   Nielsen pass: a destructive confirm must not look like the safest button). */
.sw-btn-danger { background: transparent; color: var(--sw-error); border-color: var(--sw-error); }
.sw-btn-danger:hover { background: var(--sw-error-tint); }
/* White pill for blue surfaces (DS §5) */
.sw-btn-white { background: #fff; color: var(--sw-blue); }
.sw-btn-white:hover { background: #fff; box-shadow: var(--sw-sh-float); }
.sw-btn-sm { min-height: 44px; padding: 8.5px 18.5px; font-size: 14px; }
.sw-btn-block { display: flex; width: 100%; }
/* Disabled (e.g. Buy now while the balance is short): one grey
   pill for every variant, no hover */
.sw-btn:disabled, .sw-btn[aria-disabled="true"] {
  background: var(--sw-n100); color: var(--sw-body); border-color: transparent; box-shadow: none; cursor: not-allowed;
}
/* Text action: "View order history" (eSIM build .se-btn-ghost) */
.sw-textlink {
  display: inline-flex; align-items: center; gap: 6px; min-height: 44px;
  font-size: 14px; font-weight: 600; color: var(--sw-blue);
}
.sw-textlink:hover { color: var(--sw-blue-600); text-decoration: underline; text-underline-offset: 3px; }
.sw-textlink .sw-ic { width: 18px; height: 18px; }
.sw-iconbtn {
  display: inline-grid; place-items: center; width: 44px; height: 44px; flex: none;
  padding: 0; border: 0; border-radius: var(--sw-r-pill); background: none; color: var(--sw-ink); cursor: pointer;
}
.sw-iconbtn:hover { background: var(--sw-n50); }
.sw-iconbtn .sw-ic { width: 24px; height: 24px; }
/* Quiet 20px glyph in a 44px target (Show, Copy on a credential) */
.sw-iconbtn-sm .sw-ic { width: 20px; height: 20px; color: var(--sw-body); }
.sw-iconbtn-sm:hover .sw-ic, .sw-iconbtn-sm[aria-pressed="true"] .sw-ic, .sw-iconbtn-sm.is-done .sw-ic { color: var(--sw-blue); }

/* =========================================================
   Tags and status chips
   ========================================================= */
/* Text is blue-600, not the brand blue: #2761FC on its own 8% tint measures
   4.48:1, just under AA for 12px text; blue-600 measures 5.84:1. */
.sw-tag {
  display: inline-flex; align-items: center; flex: none;
  padding: 4px 10px; border-radius: var(--sw-r-pill);
  font-size: 12px; font-weight: 600; line-height: 1.4; letter-spacing: 0; white-space: nowrap;
  background: var(--sw-blue-tint); color: var(--sw-blue-600);
}
.sw-on-blue .sw-tag, .sw-tag-onblue { background: rgba(255, 255, 255, .16); color: #fff; }
.sw-tag-neutral { background: var(--sw-n100); color: var(--sw-body); }

/* Status chips (eSIM-App/build/app.css .sa-tag family). No amber: it is
   not in the design system. */
.sw-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; border-radius: var(--sw-r-pill);
  font-size: 12px; font-weight: 600; line-height: 1.4; white-space: nowrap;
}
/* Text is ink, colour lives in the dot and tint: coloured 12px text on its own tint fails AA
   (Ready 2.52:1, Processing 4.47:1, Needs attention 4.35:1). */
.sw-chip::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--sw-chip-dot, currentColor); flex: none; }
.sw-chip-ready     { background: var(--sw-success-tint); color: var(--sw-ink); --sw-chip-dot: var(--sw-success); }
.sw-chip-progress  { background: var(--sw-blue-tint);    color: var(--sw-ink); --sw-chip-dot: var(--sw-blue); }
.sw-chip-attention { background: var(--sw-error-tint);   color: var(--sw-ink); --sw-chip-dot: var(--sw-error); }
.sw-chip-off       { background: var(--sw-n100);         color: var(--sw-body); }

/* =========================================================
   Forms — field on white follows eSIM-App/build/app.css .sa-input
   (pill, 1.5px n200 border, blue border + soft ring on focus).
   Labels are sentence case, not the app's uppercase micro-label.
   ========================================================= */
.sw-form { display: grid; gap: 20px; }
.sw-field { display: grid; gap: 8px; }
.sw-label { font-size: 14px; font-weight: 500; color: var(--sw-ink); }
.sw-label-opt { font-weight: 400; color: var(--sw-body); }
.sw-input {
  width: 100%; min-height: 52px; padding: 13px 20px;
  font-family: var(--sw-font); font-size: 16px; line-height: 1.4; color: var(--sw-ink);
  background: #fff; border: 1.5px solid var(--sw-n200); border-radius: var(--sw-r-pill);
  transition: border-color .15s, box-shadow .15s;
}
.sw-input:hover { border-color: #B9B9C6; }
.sw-input:focus { outline: none; border-color: var(--sw-blue); box-shadow: 0 0 0 4px rgba(39, 97, 252, .12); }
.sw-input:disabled { background: var(--sw-n50); color: var(--sw-body); }
input.sw-input { text-overflow: ellipsis; }
.sw-hint { font-size: 13px; color: var(--sw-body); }
.sw-error { display: none; font-size: 13px; font-weight: 600; color: var(--sw-error); }
.sw-field.is-invalid .sw-input { border-color: var(--sw-error); }
.sw-field.is-invalid .sw-input:focus { box-shadow: 0 0 0 4px var(--sw-error-tint); }
.sw-field.is-invalid .sw-error { display: block; }

/* Textarea: the same field with the inner radius (a pill cannot hold several
   lines). Precedent: the eSIM site's partner form (.sep-field textarea). */
textarea.sw-input {
  display: block; min-height: 112px; resize: vertical;
  border-radius: var(--sw-r-inner); padding: 14px 20px; line-height: 1.5;
}

/* Select: the same field on a native <select>, with the Tabler chevron */
select.sw-input {
  appearance: none; -webkit-appearance: none;
  padding-right: 48px; cursor: pointer; text-overflow: ellipsis;
  background: #fff var(--sw-chevron) no-repeat right 18px center / 18px 18px;
}

/* Amount field: the currency sits inside the pill (top-up, refill) */
.sw-money { position: relative; }
.sw-money-sym {
  position: absolute; left: 20px; top: 50%; transform: translateY(-50%);
  font-size: 16px; font-weight: 500; line-height: 1; color: var(--sw-body); pointer-events: none;
}
.sw-money .sw-input { padding-left: 40px; font-variant-numeric: tabular-nums; }

/* Date range: two labelled date fields and Apply at the same 52px height
   (billing ledger; Orders and Request logs will reuse it) */
.sw-daterange { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px; }
.sw-daterange .sw-field { gap: 6px; }
.sw-daterange .sw-input { width: 176px; padding-inline: 18px 14px; }
.sw-daterange .sw-btn { min-height: 52px; }

/* Form-level message (Laravel session status: "We have emailed your
   password reset link", or a failed login). Only the leading icon takes the
   status colour; icons inside the message (a link arrow) keep their own. */
.sw-notice {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 14px 16px; border-radius: var(--sw-r-inner);
  font-size: 14px; line-height: 1.5; color: var(--sw-ink);
  background: var(--sw-success-tint);
}
.sw-notice > .sw-ic { color: var(--sw-success); margin-top: 1px; }
.sw-notice-error { background: var(--sw-error-tint); }
.sw-notice-error > .sw-ic { color: var(--sw-error); }
/* Info: a required step, not an error (billing details before a top-up).
   Brand tint, blue-600 icon and link, ink text. Replaces the live amber box. */
.sw-notice-info { background: var(--sw-blue-tint); }
.sw-notice-info > .sw-ic { color: var(--sw-blue-600); }
.sw-notice-body { display: grid; justify-items: start; gap: 2px; min-width: 0; }
.sw-notice-body p { color: var(--sw-ink); font-size: 14px; line-height: 1.5; }
.sw-notice-title { font-weight: 600; }
/* 44px target without making the message taller */
.sw-notice-body .sw-textlink { margin: 2px 0 -12px; }
.sw-notice-info .sw-textlink { color: var(--sw-blue-600); }
/* Three levels, one rule (5 Oct 2026): info = good to know (blue);
   warning = skipping it causes a problem the user can still fix (amber);
   danger = skipping it causes a problem that cannot be undone (red, the
   existing .sw-notice-error). Ink text on every level; the icon takes the
   level colour, and on warning the title and links too (danger titles stay
   ink: red on the red tint fails AA). Never amber or red on blue
   (DS §2): inside a blue panel a warning becomes a white card first. */
.sw-notice-warning { background: var(--sw-warning-tint); }
.sw-notice-warning > .sw-ic, .sw-notice-warning .sw-notice-title { color: var(--sw-warning); }
.sw-notice-warning .sw-textlink { color: var(--sw-warning); }
/* danger keeps an ink title: #E10000 on its own tint measures 4.33:1, under AA */

/* Flash: the notice after a POST redirect (Laravel session status),
   focused so a screen reader hears what changed */
.sw-flash { margin-bottom: 16px; }
.sw-flash:focus { outline: none; }
.sw-flash p { color: var(--sw-ink); }
.sw-flash a { font-weight: 600; color: var(--sw-blue); text-decoration: underline; text-underline-offset: 3px; }

/* The one checkbox (DS §5 "One box, one look"; eSIM-App/build/app.css
   .sa-check): 22px, radius 6, 1.5px n200; checked = blue with a white
   14px tick at 2.6 stroke. The whole label row is the target. */
.sw-check {
  display: inline-flex; align-items: center; gap: 10px; min-height: 44px;
  font-size: 14px; color: var(--sw-ink); cursor: pointer;
}
.sw-check input {
  flex: none; width: 22px; height: 22px; margin: 0;
  appearance: none; -webkit-appearance: none;
  background: #fff no-repeat center / 14px 14px;
  border: 1.5px solid var(--sw-n200); border-radius: 6px; cursor: pointer;
  transition: background-color .15s, border-color .15s;
}
.sw-check input:checked {
  background-color: var(--sw-blue); border-color: var(--sw-blue);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 13 4 4L19 7'/%3E%3C/svg%3E");
}
.sw-check:hover input:not(:disabled) { border-color: var(--sw-blue); }
.sw-check input:focus-visible { outline: 2px solid var(--sw-blue); outline-offset: 3px; }

/* Radio card: one choice out of a few, each a card (VPN & Antivirus product
   and duration, Billing payment method). A real radio input; the card is the
   label and the target. Unchosen = white with the control outline (1.5px
   n200, as .sw-input); chosen = brand tint + blue ring, never a black fill.
   The round radio (.sw-radio) is the checkbox's twin: 22px, 1.5px n200,
   solid blue with a white centre when chosen. It closes the card on the
   right; the card carries the focus ring. */
.sw-radiocard {
  position: relative; display: flex; align-items: center; gap: 14px; min-height: 44px;
  padding: 14.5px; border-radius: var(--sw-r-inner); background: #fff;
  border: 1.5px solid var(--sw-n200); cursor: pointer; /* border, not inset shadow: see .sw-btn */
  transition: border-color .15s, background-color .15s;
}
.sw-radiocard:hover { border-color: var(--sw-blue); }
.sw-radiocard:has(.sw-radio:checked) { background: linear-gradient(var(--sw-blue-tint), var(--sw-blue-tint)), #fff; border-color: var(--sw-blue); }
.sw-radiocard:has(.sw-radio:focus-visible) { outline: 2px solid var(--sw-blue); outline-offset: 3px; }
.sw-radio {
  flex: none; width: 22px; height: 22px; margin: 0;
  appearance: none; -webkit-appearance: none; cursor: pointer;
  background: #fff; border: 1.5px solid var(--sw-n200); border-radius: 50%;
  transition: background-color .15s, border-color .15s;
}
.sw-radiocard > .sw-radio { order: 9; margin-left: auto; }
.sw-radiocard:hover .sw-radio, .sw-radio:checked { border-color: var(--sw-blue); }
.sw-radio:checked { background: radial-gradient(circle, #fff 0 4px, transparent 4.5px) var(--sw-blue); }
.sw-radio:focus-visible { outline: none; }
.sw-radiocard-text { display: grid; gap: 2px; min-width: 0; }
.sw-radiocard-title { font-size: 16px; font-weight: 600; line-height: 1.4; color: var(--sw-ink); }
.sw-radiocard-sub { font-size: 13px; line-height: 1.45; color: var(--sw-body); }

/* Quantity stepper (eSIM app #buyQty, eSIM-App/build/pages.css .sep-qty):
   pill track, round buttons with blue glyphs, bold typeable number. Buttons
   are 44px here, not the app's 36, to meet the 44px target. On white the
   track is n50 and the buttons white; on n50 use .sw-stepper-onsoft. */
.sw-stepper {
  display: inline-flex; align-items: center; gap: 2px; padding: 4px;
  border-radius: var(--sw-r-pill); background: var(--sw-n50);
}
.sw-stepper-btn {
  display: grid; place-items: center; width: 44px; height: 44px; padding: 0;
  border: 0; border-radius: 50%; background: #fff; color: var(--sw-blue); cursor: pointer;
  transition: background-color .15s, color .15s;
}
.sw-stepper-btn .sw-ic { width: 18px; height: 18px; stroke-width: 2.5; }
.sw-stepper-btn:hover:not(:disabled) { background: var(--sw-blue); color: #fff; }
.sw-stepper-btn:disabled { background: transparent; color: var(--sw-n200); cursor: default; }
.sw-stepper-input {
  width: 48px; padding: 0; border: 0; background: transparent; text-align: center;
  font-family: var(--sw-font); font-size: 16px; font-weight: 700; color: var(--sw-ink);
  font-variant-numeric: tabular-nums;
  -moz-appearance: textfield; appearance: textfield;
}
.sw-stepper-input::-webkit-outer-spin-button,
.sw-stepper-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.sw-stepper-input:focus { outline: 2px solid var(--sw-blue); outline-offset: 2px; border-radius: 8px; }
.sw-stepper-onsoft { background: #fff; }
.sw-stepper-onsoft .sw-stepper-btn { background: var(--sw-n50); }
.sw-stepper-onsoft .sw-stepper-btn:disabled { background: transparent; }

/* =========================================================
   Segmented control (eSIM build pages.css .sep-tabs): one control for
   every tab row in the portal — catalogue lists, order filters, billing
   sections. On a white card the track is n50; on the soft page it is white.
   ========================================================= */
.sw-seg { display: inline-flex; gap: 2px; padding: 4px; border-radius: var(--sw-r-pill); background: #fff; max-width: 100%; overflow-x: auto; }
.sw-card .sw-seg { background: var(--sw-n50); }
.sw-seg-item {
  display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 10px 18px;
  border: 0; border-radius: var(--sw-r-pill); background: none; cursor: pointer; white-space: nowrap;
  font-family: var(--sw-font); font-size: 14px; font-weight: 600; color: var(--sw-body);
  transition: background-color .18s, color .18s;
}
.sw-seg-item:hover { color: var(--sw-ink); }
.sw-seg-item:focus-visible { outline-offset: -2px; }
.sw-seg-item[aria-selected="true"]:focus-visible, .sw-seg-item[aria-current="page"]:focus-visible { outline-color: #fff; outline-offset: -4px; }
.sw-seg-item[aria-selected="true"], .sw-seg-item[aria-current="page"] { background: var(--sw-blue); color: #fff; }
.sw-seg-count { font-size: 12px; font-weight: 600; padding: 0 7px; border-radius: var(--sw-r-pill); background: var(--sw-n100); color: var(--sw-body); font-variant-numeric: tabular-nums; }
/* In the current segment: a white pill with blue-600 text (6.6:1). White on
   white-20% over blue measured 3.55:1. */
.sw-seg-item[aria-selected="true"] .sw-seg-count, .sw-seg-item[aria-current="page"] .sw-seg-count { background: #fff; color: var(--sw-blue-600); }
/* Status dot: ties a filter to its chip in the list (same colours as .sw-chip-*) */
.sw-seg-dot { width: 8px; height: 8px; flex: none; border-radius: 50%; background: var(--sw-dot, var(--sw-n200)); }
.sw-dot-ready     { --sw-dot: var(--sw-success); }
.sw-dot-progress  { --sw-dot: var(--sw-blue); }
.sw-dot-attention { --sw-dot: var(--sw-error); }
.sw-dot-off       { --sw-dot: #A3A3AD; }
.sw-seg-item[aria-current="page"] .sw-seg-dot, .sw-seg-item[aria-selected="true"] .sw-seg-dot { background: #fff; }

/* Filter row: the segmented control as a row of GET links (status, order
   type, transaction type). Replaces the live 85px count cards. On phones it
   becomes free pills that wrap, so every option stays visible (a scrolling
   track hides the last ones off-screen). */
.sw-main > .sw-filternav { margin-bottom: 16px; }
.sw-filternav .sw-seg { max-width: 100%; }
.sw-filternav .sw-seg-item { min-width: 44px; justify-content: center; }
/* A row wider than its track becomes the phone's free pills (as at 720 px)
   instead of shrinking the pills' padding: My eSIMs (5) and Request logs (4)
   need more than the track has between 721 and 1139 px. */
@media (max-width: 1139px) {
  .sw-filternav .sw-seg { flex-wrap: wrap; gap: 8px; padding: 0; background: none; overflow: visible; border-radius: 0; }
  .sw-filternav .sw-seg-item { background: #fff; padding: 10px 12px; }
  .sw-card .sw-filternav .sw-seg-item { background: var(--sw-n50); }
  .sw-filternav .sw-seg-item[aria-current="page"] { background: var(--sw-blue); }
}

/* =========================================================
   Search field + filter bar
   One GET form above a list. Controls are 48px, the sw-btn height, so a
   row of search, selects and buttons lines up. The search field carries its
   own submit (the arrow), so no separate "Search" button is needed; a
   select in the bar submits on change (main.js, data-sw-autosubmit) and
   still goes with the arrow or Enter without JavaScript.
   ========================================================= */
.sw-search { position: relative; }
.sw-search > .sw-ic {
  position: absolute; left: 18px; top: 50%; transform: translateY(-50%);
  width: 20px; height: 20px; color: var(--sw-body); pointer-events: none;
}
.sw-search .sw-input { padding-left: 46px; text-overflow: ellipsis; }
.sw-search .sw-input::-webkit-search-decoration,
.sw-search .sw-input::-webkit-search-cancel-button { -webkit-appearance: none; }
.sw-search-go { position: absolute; right: 2px; top: 50%; transform: translateY(-50%); color: var(--sw-blue); }
.sw-search-go .sw-ic { width: 20px; height: 20px; }
.sw-search:has(.sw-search-go) .sw-input { padding-right: 50px; }

.sw-filterbar { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 12px; }
.sw-filterbar .sw-input { min-height: 48px; padding-top: 11px; padding-bottom: 11px; font-size: 14px; }
.sw-filterbar > .sw-field { gap: 0; min-width: 0; }
.sw-filterbar-q { flex: 1 1 280px; }
.sw-filterbar-select { flex: 0 1 240px; }
.sw-filterbar .sw-hint { margin-top: 6px; padding-left: 20px; text-wrap: pretty; }

/* =========================================================
   Shell: full-height white sidebar + white top bar + soft main
   ========================================================= */
.sw-app {
  display: grid;
  grid-template-columns: var(--sw-sidebar-w) minmax(0, 1fr);
  min-height: 100vh;
}

/* The white column stretches with the page, so its background never stops
   at the window height (the live bug). The inner panel is sticky and exactly
   one viewport tall; if the nav is taller than the window, it scrolls on its
   own and every item stays reachable. */
.sw-sidebar { background: #fff; min-width: 0; }
.sw-sidebar-inner {
  position: sticky; top: 0;
  height: 100vh; height: 100dvh;
  display: flex; flex-direction: column;
  overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: thin; scrollbar-color: var(--sw-n200) transparent;
}
.sw-sidebar-head {
  display: flex; align-items: center; gap: 8px;
  min-height: 72px; padding: 16px 16px 12px 24px;
}
.sw-brand { display: inline-flex; align-items: center; flex: none; }
.sw-brand img { height: 24px; width: auto; }

.sw-nav { padding: 4px 16px 20px; }
.sw-nav-group + .sw-nav-group, .sw-nav > .sw-nav-link + .sw-nav-group { margin-top: 0; }
.sw-nav-label {
  padding: 14px 12px 4px;
  font-size: 13px; font-weight: 500; line-height: 20px; color: var(--sw-body); letter-spacing: 0;
}
.sw-nav-link {
  display: flex; align-items: center; gap: 12px;
  min-height: 44px; padding: 10px 12px;
  border-radius: var(--sw-r-pill);
  font-size: 14px; font-weight: 500; line-height: 1.4; color: var(--sw-ink);
  transition: background-color .15s, color .15s;
}
.sw-nav-link .sw-ic { color: var(--sw-body); stroke-width: 1.75; transition: color .15s; }
.sw-nav-link:hover { background: var(--sw-n50); }
.sw-nav-dot { display: inline-block; flex: 0 0 8px; width: 8px; height: 8px; margin-left: auto; border-radius: 50%; background: #e3435b; box-shadow: 0 0 0 3px rgba(227, 67, 91, .10); }
.sw-nav-link[aria-current="page"] { background: var(--sw-blue-tint); color: var(--sw-blue-600); font-weight: 600; }
.sw-nav-link[aria-current="page"] .sw-ic { color: var(--sw-blue); }
/* Short windows (a 13-14" laptop at 720-760 px): tighten the group gaps so
   the whole nav fits without scrolling. Taller content still scrolls. */
@media (max-height: 760px) and (min-width: 1024px) {
  .sw-sidebar-head { min-height: 64px; padding-top: 12px; padding-bottom: 8px; }
  .sw-nav-label { padding-top: 8px; padding-bottom: 2px; }
}

.sw-maincol { min-width: 0; display: flex; flex-direction: column; }

/* ---------- Top bar ---------- */
.sw-topbar {
  position: sticky; top: 0; z-index: 30;
  display: flex; align-items: center; gap: 16px;
  min-height: var(--sw-topbar-h); padding: 12px var(--sw-gutter);
  background: #fff; box-shadow: 0 1px 0 var(--sw-n100);
}
.sw-topbar-start { display: none; align-items: center; gap: 4px; min-width: 0; }
.sw-topbar-end { display: flex; align-items: center; gap: 12px; margin-left: auto; }
.sw-balance { display: grid; text-align: right; line-height: 1.25; padding-right: 4px; }
.sw-balance-label { font-size: 12px; font-weight: 500; color: var(--sw-body); }
.sw-balance-value { font-size: 16px; font-weight: 700; color: var(--sw-ink); font-variant-numeric: tabular-nums; }
.sw-topup-round { display: none; }

/* Account chip + menu (replaces the live separate Logout button) */
.sw-account { position: relative; }
.sw-account-btn {
  display: flex; align-items: center; gap: 10px;
  min-height: 48px; padding: 4px 12px 4px 4px;
  border: 0; border-radius: var(--sw-r-pill); background: none; cursor: pointer; text-align: left;
  color: var(--sw-ink);
}
.sw-account-btn:hover, .sw-account-btn[aria-expanded="true"] { background: var(--sw-n50); }
.sw-avatar {
  display: grid; place-items: center; width: 40px; height: 40px; flex: none;
  border-radius: 50%; background: var(--sw-blue); color: #fff;
  font-size: 14px; font-weight: 700; letter-spacing: 0;
}
.sw-account-id { display: grid; line-height: 1.3; min-width: 0; }
.sw-account-name { font-size: 14px; font-weight: 600; color: var(--sw-ink); }
.sw-account-mail { font-size: 12px; color: var(--sw-body); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sw-account-btn .sw-ic { width: 18px; height: 18px; color: var(--sw-body); transition: transform .18s; }
.sw-account-btn[aria-expanded="true"] .sw-ic { transform: rotate(180deg); }

/* Menus: account, Export, row "More". White, radius 20, the float shadow.
   A menu is anchored to its button inside .sw-menuwrap; .is-up opens it
   upwards when there is no room below. */
.sw-menuwrap { position: relative; display: inline-flex; }
.sw-menu {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 40;
  min-width: 220px; padding: 8px; text-align: left;
  background: #fff; border-radius: 20px; box-shadow: var(--sw-sh-float);
}
.sw-menu.is-up { top: auto; bottom: calc(100% + 8px); }
.sw-menu-item {
  display: flex; align-items: center; gap: 12px; width: 100%;
  min-height: 44px; padding: 10px 14px;
  border: 0; border-radius: 14px; background: none; cursor: pointer; text-align: left;
  font-family: var(--sw-font); font-size: 14px; font-weight: 500; color: var(--sw-ink);
}
.sw-menu-item .sw-ic { color: var(--sw-body); }
.sw-menu-item:hover { background: var(--sw-n50); }
/* A disabled item (Disable on an already disabled endpoint) reads as unavailable, like .sw-btn:disabled */
.sw-menu-item:disabled, .sw-menu-item:disabled .sw-ic { color: var(--sw-body); opacity: .55; cursor: not-allowed; }
.sw-menu-item:disabled:hover { background: none; }
.sw-menu-item[data-sw-confirm="dlg-cancel"], .sw-menu-item[data-sw-confirm="dlg-cancel"] .sw-ic { color: var(--sw-error); }
.sw-menu-sep { height: 1px; margin: 6px 8px; background: var(--sw-n100); }

/* ---------- Phone/tablet navigation: bottom tab bar ----------
   Follows eSIM-App/build/app.css .sa-tabbar (height, safe area, translucent
   white, hairline on top, 24px icons, 11px labels, blue when current).
   Tabs and labels as on the live portal: Home, Shop, Inventory, Orders, More.
   Hidden from 1024 px, where the sidebar takes over. */
.sw-tabbar { display: none; }
.sw-tab {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  min-height: 44px; padding: 6px 0 0; margin: 0;
  border: 0; background: none; cursor: pointer;
  font-family: var(--sw-font); font-size: 11px; font-weight: 600; line-height: 1.2; color: var(--sw-body);
}
.sw-tab .sw-ic { width: 24px; height: 24px; stroke-width: 1.8; }
.sw-tab[aria-current="page"] { color: var(--sw-blue); }
/* A page that lives in the More sheet (Billing, Developer, Settings): More is the current tab */
.sw-tabbar:not(:has(.sw-tab[aria-current="page"])) .sw-tab[data-sw-more] { color: var(--sw-blue); }
.sw-tab:focus-visible { outline-offset: -4px; border-radius: 14px; }

/* ---------- Bottom sheet (eSIM-App/build/app.css .sa-sheet) ----------
   The More sheet: the destinations that have no tab, plus the account and
   Log out. The grab handle is shared with the dialog's phone sheet. */
.sw-sheet {
  position: fixed; inset: 0; z-index: 70;
  display: none; align-items: flex-end; justify-content: center;
  background: rgba(11, 12, 25, .45);
}
.sw-sheet.is-open { display: flex; }
.sw-sheet-panel {
  width: 100%; max-width: 560px; max-height: 92vh; max-height: 92dvh;
  overflow-y: auto; overscroll-behavior: contain;
  background: #fff; border-radius: var(--sw-r-card) var(--sw-r-card) 0 0;
  padding: 0 16px calc(12px + var(--sw-safe-b));
  animation: sw-sheet-up .26s cubic-bezier(.2, .8, .3, 1);
}
@keyframes sw-sheet-up { from { transform: translateY(16px); opacity: .6; } to { transform: none; opacity: 1; } }
/* Grab handle = the close button, as in the app; the hit area is 44 px tall.
   Its focus ring hugs the handle area instead of the square button box. */
.sw-sheet-grab {
  position: relative; display: block; width: 88px; height: 44px; margin: 0 auto;
  padding: 0; border: 0; background: none; cursor: pointer;
}
.sw-sheet-grab:focus-visible { outline-offset: -6px; border-radius: 16px; }
.sw-sheet-grab::before {
  content: ""; position: absolute; left: 50%; top: 14px; transform: translateX(-50%);
  width: 44px; height: 5px; border-radius: var(--sw-r-pill); background: var(--sw-n200);
}
.sw-sheet-account {
  display: flex; align-items: center; gap: 12px; min-width: 0;
  padding: 0 12px 14px; border-bottom: 1px solid var(--sw-n100);
}
.sw-sheet-nav .sw-nav-label { padding-top: 12px; }
.sw-sheet-foot { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--sw-n100); }
.sw-sheet-foot .sw-menu-item { padding-inline: 12px; border-radius: var(--sw-r-pill); }

/* ---------- Main content ---------- */
.sw-main { flex: 1; padding: 32px var(--sw-gutter) 56px; min-width: 0; width: 100%; max-width: calc(1440px + 2 * var(--sw-gutter)); margin-inline: auto; }
.sw-main:focus { outline: none; }
html { scroll-padding-top: 80px; }
@media (max-width: 1023px) { html { scroll-padding-top: 72px; scroll-padding-bottom: calc(58px + env(safe-area-inset-bottom, 0px) + 8px); } }

/* Page head: Title 2 + one line + actions. No eyebrow above the title.
   A long lead wraps beside the actions instead of pushing them below
   (the live My VPN & Antivirus lead is 130 characters). */
.sw-pagehead {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 16px 24px;
  flex-wrap: wrap; margin-bottom: 24px;
}
.sw-pagehead > div:first-child { flex: 1 1 440px; min-width: 0; }
.sw-pagehead h1 { font-size: 32px; line-height: 1.3; }
.sw-pagehead p { margin-top: 4px; font-size: 16px; text-wrap: pretty; }
.sw-pagehead .sw-hint { font-size: 13px; line-height: 1.45; }
.sw-pagehead-actions { display: flex; gap: 12px; flex-wrap: wrap; }

/* =========================================================
   Cards
   ========================================================= */
.sw-card { background: #fff; border-radius: var(--sw-r-card); padding: 28px; min-width: 0; }
.sw-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px 16px; flex-wrap: wrap; margin-bottom: 20px; }
.sw-card-title { font-size: 24px; line-height: 1.3; }
.sw-card-meta { margin-top: 2px; font-size: 14px; color: var(--sw-body); }

/* Metric card: DS card anatomy — icon tile, label, figure, foot. The label
   gets the full card width, so four cards fit in a row at 1280 without the
   labels breaking (a tile beside the label squeezed them to two lines). */
.sw-metric { display: flex; flex-direction: column; }
.sw-metric > .sw-tile { margin-bottom: 16px; }
.sw-metric-label { font-size: 14px; font-weight: 500; line-height: 1.5; color: var(--sw-body); text-wrap: balance; }
.sw-metric-value { margin-top: 2px; font-size: 32px; font-weight: 700; line-height: 1.2; color: var(--sw-ink); }
.sw-metric-foot { display: flex; justify-content: space-between; align-items: center; gap: 4px 12px; flex-wrap: wrap; font-size: 13px; color: var(--sw-body); margin-top: auto; padding-top: 12px; }
.sw-metric-foot b { font-weight: 600; color: var(--sw-ink); }
.sw-metric.is-alert .sw-metric-value { color: var(--sw-error); }
.sw-metric-link { margin-top: 4px; margin-bottom: -10px; }

/* Icon tile (eSIM-App/build/app.css .sa-tile) */
.sw-tile {
  display: grid; place-items: center; width: 44px; height: 44px; flex: none;
  border-radius: 14px; background: var(--sw-blue-tint); color: var(--sw-blue);
}
.sw-tile .sw-ic { width: 22px; height: 22px; }
.sw-tile .sw-flag { font-size: 20px; line-height: 1; }
.sw-tile-alert { background: var(--sw-error-tint); color: var(--sw-error); }
.sw-tile-quiet { background: var(--sw-n50); color: var(--sw-body); }
/* 40px tile for list rows and dialog subjects */
.sw-tile-sm { width: 40px; height: 40px; border-radius: 12px; }
.sw-tile-sm .sw-ic { width: 20px; height: 20px; }

/* The brand moment: wallet balance on the brand gradient (DS §5 blue
   banner panel, scaled down). White text, white pill, DS concentric rings. */
.sw-wallet {
  position: relative; overflow: hidden; isolation: isolate;
  background: linear-gradient(135deg, var(--sw-blue) 0%, var(--sw-blue-600) 100%);
  color: #fff;
}
.sw-wallet::before, .sw-wallet::after {
  content: ""; position: absolute; z-index: -1; border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, .12); pointer-events: none;
}
.sw-wallet::before { width: 260px; height: 260px; right: -90px; bottom: -150px; }
.sw-wallet::after  { width: 400px; height: 400px; right: -160px; bottom: -220px; }
.sw-wallet .sw-metric-label { color: rgba(255, 255, 255, .94); }
.sw-wallet .sw-metric-value { color: #fff; font-size: 44px; line-height: 1.15; }
.sw-wallet .sw-metric-foot { color: rgba(255, 255, 255, .94); align-items: center; }
.sw-wallet .sw-metric-foot b { color: #fff; }
.sw-wallet .sw-tile { background: rgba(255, 255, 255, .16); color: #fff; }

/* =========================================================
   Dashboard layout
   ========================================================= */
.sw-dash { display: grid; gap: 16px; }
.sw-metrics { display: grid; grid-template-columns: 1.35fr repeat(3, minmax(0, 1fr)); gap: 16px; }
.sw-dash-row { display: grid; grid-template-columns: minmax(0, 1.75fr) minmax(0, 1fr); gap: 16px; }

/* ---------- 14-day spend: single-series column chart ----------
   Columns <= 24px with a 4px rounded cap and a square foot on the baseline,
   hairline grid, one direct label on the peak, hover readout per column,
   and a screen-reader table carrying every value. */
.sw-chart { position: relative; display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: 12px; }
.sw-chart-y { display: flex; flex-direction: column; justify-content: space-between; height: 218px; margin-top: -9px; margin-bottom: -9px; }
.sw-chart-y span { font-size: 12px; line-height: 18px; color: var(--sw-body); text-align: right; font-variant-numeric: tabular-nums; }
.sw-chart-plot {
  position: relative; height: 200px;
  background:
    linear-gradient(var(--sw-n100), var(--sw-n100)) 0 0 / 100% 1px no-repeat,
    linear-gradient(var(--sw-n100), var(--sw-n100)) 0 50% / 100% 1px no-repeat;
  border-bottom: 1px solid var(--sw-n200);
}
.sw-chart-cols { position: absolute; inset: 0; display: grid; grid-template-columns: repeat(14, minmax(0, 1fr)); }
.sw-col { position: relative; display: flex; justify-content: center; align-items: flex-end; height: 100%; }
.sw-col-bar {
  display: block; width: min(24px, 64%); height: calc(var(--v, 0) * 100%);
  background: var(--sw-blue); border-radius: 4px 4px 0 0;
  transition: background-color .15s;
}
.sw-col:hover .sw-col-bar { background: var(--sw-blue-600); }
.sw-col-peak {
  position: absolute; bottom: calc(var(--v, 0) * 100% + 6px); left: 50%; transform: translateX(-50%);
  font-size: 12px; font-weight: 600; color: var(--sw-ink); white-space: nowrap; font-variant-numeric: tabular-nums;
}
.sw-col-tip {
  position: absolute; bottom: calc(var(--v, 0) * 100% + 30px); left: 50%; z-index: 5;
  transform: translate(-50%, 4px); opacity: 0; pointer-events: none;
  padding: 8px 12px; border-radius: 12px; background: var(--sw-ink); color: #fff;
  font-size: 12px; line-height: 1.4; white-space: nowrap; text-align: center;
  transition: opacity .15s, transform .15s;
}
.sw-col-tip b { display: block; font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums; }
.sw-col:hover .sw-col-tip { opacity: 1; transform: translate(-50%, 0); }
.sw-col:first-child .sw-col-tip { left: 0; transform: translate(0, 4px); }
.sw-col:first-child:hover .sw-col-tip { transform: none; }
.sw-col:last-child .sw-col-tip { left: auto; right: 0; transform: translate(0, 4px); }
.sw-col:last-child:hover .sw-col-tip { transform: none; }
.sw-chart-x { grid-column: 2; display: grid; grid-template-columns: repeat(14, minmax(0, 1fr)); margin-top: 8px; }
.sw-chart-x span { font-size: 12px; color: var(--sw-body); text-align: center; }
.sw-chart-empty {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-size: 14px; color: var(--sw-body);
}
.sw-chart-total { text-align: right; }
.sw-chart-total b { display: block; font-size: 24px; font-weight: 700; line-height: 1.3; color: var(--sw-ink); font-variant-numeric: tabular-nums; }
.sw-chart-total span { font-size: 14px; color: var(--sw-body); }
.sw-card-foot {
  display: flex; justify-content: space-between; gap: 12px;
  margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--sw-n100);
  font-size: 14px; color: var(--sw-body);
}
.sw-card-foot b { color: var(--sw-ink); font-weight: 600; font-variant-numeric: tabular-nums; }

/* ---------- Get started: new account only (dashboard, ?state=empty) ----------
   Live since 21 Sep: shown while the account has no orders. Live copy; the
   uppercase "Get started" eyebrow is dropped and "Choose a plan → Add funds →
   Review and place your order." becomes a numbered row. The number follows
   the solid blue tile with a white bold figure of our reseller landing
   (.sw-step-num) and the eSIM pages (.se-step-num), at the portal's 40 px
   list-row size (.sw-tile-sm). Steps sit on n50 inside the white card (no
   white on white). Measured on the card: a row of three from 680 px, a
   column below that (tablets, the 1024 px window with the sidebar, phones). */
.sw-start { container: sw-start / inline-size; margin-bottom: 32px; }
.sw-start-steps { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin-top: 16px; }
.sw-start-steps li {
  display: flex; align-items: center; gap: 14px; min-width: 0;
  padding: 14px 16px; border-radius: var(--sw-r-inner); background: var(--sw-n50);
  font-size: 16px; font-weight: 600; line-height: 1.4; color: var(--sw-ink);
}
.sw-start-num {
  display: grid; place-items: center; width: 40px; height: 40px; flex: none;
  border-radius: 12px; background: var(--sw-blue); color: #fff;
  font-size: 16px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums;
}
.sw-start-lead { max-width: 80ch; margin-top: 16px; font-size: 16px; line-height: 1.6; }
.sw-start-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 24px; margin-top: 24px; }
.sw-start-actions { display: flex; flex-wrap: wrap; gap: 12px; }
.sw-start-help { font-size: 14px; line-height: 1.6; }
/* Inline link in a sentence: exempt from the 44 px target; underlined */
.sw-start-help a { font-weight: 600; color: var(--sw-blue); text-decoration: underline; text-underline-offset: 3px; white-space: nowrap; }
.sw-start-help a:hover { color: var(--sw-blue-600); }

@container sw-start (max-width: 679px) {
  .sw-start-steps { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  .sw-start-steps li { padding: 10px 14px 10px 10px; }
}
@media (max-width: 720px) {
  .sw-start { margin-bottom: 24px; }
  .sw-start-lead { font-size: 15px; }
  .sw-start-foot { margin-top: 20px; }
  .sw-start-actions { flex-direction: column; width: 100%; }
  .sw-start-actions .sw-btn { width: 100%; }
}

/* ---------- Meter: a share or usage bar (eSIM-App/build/app.css .sa-bar)
   Top destinations share, eSIM data left. Set --v (0..1) on the meter or on
   its <i>. Red only for the "20% or less" state, and only on white (DS §2). */
.sw-meter { display: block; height: 6px; border-radius: var(--sw-r-pill); background: var(--sw-n100); overflow: hidden; }
.sw-meter i { display: block; height: 100%; width: calc(var(--v, 0) * 100%); background: var(--sw-blue); border-radius: inherit; }
.sw-meter.is-low i { background: var(--sw-error); }

/* ---------- Top destinations: ranked list with share meters ---------- */
.sw-rank { display: grid; gap: 16px; }
.sw-rank li { display: grid; grid-template-columns: 28px minmax(0, 1fr) auto; column-gap: 12px; row-gap: 6px; align-items: center; }
.sw-flag { font-size: 20px; line-height: 1; text-align: center; }
.sw-rank-name { font-size: 14px; font-weight: 600; color: var(--sw-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sw-rank-count { font-size: 13px; color: var(--sw-body); font-variant-numeric: tabular-nums; }
.sw-rank .sw-meter { grid-column: 2 / -1; }

/* =========================================================
   Lists (My eSIMs, My VPN & Antivirus, Orders)
   ========================================================= */
/* Result line above a list: "58 eSIMs", "4 eSIMs have 20% data or less" */
.sw-result { margin-top: 24px; font-size: 14px; color: var(--sw-body); }
.sw-result b { margin-right: 2px; font-size: 16px; font-weight: 700; color: var(--sw-ink); font-variant-numeric: tabular-nums; }
.sw-result + .sw-table-host { margin-top: 8px; }

/* Item cell: 40px tile (flag or product icon), name, one quiet sub-line */
.sw-item { display: flex; align-items: center; gap: 12px; min-width: 0; }
.sw-item-text { min-width: 0; }
.sw-item-name { font-size: 14px; font-weight: 600; line-height: 1.4; color: var(--sw-ink); }
.sw-item-sub {
  display: flex; flex-wrap: wrap; gap: 0 12px; margin-top: 2px;
  font-size: 13px; line-height: 1.5; color: var(--sw-body); font-variant-numeric: tabular-nums;
}

/* Row actions: one visible action + a "More" menu */
.sw-rowactions { display: inline-flex; align-items: center; justify-content: flex-end; gap: 4px; }
.sw-rowactions .sw-menu { min-width: 232px; }

/* Quiet explanatory line under a list (live copy) */
.sw-list-note {
  display: flex; align-items: flex-start; gap: 10px;
  margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--sw-n100);
  font-size: 14px;
}
.sw-list-note .sw-ic { width: 20px; height: 20px; color: var(--sw-body); margin-top: 1px; }

/* =========================================================
   Table — new pattern (no <table> in any earlier Stellar build).
   Sentence-case header 13/500 body grey, hairline rows, numbers
   right-aligned and tabular.
   ========================================================= */
/* The element a table measures itself against (a card, or the list body
   inside it). Rows stack by the width the table actually gets, not by the
   window: with or without the sidebar, the same table stacks at the same
   width. */
.sw-table-host { container: sw-table / inline-size; }
.sw-table-wrap { margin-inline: -12px; }
.sw-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.sw-table th {
  padding: 10px 12px; text-align: left; white-space: nowrap;
  font-size: 13px; font-weight: 500; color: var(--sw-body); letter-spacing: 0;
  border-bottom: 1px solid var(--sw-n100);
}
.sw-table td { padding: 14px 12px; border-bottom: 1px solid var(--sw-n100); color: var(--sw-ink); vertical-align: middle; }
/* The last VISIBLE row ends the table without a hairline (rows of later
   pages or other filters sit hidden after it in the review build) */
.sw-table tbody tr:not(:has(~ tr:not([hidden]))) td { border-bottom: 0; }
.sw-table tbody tr:hover td { background: var(--sw-n50); }
.sw-table tbody tr:hover td:first-child { border-radius: 12px 0 0 12px; }
.sw-table tbody tr:hover td:last-child { border-radius: 0 12px 12px 0; }
.sw-table .is-num { text-align: right; font-variant-numeric: tabular-nums; }
.sw-table .is-muted { color: var(--sw-body); white-space: nowrap; }
.sw-table .sw-order-id { font-weight: 600; font-variant-numeric: tabular-nums; }
.sw-table .sw-order-id a:hover { color: var(--sw-blue); text-decoration: underline; text-underline-offset: 3px; }
/* Order number (live format: W + date + time + 6 letters, 19 characters),
   always a link to its order page. One line; where a column is narrower
   than the number (a page sets max-width), it ends in an ellipsis as live
   does ("W2609211713…"). The full number stays the link text, so it is the
   accessible name, and is repeated in title for a pointer. */
.sw-order-link {
  display: inline-block; max-width: 100%; overflow: hidden; vertical-align: bottom;
  text-overflow: ellipsis; white-space: nowrap; font-variant-numeric: tabular-nums;
}
.sw-table .sw-plan { font-weight: 500; }
.sw-table .sw-created { white-space: nowrap; }
.sw-table .sw-actions { width: 1%; text-align: right; white-space: nowrap; }
.sw-table-empty td { padding: 0; border: 0; }
.sw-table tbody tr.sw-table-empty:hover td { background: none; }

/* ---------- Stacked rows ----------
   Each table names the width it needs to stay a table:
     .sw-stack-760  Dashboard, recent eSIM orders (6 columns; the 19-character
                    live order number needs the room), Orders (7 columns)
     .sw-stack-880  My eSIMs, My VPN & Antivirus, Billing ledger
   Below it the header is hidden (still read out) and every row becomes a
   small grid. The mechanics below are the same for every tier; the areas a
   row stacks into are set per table, next to the table (dashboard below,
   manage.css, billing.css). An empty-state row stays hidden while [hidden]. */
@container sw-table (max-width: 759px) {
  .sw-stack-760 thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .sw-stack-760, .sw-stack-760 tbody { display: block; }
  .sw-stack-760 tbody tr { display: grid; column-gap: 12px; row-gap: 6px; align-items: center; padding: 14px 0; border-bottom: 1px solid var(--sw-n100); }
  .sw-stack-760 tbody tr:not(:has(~ tr:not([hidden]))) { border-bottom: 0; }
  .sw-stack-760 tbody tr:hover td { background: none; }
  .sw-stack-760 td { padding: 0; border: 0; font-size: 13px; }
  .sw-stack-760 tbody tr.sw-table-empty { display: block; padding: 0; border: 0; }
  .sw-stack-760 .sw-table-empty td { display: block; }
  .sw-table-wrap:has(> .sw-stack-760) { margin-inline: 0; }
}
@container sw-table (max-width: 879px) {
  .sw-stack-880 thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .sw-stack-880, .sw-stack-880 tbody { display: block; }
  .sw-stack-880 tbody tr { display: grid; column-gap: 12px; row-gap: 6px; align-items: center; padding: 14px 0; border-bottom: 1px solid var(--sw-n100); }
  .sw-stack-880 tbody tr:not(:has(~ tr:not([hidden]))) { border-bottom: 0; }
  .sw-stack-880 tbody tr:hover td { background: none; }
  .sw-stack-880 td { padding: 0; border: 0; font-size: 13px; }
  .sw-stack-880 tbody tr.sw-table-empty { display: block; padding: 0; border: 0; }
  .sw-stack-880 .sw-table-empty td { display: block; }
  .sw-table-wrap:has(> .sw-stack-880) { margin-inline: 0; }
}

/* Dashboard, recent eSIM orders: plan + status / order, qty, date, amount.
   Stacked, the order number ends in an ellipsis (full in title) */
@container sw-table (max-width: 759px) {
  .sw-table-recent .sw-order-link { max-width: 100%; }
  .sw-table-recent tbody tr { grid-template-columns: auto minmax(0, 1fr) auto; grid-template-areas: "plan plan status" "order order amount" "qty created created"; }
  .sw-table-recent td.sw-plan { grid-area: plan; font-size: 14px; font-weight: 600; }
  .sw-table-recent td.sw-order-id { grid-area: order; }
  .sw-table-recent td.sw-qty { grid-area: qty; text-align: left; color: var(--sw-body); }
  .sw-table-recent td.sw-qty::before { content: "Qty "; }
  .sw-table-recent td.sw-amount { grid-area: amount; font-size: 14px; font-weight: 600; }
  .sw-table-recent td.sw-status { grid-area: status; justify-self: end; }
  .sw-table-recent td.sw-created { grid-area: created; }
}

/* ---------- List foot: "Showing 1–15 of 61" + numbered pager ----------
   Its hairline closes the table. 44px pills, current = brand blue (as the
   segmented control); off-range steps grey. Laravel renders it (?page=). */
.sw-listfoot {
  display: flex; align-items: center; justify-content: space-between; gap: 12px 16px; flex-wrap: wrap;
  padding-top: 16px; border-top: 1px solid var(--sw-n100);
  font-size: 14px; color: var(--sw-body);
}
.sw-listfoot p { font-variant-numeric: tabular-nums; }
.sw-listfoot p b { font-weight: 600; color: var(--sw-ink); }
.sw-pager { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.sw-pager-link {
  display: inline-grid; place-items: center; min-width: 44px; height: 44px; padding: 0 8px;
  border-radius: var(--sw-r-pill); font-size: 14px; font-weight: 600; color: var(--sw-ink);
  font-variant-numeric: tabular-nums; transition: background-color .15s, color .15s;
}
a.sw-pager-link:hover { background: var(--sw-n50); }
.sw-pager-link[aria-current="page"] { background: var(--sw-blue); color: #fff; }
.sw-pager-link[aria-disabled="true"] { color: var(--sw-n200); pointer-events: none; }
.sw-pager-link .sw-ic { width: 20px; height: 20px; }
.sw-pager-gap { min-width: 24px; text-align: center; color: var(--sw-body); }

/* =========================================================
   Empty state (live copy; eSIM-App/build/app.css .sa-empty)
   ========================================================= */
.sw-empty {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 32px 16px; text-align: center;
}
.sw-empty .sw-tile { margin-bottom: 8px; }
.sw-empty h3 { font-size: 16px; font-weight: 600; line-height: 1.4; }
.sw-empty p { font-size: 14px; max-width: 34ch; }
.sw-empty .sw-btn { margin-top: 12px; }

/* =========================================================
   Dialog — native <dialog> + showModal(), as the eSIM pages'
   .se-modal (Website/eSIM-Redesign/build/styles.css): top layer, the
   page behind inert, Escape closes. main.js (SW.dialog) adds the Tab
   wrap, backdrop tap, [data-sw-dialog-close] and focus return. 520px;
   from 720px down the same element is a bottom sheet with the grab
   handle (the X gives way to the handle). One dialog for purchase
   confirmation, renewals and every row confirmation.
   ========================================================= */
dialog.sw-dialog {
  width: min(520px, calc(100% - 32px)); max-width: none;
  max-height: calc(100vh - 48px); max-height: calc(100dvh - 48px);
  margin: auto; padding: 0; border: 0; overflow-y: auto; overscroll-behavior: contain;
  border-radius: var(--sw-r-card); background: #fff; color: var(--sw-ink);
}
dialog.sw-dialog::backdrop { background: rgba(11, 12, 25, .45); }
dialog.sw-dialog[open] { animation: sw-sheet-up .22s cubic-bezier(.2, .8, .3, 1); }
.sw-dialog .sw-sheet-grab { display: none; }
.sw-dialog-body { display: grid; gap: 16px; padding: 28px; }
.sw-dialog-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.sw-dialog h2 { font-size: 24px; line-height: 1.3; }
.sw-dialog-head p { margin-top: 4px; font-size: 14px; }
.sw-dialog-x { margin: -6px -10px 0 0; color: var(--sw-body); }
.sw-dialog-x .sw-ic { width: 22px; height: 22px; }
.sw-dialog-body > p { font-size: 16px; line-height: 1.5; }
.sw-dialog-body > p b { color: var(--sw-ink); font-weight: 600; }
/* What the action applies to: the row it came from */
.sw-dialog-subject {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; border-radius: var(--sw-r-inner); background: var(--sw-n50);
}
.sw-dialog-subject .sw-tile { background: #fff; }
.sw-dialog-subject p { display: grid; font-size: 13px; line-height: 1.45; font-variant-numeric: tabular-nums; }
.sw-dialog-subject b { font-size: 14px; font-weight: 600; color: var(--sw-ink); }
.sw-dialog-actions { display: flex; justify-content: flex-end; gap: 12px; flex-wrap: wrap; margin-top: 8px; }

/* ---------- Large dialog (.sw-dialog-lg): plan details, eSIM details, top-up ----------
   The same native <dialog> and SW.dialog, 960 px wide, in three parts:
   a fixed head (.sw-dialog-top), a body that scrolls on its own
   (.sw-dialog-scroll; soft background, so white cards sit on it, DS §2)
   and a foot that stays in view with the primary action (.sw-dialog-foot).
   From 720 px down: a full-height bottom sheet with the grab handle.
   Additive: the 520 px dialog above is unchanged. */
dialog.sw-dialog.sw-dialog-lg { width: min(960px, calc(100% - 48px)); overflow: hidden; }
dialog.sw-dialog.sw-dialog-lg[open] { display: flex; flex-direction: column; }
.sw-dialog-top {
  flex: none; display: flex; align-items: flex-start; gap: 14px;
  padding: 24px 24px 20px 28px; border-bottom: 1px solid var(--sw-n100);
}
.sw-dialog-top > .sw-dialog-x { margin: -4px -4px 0 auto; }
.sw-dialog-scroll {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  display: grid; align-content: start; gap: 16px;
  padding: 24px 28px 28px; background: var(--sw-n50);
}
.sw-dialog-foot {
  flex: none; display: flex; align-items: center; justify-content: space-between; gap: 12px 16px;
  padding: 16px 28px; border-top: 1px solid var(--sw-n100); background: #fff;
}
/* A form around the three parts (eSIM top-up) keeps them in the column */
.sw-dialog-lg > form:not(.sw-dialog-foot) { display: contents; } /* a foot that is itself a form (plan details) keeps its box */
/* Medium width: a form-sized large dialog (eSIM top-up): 600 px */
dialog.sw-dialog.sw-dialog-lg.sw-dialog-md { width: min(600px, calc(100% - 48px)); }

/* Content inside the large dialog's soft body (eSIM details, eSIM top-up).
   White cards on n50 (DS §2); the same values as the plan details cards
   (sell.css .sell-pd-card, -terms, -fact), which predate these.
     .sw-dcard   a white card, radius 20; h3 = its 16/600 title
     .sw-dcols   two cards side by side, one column below 900 px
     .sw-terms   label left, value right, hairlines between (a <dl>)
     .sw-facts   small figures in a row (a <dl> of .sw-fact) */
.sw-dcard { min-width: 0; padding: 20px 22px; border-radius: 20px; background: #fff; }
.sw-dcard h3 { margin-bottom: 12px; font-size: 16px; font-weight: 600; line-height: 1.4; }
.sw-dcols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; align-items: stretch; }
.sw-terms { display: grid; margin: 0; }
.sw-terms > div { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; padding: 10px 0; border-bottom: 1px solid var(--sw-n100); }
.sw-terms > div:first-child { padding-top: 0; }
.sw-terms > div:last-child { border-bottom: 0; padding-bottom: 0; }
.sw-terms dt { flex: none; font-size: 14px; line-height: 1.5; color: var(--sw-body); }
.sw-terms dd { min-width: 0; margin: 0; font-size: 14px; font-weight: 600; line-height: 1.5; color: var(--sw-ink); text-align: right; overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }
.sw-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 8px; margin: 0; }
.sw-fact { display: grid; align-content: start; gap: 2px; padding: 12px 14px; border-radius: 14px; background: var(--sw-n50); }
.sw-fact dt { font-size: 13px; font-weight: 500; line-height: 1.4; color: var(--sw-body); }
.sw-fact dd { margin: 0; font-size: 14px; font-weight: 600; line-height: 1.4; color: var(--sw-ink); font-variant-numeric: tabular-nums; }
@media (max-width: 900px) {
  .sw-dcols { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 720px) {
  dialog.sw-dialog.sw-dialog-lg {
    width: 100%; max-width: 100%; margin: auto 0 0;
    height: calc(100vh - 16px); height: calc(100dvh - 16px);
    max-height: calc(100vh - 16px); max-height: calc(100dvh - 16px);
  }
  .sw-dialog-top { flex-wrap: wrap; gap: 12px; padding: 0 16px 16px; }
  .sw-dialog-top > .sw-sheet-grab { flex: 0 0 88px; margin: 0 calc(50% - 44px) -8px; }
  .sw-dialog-scroll { gap: 12px; padding: 16px 16px 20px; }
  .sw-dialog-foot { gap: 12px; padding: 12px 16px calc(12px + var(--sw-safe-b)); }
  /* The medium dialog is full width too, and as tall as its content, up to
     the full-height sheet */
  dialog.sw-dialog.sw-dialog-lg.sw-dialog-md { width: 100%; height: auto; }
  .sw-dcard { padding: 18px 16px; border-radius: 16px; }
  .sw-terms > div { flex-wrap: wrap; gap: 2px 16px; }
  .sw-terms dd { text-align: left; }
}

/* =========================================================
   Auth: form on white + blue brand panel (desktop), compact
   blue header above the form (mobile). Continuous with the
   reseller landing hero.
   ========================================================= */
body.sw-auth-page { background: #fff; }
.sw-auth {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  min-height: 100vh; padding: 16px;
}
.sw-auth-col { display: flex; flex-direction: column; padding: 24px clamp(24px, 5vw, 72px) 32px; min-width: 0; }
.sw-auth-top { display: flex; align-items: center; gap: 8px; }
.sw-auth-top .sw-brand img { height: 28px; }
.sw-auth-body { width: 100%; max-width: 420px; margin: auto; padding-block: 40px; }
.sw-auth-body h1 { font-size: 32px; line-height: 1.3; }
.sw-auth-lead { margin-top: 8px; font-size: 16px; }
.sw-auth-body .sw-form { margin-top: 28px; }
.sw-auth-row { display: flex; align-items: center; justify-content: space-between; gap: 8px 16px; flex-wrap: wrap; margin-top: -8px; }
.sw-auth-link { display: inline-flex; align-items: center; min-height: 44px; font-size: 14px; font-weight: 600; color: var(--sw-blue); }
.sw-auth-link:hover { color: var(--sw-blue-600); text-decoration: underline; text-underline-offset: 3px; }
.sw-auth-alt { margin-top: 20px; font-size: 14px; color: var(--sw-body); }
.sw-auth-alt a { font-weight: 600; color: var(--sw-blue); }
.sw-auth-alt a:hover { text-decoration: underline; text-underline-offset: 3px; }
.sw-auth-back { display: inline-flex; align-items: center; gap: 8px; }
.sw-auth-back .sw-ic { width: 18px; height: 18px; }

.sw-auth-panel {
  /* clip, not hidden: hidden would make the panel the scroll container and
     the sticky inner block would stop pinning to the viewport */
  position: relative; overflow: clip; isolation: isolate;
  border-radius: var(--sw-r-panel);
  background: linear-gradient(150deg, var(--sw-blue) 0%, var(--sw-blue-600) 100%);
  color: #fff;
}
/* DS hero decor: concentric rings, bottom-aligned (landing .sw-hero) */
.sw-auth-panel::before, .sw-auth-panel::after {
  content: ""; position: absolute; z-index: -1; left: 50%; border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, .1); pointer-events: none; transform: translateX(-50%);
}
.sw-auth-panel::before { width: 760px; height: 760px; bottom: -470px; }
.sw-auth-panel::after  { width: 1100px; height: 1100px; bottom: -680px; }
.sw-auth-panel-inner {
  position: sticky; top: 16px;
  display: flex; flex-direction: column; justify-content: center;
  min-height: calc(100vh - 32px); padding: 56px clamp(32px, 5vw, 72px);
}
.sw-auth-panel-mobile { display: none; }
.sw-auth-panel-inner > .sw-tag { align-self: flex-start; }
.sw-auth-panel h2 { color: #fff; font-size: 44px; line-height: 1.2; max-width: 18ch; margin-top: 20px; }
.sw-auth-panel p { color: rgba(255, 255, 255, .94); font-size: 16px; line-height: 1.6; max-width: 40ch; margin-top: 16px; }
.sw-auth-points { display: grid; gap: 14px; margin-top: 28px; }
.sw-auth-points li { display: flex; align-items: center; gap: 12px; font-size: 16px; color: rgba(255, 255, 255, .95); }
.sw-auth-points .sw-ic { width: 22px; height: 22px; }

/* =========================================================
   Review notes (review build only: delete with them; README, "Before integrating")
   when it is a line of its own, this one class, so the notes look the same on
   every page: the quiet hint type (13 px, body grey), on their own line. Where
   a note sits (margins, alignment, width) stays with its page class. A note
   inside a notice or a flash takes the notice's type instead.
   (Vlad, 7 Oct 2026: they were five different looks.)
   ========================================================= */

/* =========================================================
   Review index (index.html only — not a portal page, not shipped)
   ========================================================= */
.sw-review { max-width: 960px; margin: 0 auto; padding: 48px 24px 80px; }
.sw-review-intro { margin-top: 8px; }
.sw-review h2 { font-size: 24px; line-height: 1.3; margin: 40px 0 16px; }
.sw-review-list { display: grid; gap: 12px; }
.sw-review-screen { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px; padding: 18px 24px; }
.sw-review-screen b { display: block; font-size: 16px; font-weight: 600; }
.sw-review-screen span { display: block; font-size: 14px; color: var(--sw-body); }
.sw-review-links { display: flex; flex-wrap: wrap; gap: 0 16px; }
.sw-specimen { display: grid; gap: 24px; }
.sw-specimen-row { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.sw-specimen h3 { font-size: 16px; font-weight: 600; margin-bottom: 12px; }
.sw-specimen .sw-form { max-width: 420px; }
.sw-specimen-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }

/* =========================================================
   Responsive
   ========================================================= */
@media (max-width: 1280px) {
  .sw-portal { --sw-gutter: 32px; }
}
@media (max-width: 1180px) {
  .sw-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .sw-filterbar-select { flex-basis: 210px; }
}

/* Below 1024 px: no sidebar; the bottom tab bar and the More sheet carry
   the navigation, the top bar shows the logo */
@media (max-width: 1023px) {
  .sw-app {
    display: block;
    /* room for the fixed tab bar, as body.sa-app in the app. A sticky action
       bar sits at bottom: calc(var(--sw-tabbar-h) + var(--sw-safe-b)), as
       .sa-sticky does. */
    padding-bottom: calc(var(--sw-tabbar-h) + var(--sw-safe-b));
  }
  .sw-sidebar { display: none; }
  .sw-topbar-start { display: flex; }
  .sw-topbar-start .sw-brand img { height: 22px; }
  .sw-tabbar {
    position: fixed; inset: auto 0 0 0; z-index: 50;
    display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
    height: calc(var(--sw-tabbar-h) + var(--sw-safe-b));
    padding-bottom: var(--sw-safe-b);
    background: rgba(255, 255, 255, .94);
    -webkit-backdrop-filter: saturate(180%) blur(12px);
    backdrop-filter: saturate(180%) blur(12px);
    box-shadow: 0 -1px 0 var(--sw-n100);
  }
}
@media (min-width: 1024px) { .sw-sheet { display: none !important; } }

@media (max-width: 1180px) {
  .sw-dash-row { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 720px) {
  .sw-portal { --sw-gutter: 16px; }
  .sw-topbar { gap: 8px; min-height: 64px; padding-block: 10px; }
  .sw-topbar-end { gap: 8px; }
  .sw-topup-pill, .sw-account { display: none; }
  .sw-topup-round { display: inline-grid; background: var(--sw-blue); color: #fff; }
  .sw-topup-round:hover { background: var(--sw-blue-600); }
  .sw-main { padding-top: 24px; padding-bottom: 40px; }
  .sw-pagehead h1 { font-size: 26px; }
  .sw-pagehead-actions { width: 100%; }
  .sw-pagehead-actions .sw-btn { flex: 1; padding-inline: 16px; }
  .sw-metrics { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .sw-dash { gap: 12px; }
  .sw-card { padding: 20px; border-radius: 20px; }
  .sw-card-title { font-size: 20px; }
  .sw-wallet .sw-metric-value { font-size: 36px; }
  .sw-metric-value { font-size: 28px; }
  /* Phone: cards are full width, so the tile moves back beside label and
     figure instead of adding a row to each stacked card */
  .sw-metric { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 12px; align-content: start; }
  .sw-metric > .sw-tile { grid-column: 2; grid-row: 1 / span 2; margin: 0; align-self: start; }
  .sw-metric-label, .sw-metric-value { grid-column: 1; }
  .sw-metric-foot, .sw-metric-link { grid-column: 1 / -1; }
  .sw-chart-y, .sw-chart-plot { height: 160px; }
  .sw-chart-x span:nth-child(even) { visibility: hidden; }

  /* Filter row: free pills that wrap */
  .sw-filternav .sw-seg { flex-wrap: wrap; gap: 8px; padding: 0; background: none; overflow: visible; border-radius: 0; }
  .sw-filternav .sw-seg-item { background: #fff; padding: 10px 12px; }
  .sw-card .sw-filternav .sw-seg-item { background: var(--sw-n50); }
  .sw-filternav .sw-seg-item[aria-current="page"] { background: var(--sw-blue); }

  /* Search + filter bar: 16px text so iOS does not zoom into the field; the
     phone keyboard's Search key submits, so the arrow steps aside */
  .sw-filterbar .sw-input { font-size: 16px; }
  .sw-search .sw-input::placeholder { font-size: 15px; }
  .sw-filterbar-select { flex-basis: 100%; }
  .sw-search-go { display: none; }
  .sw-search:has(.sw-search-go) .sw-input { padding-right: 16px; }
  .sw-filterbar .sw-hint { padding-left: 16px; }

  .sw-result { margin-top: 20px; }
  .sw-daterange { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); width: 100%; }
  .sw-daterange .sw-input { width: 100%; min-width: 0; padding-inline: 14px 10px; }
  .sw-daterange .sw-btn { grid-column: 1 / -1; }

  .sw-listfoot { justify-content: center; text-align: center; }
  .sw-listfoot p { width: 100%; }
  .sw-pager .is-far { display: none; }

  /* Dialog: the same <dialog>, as a bottom sheet with the grab handle */
  dialog.sw-dialog {
    width: 100%; max-width: 100%; margin: auto 0 0;
    max-height: 92vh; max-height: 92dvh;
    border-radius: var(--sw-r-card) var(--sw-r-card) 0 0;
    animation-duration: .26s;
  }
  .sw-dialog-body { padding: 0 20px calc(20px + var(--sw-safe-b)); }
  .sw-dialog .sw-sheet-grab { display: block; margin-bottom: -8px; }
  .sw-dialog-x { display: none; }
  .sw-dialog h2 { font-size: 20px; }
  .sw-dialog-actions { flex-direction: column-reverse; }
  .sw-dialog-actions .sw-btn { width: 100%; }

  /* Auth: the brand panel collapses to a compact blue header */
  .sw-auth { display: flex; flex-direction: column; padding: 12px; }
  .sw-auth-panel { order: -1; border-radius: 32px; }
  .sw-auth-panel::before { width: 420px; height: 420px; bottom: -330px; }
  .sw-auth-panel::after  { width: 620px; height: 620px; bottom: -480px; }
  .sw-auth-panel-inner { display: none; }
  .sw-auth-panel-mobile { display: flex; flex-direction: column; align-items: flex-start; gap: 14px; padding: 22px 22px 24px; }
  .sw-auth-panel-mobile .sw-brandrow { display: flex; align-items: center; gap: 8px; }
  .sw-auth-panel-mobile .sw-brand img { height: 22px; }
  .sw-auth-panel-mobile p { margin: 0; font-size: 14px; font-weight: 500; color: rgba(255, 255, 255, .94); }
  .sw-auth-col { padding: 8px 8px 24px; }
  .sw-auth-top { display: none; }
  .sw-auth-body { padding-block: 24px 8px; margin: 0 auto; }
  .sw-auth-body h1 { font-size: 26px; }
  .sw-specimen-grid { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 380px) {
  .sw-topbar-start .sw-brand img { height: 20px; }
  .sw-balance-label { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .sw-portal *, .sw-portal *::before, .sw-portal *::after { transition: none !important; animation: none !important; }
}

/* ---------- Developer pages: identifiers and HTTP methods (round 2) ----------
   Shared by API keys, Request logs, Documentation and Webhooks, so it is
   defined once here. .sw-mono: base URL, scopes, endpoint paths, key
   prefixes, request IDs. .sw-method: tonal pill, mono caps; GET in brand
   tint, POST in success tint, DELETE in error tint; ink text on the green
   and red tints for AA (as status chips, §12). */
.sw-mono { font-family: var(--sw-mono); font-size: max(12px, .875em); }
.sw-method {
  display: inline-flex; align-items: center; justify-content: center; flex: none; min-width: calc(4ch + 20px);
  padding: 4px 10px; border-radius: var(--sw-r-pill);
  font-family: var(--sw-mono); font-size: 12px; font-weight: 700; line-height: 1.4; letter-spacing: 0;
}
.sw-method-get    { background: var(--sw-blue-tint); color: var(--sw-blue-600); }
.sw-method-post   { background: var(--sw-success-tint); color: var(--sw-ink); }
.sw-method-delete { background: var(--sw-error-tint); color: var(--sw-ink); }

/* ---------- Blue side panel with numbered points (round 2, 2 Oct) ----------
   The security notes beside a long create form (API keys, Webhooks). The DS
   blue banner scaled to a side card, the same family as the wallet card
   (.sw-wallet): radius 24, brand gradient, two concentric rings off the
   bottom-right corner (DS §5 motif), white text. Sticky on a desktop when the
   page sets it. Kristina's call 2 Oct: one blue moment per developer page. */
.sw-sidepanel {
  position: relative; overflow: hidden; isolation: isolate;
  padding: 28px; border-radius: var(--sw-r-card);
  background: linear-gradient(150deg, var(--sw-blue) 0%, var(--sw-blue-600) 100%);
  color: #fff;
}
.sw-sidepanel::before, .sw-sidepanel::after {
  content: ""; position: absolute; z-index: -1; border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, .12); pointer-events: none;
}
.sw-sidepanel::before { width: 300px; height: 300px; right: -120px; bottom: -170px; }
.sw-sidepanel::after  { width: 460px; height: 460px; right: -200px; bottom: -250px; }
.sw-sidepanel h2 { font-size: 24px; line-height: 1.3; color: #fff; }
.sw-sidepanel-points { display: grid; margin-top: 8px; }
.sw-sidepanel-points li { display: flex; align-items: flex-start; gap: 14px; padding: 16px 0; border-bottom: 1px solid rgba(255, 255, 255, .16); }
.sw-sidepanel-points li:last-child { border-bottom: 0; padding-bottom: 0; }
.sw-sidepanel-num {
  display: grid; place-items: center; width: 32px; height: 32px; flex: none;
  border-radius: 10px; background: rgba(255, 255, 255, .16);
  font-size: 14px; font-weight: 700; line-height: 1; color: #fff; font-variant-numeric: tabular-nums;
}
.sw-sidepanel-title { font-size: 15px; font-weight: 600; line-height: 1.45; color: #fff; }
.sw-sidepanel-points p:not(.sw-sidepanel-title) { margin-top: 2px; font-size: 14px; line-height: 1.5; color: rgba(255, 255, 255, .94); }
.sw-sidepanel .sw-tag { background: rgba(255, 255, 255, .16); color: #fff; }
@media (max-width: 599px) { .sw-sidepanel { padding: 22px 20px; border-radius: 20px; } .sw-sidepanel h2 { font-size: 20px; } }

/* ---------- Blue side panel: points with icons + an illustration (6 Oct) ----------
   Vlad's review: the four points are not steps, so they carry an icon tile
   instead of a number; and the panel gets an illustration in the house style
   (DS §5–§6: a device on the brand blue, a floating white chip). The device
   screen shows a real piece of OUR build (a row or a dialog from the same
   page), never an invented screen. Soft drop shadow only on the floating
   screen, as on hero chips (DS §4). */
.sw-sidepanel-ic {
  display: grid; place-items: center; width: 32px; height: 32px; flex: none;
  border-radius: 10px; background: rgba(255, 255, 255, .16); color: #fff;
}
.sw-sidepanel-ic .sw-ic { width: 18px; height: 18px; }
.sw-sidepanel-art { position: relative; margin: 4px 0 20px; }
.sw-device {
  position: relative; border-radius: 16px; padding: 10px;
  background: rgba(255, 255, 255, .14); border: 1.5px solid rgba(255, 255, 255, .24);
}
.sw-device-screen {
  border-radius: 10px; background: #fff; color: var(--sw-ink); overflow: hidden;
  box-shadow: 0 18px 40px rgba(11, 12, 25, .22);
  pointer-events: none; user-select: none;
}
.sw-device-bar { display: flex; gap: 5px; padding: 8px 10px; background: var(--sw-n50); }
.sw-device-bar i { width: 7px; height: 7px; border-radius: 50%; background: var(--sw-n200); }
.sw-device-body { padding: 12px; font-size: 12px; line-height: 1.45; }
/* tags inside the white device screen are ordinary tags, not the on-blue variant */
.sw-device-screen .sw-tag { background: var(--sw-blue-tint); color: var(--sw-blue-600); }
