/* ============================================================================
   mobile.css — responsive layer for phones/small tablets (≤ 768px).

   HARD RULE: every visual rule lives inside the @media (max-width: 768px)
   block below, so it can only ever match on narrow screens. The desktop
   layout (loaded from tokens.css + components.css + each page's own <style>)
   is therefore byte-for-byte unchanged — this file is purely additive.

   The only rules OUTSIDE the media query are the base `display:none` that
   hides the mobile-only bottom nav on desktop (a new element that renders
   nothing on desktop — zero visual change to the existing layout).

   Loaded after components.css in base.html (login + Hub) and _app.html
   (all app pages). See docs/superpowers/specs/2026-07-18-mobile-responsive-design.md
   ========================================================================== */

/* Mobile-only chrome is hidden on desktop (new elements, no visual impact). */
.mnav,
.mnav-sheet { display: none; }

/* The mobile filter dropdown (built by /static/filter-collapse.js from each
   .pill-row's buttons) is a new element hidden on desktop — the pills show as
   before. It's revealed, and the pills hidden, only inside the media query. */
.filter-select { display: none; }

@media (max-width: 768px) {
  /* ==== App shell ======================================================= */
  /* Drop the desktop left sidebar + its vertical hairline; the bottom tab
     bar (below) takes over primary navigation. */
  .sidebar,
  .shell > .hairline--v { display: none; }

  /* CRITICAL mobile-scroll fix. The shell (.app) is height:100vh, but on a
     phone 100vh is the LARGEST viewport (toolbars hidden) — taller than what's
     actually visible while the address bar shows. That pushes the bottom of
     the inner scroll area (.content-wrap) below the fold, so pages can't be
     scrolled to their end. `dvh` (dynamic viewport height) tracks the real
     visible height; browsers without dvh keep the 100vh from _app.html. */
  .app { height: 100dvh; }
  .content-wrap { -webkit-overflow-scrolling: touch; }

  /* Content goes full-width and leaves room for the fixed bottom nav. */
  .content {
    padding: 16px 14px calc(64px + env(safe-area-inset-bottom, 0px));
    gap: 14px;
  }

  /* Slim top bar: let the title use the freed space (the desktop counter-
     weight spacer is only there to visually center the title on wide screens). */
  .titlebar { padding-left: 4px; padding-right: 4px; }
  .tb-spacer { display: none; }
  /* Balance the bar so the family/user title sits centered: keep the ☰ account
     menu on the left, move the bell + calendar (the <a> tb-btns) to the RIGHT
     of the title (order:2), and let the title fill the middle. Reads as the
     conventional ☰ · Title · 🔔📅 mobile app bar. */
  .titlebar a.tb-btn { order: 2; }
  .tb-title {
    order: 1; flex: 1; text-align: center;
    font-size: var(--font-small);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    padding: 0 6px;
  }

  /* ==== Page header: stack title over actions, wrap the buttons ========= */
  /* On desktop the title and its action buttons sit on one row; at phone width
     that row overflows (the "Add" button clipped off the edge). Every page's
     header is the FIRST child of .content and contains the .page-title h1, but
     each page names its wrapper differently (.page-head-row, .debt-head,
     .assets-head, .subs-header, …). Target them ALL by structure — no per-page
     class list to keep in sync — so the title stacks over its action buttons
     and the buttons wrap instead of clipping off the right edge. */
  .content > :first-child:has(.page-title) {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
  }
  .content > :first-child:has(.page-title) > :last-child { flex-wrap: wrap; }

  /* Title + caps subtitle spacing. The desktop `.page-title { margin-bottom:
     -6px }` tucks the subtitle up tight; on a phone the larger, often-wrapped
     title then clips against the caps subtitle below it. Give them room, and
     ease the subtitle's very wide 0.34em tracking so it doesn't wrap mid-word
     or run to the edge. */
  .page-title { margin-bottom: 9px; line-height: 1.28; }
  .caps-label--spaced { letter-spacing: 0.16em; line-height: 1.5; }

  /* ==== Bottom tab bar (_mobile_nav.html) =============================== */
  .mnav {
    display: flex;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
    height: calc(58px + env(safe-area-inset-bottom, 0px));
    padding-bottom: env(safe-area-inset-bottom, 0px);
    background: var(--bg-topbar);
    border-top: var(--hairline) solid var(--border);
  }
  .mnav__tab {
    flex: 1 1 0; min-width: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 3px; padding: 8px 2px 6px;
    background: none; border: none; cursor: pointer;
    color: var(--text-dim); text-decoration: none;
    font: var(--weight-semibold) 10px/1 var(--font-sans);
  }
  .mnav__tab .icon { font-size: 19px; }
  .mnav__lbl {
    max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    letter-spacing: 0.02em;
  }
  .mnav__tab.is-active { color: var(--text-main); }
  .mnav__tab.is-active .icon { color: var(--accent); }

  /* "More" bottom sheet */
  .mnav-sheet {
    display: block;
    position: fixed; inset: 0; z-index: 65;
  }
  .mnav-sheet[hidden] { display: none; }
  .mnav-sheet__backdrop {
    position: absolute; inset: 0;
    background: rgba(0, 0, 0, 0.55);
    opacity: 0; transition: opacity 0.18s ease;
  }
  .mnav-sheet.is-open .mnav-sheet__backdrop { opacity: 1; }
  .mnav-sheet__panel {
    position: absolute; left: 0; right: 0; bottom: 0;
    background: var(--bg-card);
    border-top-left-radius: 16px; border-top-right-radius: 16px;
    border-top: var(--hairline) solid var(--border);
    padding: 8px 12px calc(16px + env(safe-area-inset-bottom, 0px));
    transform: translateY(100%); transition: transform 0.2s ease;
    max-height: 70vh; overflow-y: auto;
  }
  .mnav-sheet.is-open .mnav-sheet__panel { transform: translateY(0); }
  .mnav-sheet__grip {
    width: 38px; height: 4px; border-radius: 999px;
    background: var(--border); margin: 6px auto 12px;
  }
  .mnav-sheet__item {
    display: flex; align-items: center; gap: 12px;
    padding: 13px 10px; border-radius: var(--radius-tile);
    color: var(--text-main); text-decoration: none;
    font: var(--weight-regular) var(--font-body)/1 var(--font-sans);
  }
  .mnav-sheet__item .icon { font-size: 17px; color: var(--text-dim); }
  .mnav-sheet__item.is-active { color: var(--accent); }
  .mnav-sheet__item.is-active .icon { color: var(--accent); }
  .mnav-sheet__item.is-danger { color: var(--danger); }
  .mnav-sheet__item.is-danger .icon { color: var(--danger); }

  /* ==== KPI rows -> 2-up ================================================ */
  /* KPI / stat tile rows → 2 columns. Covers .kpi-row(+--uniform/--3/--4 via
     the base class) and .stat-row (HomeKeeper Dashboard is repeat(4,1fr) and
     was clipping; Insights is already 2-up; Admin's .stat-row is display:flex
     so grid-template-columns is a harmless no-op there). Profile's own
     .profile-stats stays 1-col — its long net-worth values need the full
     width — and is intentionally NOT included here. */
  .kpi-row,
  .kpi-row--uniform,
  .stat-row { grid-template-columns: 1fr 1fr !important; }

  /* ==== Filter pills -> single dropdown ================================= */
  /* Save horizontal space: hide the wrapping row of pill buttons and show the
     script-built <select> in its place (one per .pill-row). Each page's own
     filter logic is untouched — the select .click()s the matching pill. */
  .pill-row .filter-pill { display: none; }
  .pill-row .filter-select {
    display: block; width: 100%; box-sizing: border-box;
    padding: 9px 12px; border-radius: var(--radius-chip);
    background: var(--bg-card); color: var(--text-main);
    border: var(--hairline) solid var(--border);
    font: var(--weight-semibold) var(--font-small)/1.1 var(--font-sans);
  }
  /* Row filtering hides rows via the [hidden] attribute (subscriptions/debt/
     assets) or the .is-filtered-hidden class (bills/budget). The card-grid
     `display` rules above out-specify BOTH, so on a phone filtered rows leaked
     back in and the filter looked dead — force filtered rows hidden. */
  [hidden], .is-filtered-hidden { display: none !important; }

  /* ==== Modals & focus panels -> full-screen sheets ==================== */
  .modal-overlay { padding: 0 !important; align-items: stretch !important; }
  .modal-overlay .modal {
    width: 100% !important; max-width: 100% !important;
    /* Exactly the viewport height + own scroll, so a long Manage list (or a
       tall edit form) scrolls to the very bottom instead of being clipped by
       the fixed overlay (which doesn't scroll). */
    height: 100vh; max-height: 100vh; border-radius: 0 !important;
    display: flex; flex-direction: column;
    overflow-y: auto; -webkit-overflow-scrolling: touch;
  }
  /* Detail inspector panels present as a bottom SHEET on a phone — a slide-up
     "dropdown" of details, anchored to the bottom with a capped height + its
     own scroll and a rounded top — rather than a full-height side drawer. The
     document VIEWER (--doc) is the exception: it stays a full-screen sheet so
     the file is as large as possible. */
  .inspector-panel {
    top: auto; bottom: 0; left: 0; right: 0;
    width: 100% !important; max-width: 100% !important;
    height: auto; max-height: 86vh;
    border-left: 0; border-top: var(--hairline) solid var(--border);
    border-radius: 16px 16px 0 0 !important;
    box-shadow: 0 -14px 34px rgba(0, 0, 0, 0.5);
  }
  .inspector-panel--doc {
    top: var(--titlebar-h); bottom: 0;
    height: auto; max-height: none;
    border-radius: 0 !important;
    -webkit-overflow-scrolling: touch;   /* momentum finger scroll */
  }
  /* Scroll the document with a finger (momentum touch), not a drag-the-
     scrollbar/wheel gesture: the wrapper scrolls a tall image, and the PDF
     <iframe> keeps its own native touch scroll. */
  .inspector-panel--doc .doc-viewer {
    overflow: auto; -webkit-overflow-scrolling: touch;
    touch-action: pan-y pinch-zoom;
  }
  .inspector-panel--doc .doc-viewer__frame { touch-action: pan-y pinch-zoom; }
  /* Stack the 2-column field pairs (name|vendor, amount|due) to one column on
     a phone — bigger touch targets, no cramped side-by-side inputs. */
  .modal__grid { grid-template-columns: 1fr; }

  /* ==== Wide grids -> card per row ===================================== */
  /* Demo target: the Bills ledger (api/templates/pages/bills.html). Each
     11-column <tr class="bill-row"> becomes a compact card via positional
     grid — every visible field is its OWN <td>, so it maps cleanly to one
     grid cell (no markup change, no per-cell data-label needed). Hidden
     fields (lender / account / owner / auto-pay) drop off the phone card;
     they remain on the full edit dialog reachable from the row's ⋮ (or by
     tapping the card — see the mobile handler in bills.html). */
  .ledger-table-wrap { overflow: visible; }
  .ledger-table-wrap .table { min-width: 0; width: 100%; }
  .ledger-table-wrap .table-head { display: none; }
  .ledger-table-wrap tbody,
  .ledger-table-wrap tbody tr { display: block; }

  .ledger-table-wrap .bill-row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    column-gap: 11px; row-gap: 2px;
    padding: 11px 14px; margin: 0 0 8px;
    background: var(--bg-card);
    border: var(--hairline) solid var(--border);
    border-radius: var(--radius-menu);
    cursor: pointer;
  }
  .ledger-table-wrap .bill-row > td { padding: 0 !important; border: 0 !important; }
  /* icon (1) spans the three text rows on the left */
  .ledger-table-wrap .bill-row > td:nth-child(1) { grid-column: 1; grid-row: 1 / span 3; align-self: start; }
  /* name (2) */
  .ledger-table-wrap .bill-row > td:nth-child(2) {
    grid-column: 2; grid-row: 1;
    font: var(--weight-semibold) var(--font-body)/1.2 var(--font-sans);
    color: var(--text-main);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  /* amount (4) */
  .ledger-table-wrap .bill-row > td:nth-child(4) {
    grid-column: 3; grid-row: 1; justify-self: end;
    font-weight: var(--weight-semibold); color: var(--text-main); text-align: right;
  }
  /* category (7) */
  .ledger-table-wrap .bill-row > td:nth-child(7) {
    grid-column: 2; grid-row: 2;
    color: var(--text-dim); font: var(--weight-regular) var(--font-small)/1.3 var(--font-sans);
  }
  /* status pill (10) */
  .ledger-table-wrap .bill-row > td:nth-child(10) { grid-column: 3; grid-row: 2; justify-self: end; }
  /* due day (5) — the cell is just a number, so label it */
  .ledger-table-wrap .bill-row > td:nth-child(5) {
    grid-column: 2; grid-row: 3;
    color: var(--text-dim); font: var(--weight-regular) var(--font-small)/1.3 var(--font-sans);
  }
  .ledger-table-wrap .bill-row > td:nth-child(5) .ge-view::before { content: "Due day "; color: var(--text-dim); }
  /* menu ⋮ (11) */
  .ledger-table-wrap .bill-row > td:nth-child(11) { grid-column: 3; grid-row: 3; justify-self: end; }
  /* hidden on the phone card: lender (3), account (6), owner (8), auto-pay (9) */
  .ledger-table-wrap .bill-row > td:nth-child(3),
  .ledger-table-wrap .bill-row > td:nth-child(6),
  .ledger-table-wrap .bill-row > td:nth-child(8),
  .ledger-table-wrap .bill-row > td:nth-child(9) { display: none; }
}
