/* ── Responsive ────────────────────────────────────────────────────────── */
@media (max-width: 860px) {
  .app { grid-template-columns: 1fr; }
  /* The sidebar becomes an OFF-CANVAS DRAWER anchored to the inline-START edge (left in LTR, right in RTL).
     It keeps its base vertical column layout (brand → nav → footer); only the positioning + slide change.
     Transforms have no logical form, so the hidden offset is flipped per-direction explicitly. */
  .sidebar {
    position: fixed; inset-block: 0; inset-inline-start: 0; z-index: var(--z-drawer);
    width: min(82vw, 300px); overflow-y: auto;
    /* Track the VISIBLE viewport, not 100vh. On phones 100vh is the LARGE viewport (it spans under the
       browser URL/tool bars), so a 100vh drawer is taller than the screen and its bottom rows fall off it.
       When the nav is long enough to overflow that oversized box it still scrolls (operator menu), but a
       medium menu (regular user) "fits" the oversized box → never scrolls → its last rows are stuck under
       the URL bar, unreachable. 100dvh sizes the drawer to what's actually on screen, so the nav overflows
       and scrolls exactly when it needs to. (Base 100vh remains the fallback for engines without dvh.) */
    height: 100dvh;
    transform: translateX(-101%);            /* hidden off the inline-start edge (LTR: left) */
    transition: transform var(--dur-slow) var(--ease);
    box-shadow: var(--elev-2);
    overscroll-behavior: contain;            /* don't chain the drawer's scroll to the locked page behind */
  }
  .sidebar .nav { overscroll-behavior: contain; }
  [dir="rtl"] .sidebar { transform: translateX(101%); }   /* inline-start is the RIGHT edge in RTL */
  .app.nav-open .sidebar { transform: translateX(0); }     /* slid in — both directions (higher specificity) */
  /* dim backdrop behind the open drawer; tap closes it (app.js) */
  .nav-backdrop { display: block; position: fixed; inset: 0; z-index: var(--z-backdrop); background: var(--overlay);
                  opacity: 0; visibility: hidden; transition: opacity var(--dur-slow) var(--ease); }
  .app.nav-open .nav-backdrop { opacity: 1; visibility: visible; }
  /* the hamburger (in the topbar) shows only at this width; lock the page behind the open drawer */
  .nav-toggle { display: inline-flex; }
  body.nav-open-lock { overflow: hidden; }
  /* brand moves UP into the header; the drawer is nav-only on mobile (the account block already lives in
     the header account menu at all widths) */
  .topbar-brand { display: inline-flex; }
  .sidebar .brand { display: none; }

  .content { padding: var(--sp-5); }
  /* tighter app bar + shrinkable brand so hamburger·brand·language·theme·account never collide on a phone */
  .topbar { padding: var(--sp-3) var(--sp-4); gap: var(--sp-2h); }
  .topbar-actions { gap: var(--sp-2); }
  .topbar-lead { min-width: 0; }
  .topbar-brand { min-width: 0; }
  .topbar-page-title { display: none; }
  .topbar-brand span { overflow: hidden; text-overflow: ellipsis; }
  .page-header { padding: var(--sp-4) var(--sp-5); }   /* align the band with the topbar/content inset */
  /* finger-sized controls */
  .btn-sm { height: 40px; }
  /* wide tables scroll horizontally instead of clipping/crushing */
  .card.flush { overflow-x: auto; overflow-y: hidden; }
  .card.flush .table { min-width: 640px; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}
/* ≤640 overrides placed last so they win over the base .data-card / .stat-grid by source order
   (media queries add no specificity). */
@media (max-width: 640px) {
  /* phones: lift the two smallest type tiers a step so labels/meta/chips stay comfortably legible */
  :root { --text-2xs: 12px; --text-xs: 13px; }
  .data-card { padding: var(--sp-4); }
  /* the shared stat-grid's 150px min overflows ~2-up on the narrowest phones; tighten it here only */
  .stat-grid { grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); }
  /* footer action bars wrap to extra rows when 3 buttons won't fit one line */
  .data-card-actions { flex-wrap: wrap; }
  .data-card-actions > * { flex: 1 1 96px; }
  /* selection bar: center the toggle + count, then a full-width Fetch row that wraps to stacked
     buttons when two won't fit (the buttons grow to share the row otherwise) */
  .ptb-select { justify-content: center; text-align: center; }
  .ptb-actions { width: 100%; margin-inline-start: 0; justify-content: center; }
  .ptb-actions .btn { flex: 1 1 150px; }
  /* pager: drop the numbered list for the compact 'Page X of Y' indicator, centered */
  .pager { justify-content: center; }
  .pager-info { order: -1; width: 100%; text-align: center; }
  .pager-pages { display: none; }
  .pager-page { display: inline-flex; align-items: center; padding: 0 var(--sp-2); }
  /* keep only the rocket mark in the header brand (drop the wordmark text) */
  .topbar-brand span { display: none; }
  /* Phone app-bar declutter: the credit pill moves into the account dropdown (see _Layout / .user-menu-balance)
     and the command-palette hint is dropped (a keyboard affordance — Ctrl/Cmd+K still works with a hardware
     keyboard). That leaves the hamburger + rocket + language/theme/bell/account with room to breathe, so the
     lead never collapses and nothing overlaps the way the long balance number used to. */
  .credit-pill { display: none; }
  .cmdk-hint { display: none; }
  /* preferences matrix: tighter switch columns on phones */
  .pref-row { grid-template-columns: minmax(0, 1fr) 64px 64px; }
}
