/* Aerial panel — forge v5 bones × Aerial "signal" blood.
   From forge (research-driven, Linear×monday): the surface LADDER instead of
   boxes, ONE accent, tight negative-tracking headings, subtle top-edge
   highlights, vivid solid status pills readable in 3 seconds, friendly
   0.14s motion, components consume tokens only.
   From Aerial (lib/app.dart Brand): the near-black blue field #0A0D16, cyan
   #4FD8FF as THE accent, and the cyan→violet signal gradient reserved for
   signature moments — here, exactly one: the inventory bar. */

:root {
  --bg: #0a0d16;            /* the app icon field */
  --surface-1: #0f1320;
  --surface-2: #141a2b;
  --surface-3: #171c2b;
  --line: #20263a;
  --line-strong: #2c3450;
  --ink: #eaeef7;
  --muted: #8791a8;
  --soft: #5c657d;
  --brand: #4fd8ff;         /* Aerial cyan — the one accent */
  --brand-ink: #041016;     /* text on brand */
  --brand-hover: #7de2ff;
  --brand-soft: rgba(79, 216, 255, 0.13);
  --violet: #8b6bff;
  --grad-signal: linear-gradient(90deg, #4fd8ff 0%, #8b6bff 100%);
  --edge: inset 0 1px 0 rgba(255, 255, 255, 0.04);
  /* status pills — monday-vivid, via forge */
  --st-free: #579bfc;       /* libre */
  --st-assigned: #fdab3d;   /* entregada, aún sin activar */
  --st-active: #00c875;     /* en uso */
  --st-trial: #a25ddc;      /* prueba */
  --st-dead: #e2445c;       /* vencida / suspendida */
  --ok: #00c875;  --ok-bg: rgba(0, 200, 117, 0.14);
  --warn: #fdab3d; --warn-bg: rgba(253, 171, 61, 0.14);
  --bad: #e2445c;  --bad-bg: rgba(226, 68, 92, 0.14);
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.35);
  --shadow-md: 0 6px 20px rgba(0, 0, 0, 0.4);
  --shadow-lg: 0 24px 60px rgba(0, 0, 0, 0.55);
  color-scheme: dark;
}

* { box-sizing: border-box; }
html { -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--ink); font-size: 14px;
  font-family: "Inter", -apple-system, "Segoe UI", sans-serif;
  letter-spacing: -0.006em;
}

/* ---------- phone baseline (HIG pass) --------------------------------- */

/* No grey flash on tap, and no 300ms double-tap-zoom delay. */
a, button, [role="button"], label, select, summary, .seg span {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

/* Belt and braces — the real fix is always the offending element, never this. */
html, body { overflow-x: hidden; max-width: 100vw; }

button {
  font: inherit; font-size: 13px; cursor: pointer; border: 1px solid var(--line);
  background: var(--surface-2); border-radius: 8px; padding: 6px 13px;
  color: var(--ink); font-weight: 500;
  transition: background .14s ease, border-color .14s ease, color .14s ease, transform .14s ease;
}
button:hover { background: var(--surface-3); border-color: var(--line-strong); }
button:active { transform: scale(0.98); }
button.primary {
  background: var(--brand); color: var(--brand-ink); border-color: transparent;
  font-weight: 700; box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
}
button.primary:hover { background: var(--brand-hover); }
button.ghost { background: transparent; border-color: transparent; color: var(--muted); }
button.ghost:hover { color: var(--ink); background: rgba(255, 255, 255, 0.045); }
button.danger { color: var(--bad); }
button.danger:hover { background: var(--bad-bg); border-color: var(--bad); }

input, select {
  font: inherit; font-size: 13px; padding: 7px 11px; border: 1px solid var(--line);
  border-radius: 8px; background: var(--surface-2); color: var(--ink);
  transition: border-color .14s ease;
}
input::placeholder { color: var(--soft); }
input:focus, select:focus { outline: 3px solid var(--brand-soft); border-color: var(--brand); }

/* ---------- shell: sidebar + main (forge layout) */
.shell { display: flex; min-height: 100vh; }
.sidebar {
  width: 216px; flex: none; background: var(--bg); border-right: 1px solid var(--line);
  padding: 18px 12px; display: flex; flex-direction: column; gap: 4px;
  position: sticky; top: 0; height: 100vh;
}
.wordmark {
  display: flex; align-items: center; gap: 9px; padding: 4px 8px 16px;
  font-weight: 700; font-size: 15px; letter-spacing: -0.02em;
}
.wordmark .dot {
  width: 22px; height: 22px; border-radius: 7px; background: var(--grad-signal);
  box-shadow: 0 0 14px rgba(79, 216, 255, 0.4);
}
.nav-item {
  display: flex; align-items: center; gap: 9px; padding: 7px 10px;
  border-radius: 8px; color: var(--muted); font-weight: 500; font-size: 13px;
  cursor: pointer; border: none; background: none; width: 100%; text-align: left;
}
.nav-item:hover { color: var(--ink); background: rgba(255, 255, 255, 0.045); }
.nav-item.on { color: var(--ink); background: var(--surface-2); }
.sidebar .foot { margin-top: auto; font-size: 12px; color: var(--soft); padding: 8px 10px; }

.main { flex: 1; min-width: 0; padding: 26px 34px 60px; }
.page-head { display: flex; align-items: center; gap: 14px; margin-bottom: 18px; }
.page-head h1 {
  font-size: 21px; font-weight: 700; letter-spacing: -0.03em; margin: 0;
}
.page-head .spacer { flex: 1; }
.page-head input[type="search"] { width: 260px; }

/* ---------- stat cards (forge surface ladder) */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-bottom: 18px; }
.stat {
  background: var(--surface-1); border: 1px solid var(--line); border-radius: 12px;
  padding: 13px 16px; box-shadow: var(--shadow-sm), var(--edge);
}
.stat .n { font-size: 24px; font-weight: 700; letter-spacing: -0.03em; }
.stat .l { font-size: 12px; color: var(--muted); margin-top: 2px; }
.stat.accent .n { color: var(--brand); }
.stat.warn .n { color: var(--warn); }

/* THE signature moment — the one place the signal gradient appears. */
.inventory-bar {
  height: 8px; border-radius: 999px; background: var(--surface-3);
  overflow: hidden; margin: 4px 0 18px;
}
.inventory-bar .fill { height: 100%; background: var(--grad-signal); border-radius: 999px; transition: width .4s cubic-bezier(.2,.8,.25,1); }

/* ---------- table (forge list) */
.tablewrap {
  background: var(--surface-1); border: 1px solid var(--line); border-radius: 12px;
  overflow: auto; box-shadow: var(--shadow-sm), var(--edge);
}
/* A scroll container that isn't focusable cannot be scrolled by keyboard at
   all — WCAG 2.1.1, Level A. The region also needs a name, hence the
   attribute selector: styling only applies where both are present. */
.tablewrap[role="region"][tabindex]:focus-visible {
  outline: 3px solid var(--brand); outline-offset: 2px;
}
/* SC 2.4.11 — a focused row must never be entirely hidden behind the sticky
   top bar the phone layout uses. */
tbody tr, .stat, .seg, button, input, select { scroll-margin-block: 72px; }
table { width: 100%; border-collapse: separate; border-spacing: 0; }
th {
  text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--soft); font-weight: 600; padding: 10px 14px;
  border-bottom: 1px solid var(--line); white-space: nowrap;
}
td { padding: 10px 14px; border-bottom: 1px solid var(--line); font-size: 13px; white-space: nowrap; }
tr:last-child td { border-bottom: none; }
tbody tr { transition: background .14s ease; }
tbody tr:hover { background: var(--surface-2); }
td.mono, .mono { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 12.5px; }
td .note { color: var(--muted); max-width: 260px; overflow: hidden; text-overflow: ellipsis; display: inline-block; vertical-align: bottom; white-space: nowrap; }

/* Status pills — readable in 3 seconds, and legible.
   🚨 White-on-saturated FAILS 4.5:1: white on our blue measured 2.80:1, on
   violet 4.09:1, on red 4.03:1. Three of five pills were unreadable to anyone
   with reduced contrast sensitivity. Dark fill + bright text fixes it and
   suits a dark panel better anyway. Every ratio below is measured, not eyed.
   The pill's FILL does not need 3:1 against the page — these are static and
   carry a text label, so the label is what conveys the state (SC 1.4.1). */
.pill {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11px; font-weight: 700; border-radius: 999px;
  padding: 2px 9px; letter-spacing: 0.01em; white-space: nowrap;
}
.pill::before { font-size: 10px; line-height: 1; }
.pill.free     { background: #16263f; color: #78a9ff; }  /* 6.45:1 */
.pill.free::before     { content: "○"; }
.pill.assigned { background: #33290a; color: #f1c21b; }  /* 8.53:1 */
.pill.assigned::before { content: "◷"; }
.pill.active   { background: #0d2b18; color: #42be65; }  /* 6.39:1 */
.pill.active::before   { content: "✓"; }
.pill.trial    { background: #241a3d; color: #c3adff; }  /* 7.36:1 */
.pill.trial::before    { content: "◐"; }
.pill.dead     { background: #3d1418; color: #ff8389; }  /* 6.75:1 */
.pill.dead::before     { content: "⊗"; }
.chip {
  font-size: 11px; padding: 1px 8px; border-radius: 999px;
  background: var(--surface-2); color: var(--muted);
}

/* ---------- native <dialog>: the platform owns focus trap, ESC and restore */
.dlg {
  background: var(--surface-1); color: var(--ink);
  border: 1px solid var(--line); border-radius: 14px; padding: 0;
  width: min(500px, 94vw); box-shadow: var(--shadow-lg);
  animation: pop .16s cubic-bezier(.2, .8, .25, 1);
}
.dlg::backdrop { background: rgba(4, 6, 12, 0.62); backdrop-filter: blur(2px); }
/* <dialog> makes the page inert but does NOT stop it scrolling behind the
   modal — that part is still ours. */
html:has(dialog[open]) { overflow: hidden; }
@keyframes pop { from { transform: scale(.97); opacity: 0; } to { transform: scale(1); opacity: 1; } }
.dlgform header { padding: 15px 18px 13px; border-bottom: 1px solid var(--line); }
.dlgform header h2 { margin: 0; font-size: 16px; font-weight: 700; letter-spacing: -0.02em; }
.dlgform .body { padding: 16px 18px; display: flex; flex-direction: column; gap: 13px; }
.dlgform footer {
  padding: 12px 18px; border-top: 1px solid var(--line);
  display: flex; justify-content: flex-end; gap: 8px; flex-wrap: wrap;
}
.lede { margin: 0; color: var(--muted); font-size: 13px; line-height: 1.55; }
.lede strong { color: var(--ink); }
.pagelede { max-width: 68ch; margin: -4px 0 16px; }
.dim { color: var(--soft); }

.field { display: flex; flex-direction: column; gap: 5px; }
.field label { font-size: 12px; color: var(--muted); font-weight: 600; }
.field .row { display: flex; gap: 8px; }
.field .row input { flex: 1; }
.field input, .field select { width: 100%; }
.hint { font-size: 11.5px; color: var(--soft); line-height: 1.45; }
.warnbox {
  background: var(--warn-bg); border: 1px solid rgba(253, 171, 61, .35);
  color: #ffd8a0; border-radius: 9px; padding: 9px 12px; font-size: 12.5px; line-height: 1.5;
}
button.danger-solid {
  background: var(--bad); color: #fff; border-color: transparent; font-weight: 700;
}
button.danger-solid:hover { background: #f05570; }
button:disabled { opacity: .5; cursor: not-allowed; }

/* package picker — radio cards, so a tap target is a whole row not a dot */
.pkgpick { display: flex; flex-direction: column; gap: 7px; }
.pkg {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: 10px; background: var(--surface-2);
  cursor: pointer; transition: border-color .14s ease, background .14s ease;
}
.pkg:hover { border-color: var(--line-strong); }
.pkg:has(input:checked) { border-color: var(--brand); background: var(--brand-soft); }
.pkg:has(input:focus-visible) { outline: 3px solid var(--brand-soft); }
.pkgname { font-weight: 600; font-size: 13px; }
.pkgslots { margin-left: auto; font-size: 12px; color: var(--muted); }

/* segmented quantity control — tap a preset instead of typing a number */
.segwrap { display: flex; flex-direction: column; gap: 8px; }
.seg-row { display: flex; flex-wrap: wrap; gap: 6px; }
.seg { position: relative; }
.seg input { position: absolute; opacity: 0; pointer-events: none; }
.seg span {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 56px; min-height: 38px; padding: 6px 14px; cursor: pointer;
  border: 1px solid var(--line); border-radius: 9px; background: var(--surface-2);
  font-size: 13px; font-weight: 600; color: var(--ink);
  transition: background .14s ease, border-color .14s ease, color .14s ease;
}
.seg span:hover { border-color: var(--line-strong); background: var(--surface-3); }
.seg input:checked + span {
  background: var(--brand); border-color: transparent; color: var(--brand-ink);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25);
}
.seg input:focus-visible + span { outline: 3px solid var(--brand-soft); outline-offset: 1px; }
.seg-custom { width: 100%; }
.seg-custom[hidden] { display: none; }

/* split primary action */
.split { display: inline-flex; }
.split .primary { border-radius: 8px 0 0 8px; }
.split .caret { border-radius: 0 8px 8px 0; padding: 6px 9px; margin-left: 1px; }
.menu {
  position: absolute; right: 34px; margin-top: 40px; z-index: 40;
  background: var(--surface-1); border: 1px solid var(--line-strong);
  border-radius: 11px; box-shadow: var(--shadow-lg); overflow: hidden;
  display: flex; flex-direction: column; min-width: 262px;
}
/* 🚨 A class selector beats the UA's [hidden]{display:none}, so without this
   the menu is permanently open. Caught only by looking at a screenshot. */
.menu[hidden] { display: none; }
.menu button {
  border: none; border-radius: 0; background: none; text-align: left;
  padding: 10px 14px; display: flex; flex-direction: column; gap: 2px;
}
.menu button + button { border-top: 1px solid var(--line); }
.menu button:hover { background: var(--surface-2); }
.menu strong { font-size: 13px; font-weight: 600; }
.menu span { font-size: 11.5px; color: var(--muted); font-weight: 400; }

/* credential handoff card — what the seller pastes into WhatsApp */
.handoff {
  background: var(--surface-2); border: 1px dashed var(--line-strong);
  border-radius: 10px; padding: 12px 14px;
  font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 13px;
  white-space: pre-wrap; line-height: 1.6;
}
.error { color: var(--bad); background: var(--bad-bg); border-radius: 8px; padding: 8px 12px; font-size: 13px; }
.okmsg { color: var(--ok); background: var(--ok-bg); border-radius: 8px; padding: 8px 12px; font-size: 13px; }

/* ---------- sign-in */
.gate {
  min-height: 100vh; display: flex; align-items: center; justify-content: center;
  background:
    radial-gradient(600px 300px at 70% 10%, rgba(79, 216, 255, 0.07), transparent),
    radial-gradient(500px 300px at 20% 90%, rgba(139, 107, 255, 0.06), transparent),
    var(--bg);
}
.gate .card {
  width: min(360px, 92vw); background: var(--surface-1); border: 1px solid var(--line);
  border-radius: 16px; padding: 28px; box-shadow: var(--shadow-lg), var(--edge);
  display: flex; flex-direction: column; gap: 12px;
}
.gate h1 { margin: 4px 0 2px; font-size: 19px; letter-spacing: -0.03em; }
.gate p { margin: 0 0 6px; color: var(--muted); font-size: 13px; }

.empty { padding: 40px 20px; text-align: center; color: var(--muted); line-height: 1.6; }
.sr {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* row actions are ALWAYS visible — hover-reveal simply does not exist on touch */
td.actions { text-align: right; }
td.actions button + button { margin-left: 6px; }

.pager {
  display: flex; align-items: center; justify-content: center; gap: 14px;
  padding: 14px 0 0; font-size: 12.5px; color: var(--muted);
}

.warnchip { background: var(--warn-bg); color: var(--warn); font-weight: 600; }

/* Toasts are PURELY VISUAL — the announcement goes to the pre-existing live
   regions in index.html. On phones they sit at the TOP: a bottom toast covers
   the focused field on a 375px screen, which is an SC 2.4.11 failure. */
.toasts {
  position: fixed; bottom: 22px; left: 50%; transform: translateX(-50%);
  z-index: 90; display: flex; flex-direction: column; gap: 8px; align-items: center;
  pointer-events: none;
}
@media (max-width: 800px) {
  .toasts { bottom: auto; top: 12px; width: calc(100% - 24px); }
  .toast { width: 100%; text-align: center; }
}
.toast {
  background: var(--surface-3); border: 1px solid var(--line-strong);
  border-radius: 10px; padding: 9px 16px; font-size: 13px;
  box-shadow: var(--shadow-md); animation: pop .16s ease;
}
.toast.ok  { border-color: var(--ok);  color: var(--ok); }
.toast.bad { border-color: var(--bad); color: var(--bad); }

/* "there is a newer build than the one this tab is running" */
.newbuild {
  position: fixed; left: 50%; transform: translateX(-50%); top: 14px; z-index: 95;
  display: flex; align-items: center; gap: 14px;
  background: var(--surface-3); border: 1px solid var(--brand);
  border-radius: 11px; padding: 10px 12px 10px 16px; font-size: 13px;
  box-shadow: var(--shadow-lg); animation: pop .16s ease;
}
@media (max-width: 800px) { .newbuild { left: 12px; right: 12px; transform: none; } }

.handoff.scroll { max-height: 220px; overflow-y: auto; }
.handoff:focus-visible { outline: 3px solid var(--brand); outline-offset: 2px; }
.check { display: flex; align-items: center; gap: 9px; font-size: 13px; color: var(--muted); cursor: pointer; }
.check input { width: 18px; height: 18px; accent-color: var(--brand); }

.sidebar nav { display: flex; flex-direction: column; gap: 3px; }
a.nav-item { text-decoration: none; }
.sidebar .foot .who { margin-bottom: 2px; }

/* Phone chrome. Hidden on desktop; the sidebar owns that. */
.topbar, .tabbar { display: none; }

/* ---------- phone. Resellers run their business from a phone, so the table
   becomes a labelled card list rather than something to pan sideways — and
   navigation moves to a real bottom tab bar. A desktop sidebar squeezed onto
   a 393px screen was putting five 29px-tall text links on every view; that
   was the biggest single mobile problem here, not any individual page. */
@media (max-width: 800px) {
  .shell { flex-direction: column; }
  .sidebar { display: none; }

  .topbar {
    display: flex; align-items: center; gap: 10px;
    position: sticky; top: 0; z-index: 30;
    padding: 8px 14px; padding-top: calc(8px + env(safe-area-inset-top));
    background: rgba(10, 13, 22, 0.86); backdrop-filter: blur(12px);
    border-bottom: 1px solid var(--line);
  }
  .topbar .wordmark { padding: 0; font-size: 14px; }
  .topbar .who {
    margin-left: auto; font-size: 12px; color: var(--muted);
    max-width: 42vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .topbar button { min-height: 44px; display: inline-flex; align-items: center; }

  .tabbar {
    display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
    position: fixed; inset-inline: 0; bottom: 0; z-index: 40;
    background: rgba(10, 13, 22, 0.92); backdrop-filter: blur(14px);
    border-top: 1px solid var(--line);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .tab {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 3px; min-height: 56px; text-decoration: none;
    color: var(--soft); font-size: 10px; font-weight: 600; letter-spacing: .01em;
  }
  .tab svg { width: 22px; height: 22px; }
  .tab.on { color: var(--brand); }
  .tab.on svg { stroke-width: 2.4; }
  .tab:active { background: rgba(255, 255, 255, .05); }

  /* Content must clear the bar, or the last row is unreachable. */
  .main { padding: 16px 12px calc(76px + env(safe-area-inset-bottom)); }
  /* Every real control clears 44px. The audit found 27 sub-44 targets on the
     busiest view; almost all of them were chrome and form controls sized for
     a mouse. Dense in-card actions are handled by td.actions below. */
  /* 🚨 16px or iOS zooms the page the moment a field takes focus — and it does
     not zoom back out. Every input here was 13px, so tapping the search box or
     the password field threw the layout sideways.
     This MUST sit after the base `input, select` rule: same specificity means
     source order decides, and an identical rule placed near the top of the
     file lost silently to the 13px default further down. */
  input, select, textarea { font-size: 16px; min-height: 44px; padding: 10px 12px; }
  button, .btn { min-height: 44px; }
  .field label { font-size: 13px; }
  .gate .card button[type="submit"] { min-height: 48px; }
  /* The split-button caret is a real action (it opens the trial option), so it
     gets a real width rather than the 28px a mouse can manage. */
  .split .caret { min-width: 48px; }

  .page-head { flex-wrap: wrap; gap: 9px; }
  .page-head h1 { font-size: 19px; width: 100%; }
  /* The primary action gets its own full-width row instead of being wedged
     beside the title — otherwise Campañas and Paquetes read cramped while
     Clientes (which has the split control) reads fine. */
  .page-head > button.primary:not(.caret) { flex: 1 0 100%; }
  .page-head .spacer { display: none; }
  .page-head input[type="search"] { width: 100%; order: 5; }
  .page-head select { flex: 1; }
  .split { flex: 1 0 auto; }
  .split .primary:first-child { flex: 1; }
  .menu { right: 12px; left: 12px; min-width: 0; }

  .stats { grid-template-columns: repeat(3, 1fr); gap: 8px; }
  .stat { padding: 10px 12px; }
  .stat .n { font-size: 19px; }
  .stat .l { font-size: 11px; }

  .tablewrap { border: none; background: none; box-shadow: none; overflow: visible; }
  table, thead, tbody, tr, td { display: block; width: 100%; }
  thead { display: none; }
  tbody tr {
    background: var(--surface-1); border: 1px solid var(--line); border-radius: 12px;
    padding: 11px 13px; margin-bottom: 10px; box-shadow: var(--shadow-sm), var(--edge);
  }
  tbody tr:hover { background: var(--surface-1); }
  td {
    border: none; padding: 3px 0; white-space: normal;
    display: flex; align-items: baseline; gap: 10px;
  }
  td[data-l]::before {
    content: attr(data-l); flex: none; width: 96px; color: var(--soft);
    font-size: 11px; text-transform: uppercase; letter-spacing: .05em; font-weight: 600;
  }
  /* the empty-state cell is prose, not a field — keep it out of the card grid */
  td.empty { display: block; padding: 26px 8px; }
  tbody tr:has(td.empty) { background: none; border: none; box-shadow: none; }
  td:empty, td.actions:empty { display: none; }
  td.actions {
    display: flex; gap: 8px; margin-top: 9px; padding-top: 10px;
    border-top: 1px solid var(--line); text-align: left;
  }
  td.actions::before { display: none; }
  td.actions button { flex: 1; margin-left: 0 !important; padding: 9px 10px; }
  td .note { max-width: none; white-space: normal; }
  .dlgform footer button { flex: 1; }

  /* 🚨 THE KEYBOARD. On a real Galaxy A14 it takes 375px of a 729px screen.
     A <dialog> centres itself in the LAYOUT viewport, which does not shrink —
     so the submit button landed 210px below anything visible and "Entregar
     acceso" could not be tapped after typing the customer's name.
     Anchor the dialog to the top and cap it at the VISUAL viewport (--vvh,
     maintained in app.js), letting its body scroll instead of its footer
     falling off the world. */
  .dlg {
    margin: 10px auto auto;
    max-height: calc(var(--vvh, 100dvh) - 20px);
    display: flex; flex-direction: column;
  }
  .dlgform { display: flex; flex-direction: column; min-height: 0; max-height: 100%; }
  .dlgform header, .dlgform footer { flex: none; }
  .dlgform .body { overflow-y: auto; min-height: 0; -webkit-overflow-scrolling: touch; }

  /* Dialogs are where a phone user actually works — every control in one has
     to be thumb-sized. Measured before this: the trial-length chips were 38px
     tall, the ↻ regenerate buttons 36px wide, and the handoff acknowledgement
     checkbox 18px — the one control that unlocks the screen showing a
     password you cannot see again. */
  .seg span { min-height: 44px; padding: 10px 16px; }
  .field .row button { min-width: 48px; min-height: 44px; }
  .check { min-height: 44px; }
  .check input { width: 24px; height: 24px; flex: none; }
  .pkg { min-height: 52px; }
}

/* ---------- atajos de teclado: el diálogo «?», la pista de «Ir a», el cursor
   de fila. Todo esto vive al final del archivo a propósito: `tr.rowsel` tiene
   que ganarle a `tbody tr:hover`, que es de la misma especificidad. */
.sc-btn { padding: 4px 10px; font-weight: 700; line-height: 1; }
.dlg.sc { width: min(720px, 94vw); }
.sc-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(238px, 1fr)); gap: 18px;
}
/* Cada sección es su propia rejilla de dos columnas y cada fila se disuelve
   con display:contents, para que TODAS las descripciones de una sección
   arranquen en la misma x — si no, la fila de «⌘ .» empuja su texto y la
   columna queda dentada. */
.sc-grid section {
  display: grid; grid-template-columns: max-content 1fr;
  column-gap: 10px; align-items: center; align-content: start;
}
.sc-grid h4 {
  grid-column: 1 / -1; margin: 0 0 8px; font-size: 10.5px; text-transform: uppercase;
  letter-spacing: .07em; color: var(--soft); font-weight: 700;
}
.sc-row { display: contents; }
.sc-keys { display: inline-flex; gap: 3px; padding: 4px 0; }
.sc-what { padding: 4px 0; font-size: 13px; color: var(--muted); }
.sc-keys kbd, .g-hint kbd {
  font: inherit; font-size: 11px; font-weight: 700; min-width: 21px; text-align: center;
  padding: 3px 6px; border-radius: 6px; background: var(--surface-3);
  border: 1px solid var(--line-strong); border-bottom-width: 2px;
  color: var(--ink); line-height: 1;
}
.sc-or { font-size: 10px; color: var(--soft); align-self: center; }

.g-hint {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%); z-index: 80;
  display: flex; gap: 8px; align-items: center; white-space: nowrap;
  padding: 9px 15px; border-radius: 999px; background: var(--surface-3);
  border: 1px solid var(--line-strong); box-shadow: var(--shadow-md);
  font-size: 12px; color: var(--muted); animation: pop .12s ease;
}
.g-hint kbd { background: var(--surface-1); }

/* El cursor de fila: relleno tenue MÁS un borde sólido a la izquierda. Nunca
   sólo color — sobre un monitor malo el relleno solo desaparece. */
tbody tr.rowsel { background: var(--brand-soft); box-shadow: inset 3px 0 0 var(--brand); }
tbody tr:focus { outline: none; }
tbody tr:focus-visible { outline: 3px solid var(--brand); outline-offset: -3px; }

/* Sin teclado no hay atajos: en teléfono el botón «?» y la pista sobran. */
@media (max-width: 800px) { .sc-btn, .g-hint { display: none; } }

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