/* ─────────────────────────────────────────────────────────────────────────────
 * The portal on a phone (user 2026-10-24: "Can we make the portal more mobile friendly?").
 *
 * Loaded AFTER app.css, so these rules win at equal specificity. Everything here sits inside one
 * breakpoint (768px, the same one that turns the sidebar into a drawer in app.css). Desktop is
 * untouched.
 *
 * The bug behind the screenshot: on a phone a few things were wider than the screen (the topbar's
 * 326px search box, a row of tabs, a filter strip), so the browser zoomed the WHOLE page out to fit
 * the widest one and the page itself filled only half of it. The rules below:
 *   1. Nothing may make the page wider than the screen (the page is clipped sideways; rows of tabs
 *      and filter pills scroll sideways inside themselves instead).
 *   2. #main always takes the full width (it used to shrink-wrap on pages that pinned it only on
 *      desktop: the Dashboard, Settings, the Intake page).
 *   3. The topbar fits: the logo shrinks, the search box becomes a search button (it opens the same
 *      search window, full width), "Create new" keeps only its +.
 *   4. Page headers wrap instead of overlapping (the matter header's status, stage, Customize and
 *      Edit matter ran over each other).
 *   5. Filter rows stack: the label above, its pills on one line that scrolls, the search full width.
 *   6. Dialogs and menus fit the screen.
 * Tests: api/_lib/mobile-layout.test.mjs.
 * ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 768px) {
  /* 1. The page never scrolls sideways (a table or a strip scrolls inside its own box). `clip`, not
        `hidden`: it makes no scroll container, so position: sticky keeps working. */
  html, body { overflow-x: clip; }

  /* 2. Full width on every page, whatever a page pins on desktop. */
  #main,
  #sidebar.collapsed ~ #main,
  body #main { margin-left: 0 !important; width: 100% !important; min-width: 0 !important; max-width: 100vw; }
  #content { min-width: 0; max-width: 100vw; }

  /* The menu drawer has no Collapse button (a drawer closes; collapsing is for a desktop window). */
  .sidebar-collapse-btn { display: none !important; }

  /* 3. The topbar: [menu] [logo] ........ [search] [+] [sync] [bell] */
  .topbar-brand { width: auto !important; min-width: 0; max-width: none; padding: 0 var(--space-1); flex: 0 1 auto; }
  .topbar-brand-logo { max-height: 34px; max-width: 132px; }
  .topbar-search {
    position: relative;
    width: 40px !important; min-width: 40px !important; max-width: 40px !important;
    margin-left: auto; padding: 0; justify-content: center; gap: 0;
  }
  .topbar-search input { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; font-size: 16px; }
  .topbar-search .search-clear { display: none !important; }
  .topbar-right { margin-left: var(--space-2); margin-right: var(--space-2); gap: 6px; }
  .create-new-btn { width: 40px; padding: 0; justify-content: center; }
  .create-new-btn > span { display: none; }
  .vas-pill .vas-pill-text { display: none; }
  /* The search window: full width under the topbar's edge, scrolling when long. */
  #global-search-results,
  #sidebar.collapsed ~ #main #global-search-results,
  body:has(#sidebar.collapsed) #global-search-results {
    left: var(--space-2); right: var(--space-2); width: auto;
    max-height: calc(100dvh - var(--space-4)); overflow-y: auto;
  }
  /* A field under 16px makes iOS zoom in on it when tapped. !important: the page's own field classes (.input,
     .select-input, .textarea-input: 14px) are more specific than a bare element rule, so this one never applied
     to them (the 2026-11-02 audit found 14px fields on every form). A pill dropdown keeps its size (ui.js's
     maximum-scale stops the zoom there); the two fields drawn larger keep theirs. */
  :is(input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not([type="color"]), select, textarea):not(.stage-select):not(.ai-ask-input):not(.cp-collab-code-input) { font-size: 16px !important; }

  /* The topbar's popovers (Create new, sync, notifications) stay on the screen. */
  .create-new-pop, .sync-popover { max-width: calc(100vw - var(--space-4)); }
  .sync-popover { right: calc(-1 * var(--space-2)); }

  /* 4. Page headers wrap: the title takes the room it needs, the buttons go under it when they do not fit. */
  .page-header { height: auto; min-height: 56px; flex-wrap: wrap; row-gap: var(--space-2); padding: var(--space-2) var(--space-3); }
  .page-header > :first-child { min-width: 0; flex: 1 1 0; }
  /* A plain page title keeps its words: with the buttons beside it too wide, the buttons go under it (Transcripts read
     "Tran", Expenses "Ex", Settings > Collaborators "Collabor"). The buttons never pass the screen's edge either: they
     wrap among themselves (Intake's New questionnaire, Mail & Ship's three). */
  .page-header > .page-title:first-child { flex: 1 0 auto; max-width: 100%; }
  .page-header > .page-actions { flex: 0 1 auto; max-width: 100%; min-width: 0; }
  .page-title { font-size: var(--fs-2xl); }
  .page-actions { flex-wrap: wrap; row-gap: var(--space-2); }
  /* A matter: the number and the client (wrapping), the status and stage under it, then the description. */
  .matter-page-header, #contact-header .page-header { align-items: flex-start; }
  .matter-title { font-size: var(--fs-xl); overflow-wrap: anywhere; }
  .matter-title-row { row-gap: var(--space-2); }
  .matter-header-pills { margin-left: 0; flex-wrap: wrap; row-gap: var(--space-2); max-width: 100%; }
  .matter-header-pills > .matter-status-dd { border-right: 0; padding-right: 0; }
  .matter-header-pills .ui-select-trigger { max-width: calc(100vw - 150px); }
  /* With three buttons (a pending matter's Quick action) the title gets the whole first line, the buttons go under it. */
  .matter-page-header:has(> .page-actions > :nth-child(3)) > .matter-header-titles { flex: 1 1 100%; }
  .matter-page-header:has(> .page-actions > :nth-child(3)) > .page-actions { flex: 1 1 100%; justify-content: flex-end; margin-top: 0; }
  /* Customize and Edit stay beside the title, top right; the title wraps instead. */
  .matter-page-header > .page-actions, #contact-header .page-header > .page-actions { flex-wrap: nowrap; }
  /* A Settings page: the breadcrumb, title and description take the whole width, the page's own buttons go under them. */
  .page-header.settings-head { row-gap: var(--space-3); }
  .page-header.settings-head > .settings-head-main { flex: 1 1 100%; }
  /* An inventory device: its five buttons go under the tag on a line of their own. */
  .page-header:has(.inv-dev-head) > .page-actions { flex: 1 1 100%; justify-content: flex-end; }
  /* The inventory dialogs' rows of three become two. */
  .inv-form .form-row.thirds { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* Rows of tabs scroll sideways inside themselves (the page stays put); the active underline is pulled inside the bar. */
  .contact-tabbar, .tabbar {
    flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden;
    scrollbar-width: none; -webkit-overflow-scrolling: touch; overscroll-behavior-x: contain;
  }
  .contact-tabbar::-webkit-scrollbar, .tabbar::-webkit-scrollbar { display: none; }
  .contact-tabbar .tab, .tabbar .tab { flex: 0 0 auto; white-space: nowrap; }
  .contact-tabbar .tab.active::after { bottom: -5px; }

  /* 5. Filter rows: the label on its own line, the pills on ONE line that scrolls, Search and Columns full width under them. */
  .card-toolbar { padding: var(--space-2) var(--space-3); }
  .tr-filter-row, .tr-filter-row--status { flex-wrap: wrap; align-items: center; row-gap: 6px; }
  .tr-filter-row > .tr-filter-label,
  .tr-filter-row--status > .tr-filter-label,
  .tr-filter-row > .list-filter-label { flex: 1 1 100%; min-width: 0; text-align: left; padding-top: 0; font-size: var(--fs-xs); }
  .tr-filter-row > .spacer, .tr-filter-row--status > .spacer { display: none; }
  .tab-strip,
  .tab-strip.tr-filter-strip,
  .tab-strip.tr-filter-strip--multi {
    display: flex; flex-wrap: nowrap; max-width: 100%; min-width: 0; flex: 0 1 auto;
    overflow-x: auto; overflow-y: hidden; scrollbar-width: none; overscroll-behavior-x: contain;
  }
  .tab-strip::-webkit-scrollbar { display: none; }
  .tab-strip .tab-strip-btn { flex: 0 0 auto; white-space: nowrap; }
  .toolbar-search { flex: 1 1 100%; min-width: 0 !important; max-width: none !important; width: auto !important; order: 10; }
  .toolbar-search input { width: 100% !important; min-width: 0 !important; }
  /* Columns and the other toolbar buttons follow the search on its own line. */
  .tr-filter-row > .btn, .tr-filter-row--status > .btn { order: 11; }
  .toolbar-controls > .spacer { display: none; }
  /* A page's own button group inside a filter row wraps too (Zelle's Check now / Scan past emails / Settings). */
  .tr-filter-row > div:not(.tab-strip):not(.toolbar-search):not(.spacer) { flex-wrap: wrap; max-width: 100%; margin-left: 0; }
  /* Date ranges (Tasks, Activities, Transactions): two boxes side by side, each shrinking. */
  .mc-date-range { flex: 1 1 100%; min-width: 0; }
  .mc-date-range input { min-width: 0; }

  /* Cards and the list pages' footers. */
  .tr-page-body { padding-left: var(--space-2); padding-right: var(--space-2); }
  /* A list card's footer (pager, count, per page, Export ...) is 64px tall on a computer; on a phone it may need two lines, so it
     grows with them instead (user 2026-11-08, Documents > Dashboard: Export cut off under the pager; Matters lost its PDF menu the
     same way). One line is still 64px: 12px, the 40px controls, 12px. Export is its icon alone, so the usual footer fits on one line;
     so is the Matters PDF report (its icon and caret: user 2026-11-08, "Make the Matters PDF report icon-only on phones too"). */
  .card-footer { flex-wrap: wrap; row-gap: var(--space-2); height: auto; min-height: 64px; padding-top: var(--space-3); padding-bottom: var(--space-3); }
  .card-footer .btn:has(> .icon-export) { font-size: 0; gap: 4px; padding-left: 8px; padding-right: 8px; justify-content: center; }
  .card-footer .btn:has(> .icon-export):not(:has(> svg ~ svg)) { gap: 0; width: var(--control-h); padding-left: 0; padding-right: 0; }
  .card-footer .btn:has(> .icon-export) > .icon { margin: 0; }
  .kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* 6. Dialogs fit the screen: nearly full width, scrolling inside, buttons wrapping. */
  .modal-overlay { padding: var(--space-2); align-items: flex-start; padding-top: max(var(--space-2), env(safe-area-inset-top)); }
  .modal { max-width: 100% !important; width: 100% !important; max-height: calc(100dvh - var(--space-4)); }
  .modal-footer { flex-wrap: wrap; row-gap: var(--space-2); }
  .ui-pop { max-width: calc(100vw - var(--space-4)); }

  /* 7. What the page-by-page audit of 2026-11-02 found (every page and tab at iPhone size). */
  /* A table wider than its card scrolls sideways inside itself (ui.js marks it; a list page's .tr-scroll already does). */
  table[data-m-scroll] { display: block; max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; overscroll-behavior-x: contain; }
  /* Three fields side by side were a few letters each ("Searc", "11,"): one under another. */
  .form-row.thirds { grid-template-columns: minmax(0, 1fr); }
  /* Cards and dialogs give their fields more of the screen. */
  .settings-field { padding: var(--space-4); }
  /* Quick intake's four-way picker (New person, company, estate, Existing contact): two by two. */
  .ec-typetoggle:has(> .ec-type-btn:nth-child(4)) {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1px; height: auto; width: 100%;
    background: var(--border-strong);
  }
  .ec-typetoggle:has(> .ec-type-btn:nth-child(4)) > .ec-type-btn { height: 40px; justify-content: center; border-left: 0; }
  /* A matter's / contact's Communications toolbar: the type pills, then the dates and their preset, each on a line. */
  #mc-toolbar-slot { flex: 1 1 100% !important; flex-wrap: wrap !important; row-gap: 6px; }
  #mc-toolbar-slot > .tab-strip { flex: 1 1 100%; }
  .mc-date-range { flex-wrap: wrap; row-gap: 6px; }
  .mc-date-range .msl-datepicker { flex: 1 1 0; width: auto; min-width: 0; }
  .mc-date-range > .ui-select, .mc-date-range > .mc-date-preset { flex: 1 1 100%; margin-left: 0; }
  /* A toolbar's own button group wraps (Billing > Zelle: Check now, Scan past emails, Settings, Columns). */
  #zl-card .zl-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); flex: 1 1 100%; margin-left: 0; }
  /* Transcripts > Offer in compromise: eight figures in one row overlapped; two across. */
  .trx-oic-stats { grid-auto-flow: row; grid-template-columns: repeat(2, minmax(0, 1fr)); width: 100%; }
  .trx-oic-stats .trx-kpi { white-space: normal; padding: 0 8px; border-left: 0 !important; }
  /* A full-page editor's footer (New event, New contact, Edit matter ...): its buttons wrap instead of running off. */
  .ec-footer-inner { flex-wrap: wrap; row-gap: var(--space-2); }
  /* The month calendar's day numbers: a little more to aim at. */
  .cal-mnum { min-width: 32px; min-height: 32px; }

  /* 8. A list page is not locked to the window on a phone (user 2026-11-03: the Fax dashboard's table showed its header and
        no rows, the tab row was cut in half). On a computer the page is as tall as the window and the table scrolls inside its
        card, its height kept up by calc-size(), which iPhone Safari does not have: there the rows were squeezed to nothing,
        and the tab row (a sideways scroller, so allowed to shrink to 0) was squeezed with them. On a phone the page grows with
        its rows and scrolls as a whole; the table scrolls only sideways in its card. */
  body:has(.tr-page-body:not(.is-embedded)) #main,
  body:has(#draft-pane-dashboard:not([hidden])) #main { height: auto; min-height: calc(100dvh - var(--topbar-h)); overflow: visible; }
  body:has(.tr-page-body:not(.is-embedded)) #content,
  body:has(#draft-pane-dashboard:not([hidden])) #content { height: auto; overflow: visible; }
  .tr-page-body:not(.is-embedded),
  .tr-page-body:not(.is-embedded):has(.card .tr-scroll) { flex: 0 0 auto; overflow: visible; }
  .contact-tabbar, .tabbar { flex-shrink: 0; }
  /* The KPI strip is a wrapping row on a computer, so the grid above never applied to it: eight figures wrapped 3, 3, 2 with
     their dividers in odd places. Two across, a line between the rows. */
  .trx-kpi-card { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0; padding: 4px 8px; }
  .trx-kpi-card > .trx-kpi { padding: 8px 6px; border-left: 0; min-width: 0; }
  .trx-kpi-card > .trx-kpi:nth-child(even) { border-left: 1px solid var(--divider); }
  .trx-kpi-card > .trx-kpi:nth-child(n+3) { border-top: 1px solid var(--divider); }
  .trx-kpi-card > :not(.trx-kpi) { grid-column: 1 / -1; margin-left: 0; justify-content: center; padding: 8px 0; }

  /* 9. The invoice panel and the Send window (Billing > Invoices; user 2026-11-07: "The invoice page looks pretty mangled on
        mobile"). The panel and its preview stack (app.css, under 1100px); here the header, the fields, the lines and the
        buttons are laid out for a phone. Heights in dvh: 100vh on an iPhone runs under Safari's toolbar. */
  .modal.iv-wide { max-height: calc(100dvh - var(--space-4)); }
  .modal.iv-wide:not(.iv-modal) { height: calc(100dvh - var(--space-4)); }
  /* Header: the number, its pill and the X on one line; the pay page / pay link / PDF buttons on the line under them. */
  .iv-wide .modal-header { flex-wrap: wrap; row-gap: var(--space-2); }
  .iv-wide .modal-header h2 { flex: 0 1 auto; min-width: 0; overflow-wrap: anywhere; }
  .iv-wide .modal-header .modal-close { margin-left: auto; }
  .iv-wide .modal-header .iv-head-actions { order: 10; flex: 1 0 100%; margin-left: 0; flex-wrap: wrap; }
  /* Fields: one under another, the two dates side by side. */
  .iv-head-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .iv-head-grid > .bd-field { grid-column: 1 / -1; }
  .iv-head-grid > .iv-f-issued_at, .iv-head-grid > .iv-f-due_at { grid-column: auto; }
  /* The lines keep every column and scroll sideways in their box (they were cut at the Amount). */
  .iv-lines { overflow-x: auto; }
  .iv-main .iv-lines > .data-table { min-width: 520px; }
  .iv-main .iv-lines.is-draft > .data-table { min-width: 660px; }
  /* The preview's title and its Invoice / Timeline switch: the switch under the title when both do not fit. */
  .iv-preview-head { flex-wrap: wrap; row-gap: var(--space-2); }
  .iv-preview-head .iv-pane-tabs { margin-left: auto; }
  .iv-modal .iv-preview-frame { min-height: 0; }
  .iv-modal .iv-preview-pages { min-height: 240px; padding: var(--space-2); }
  /* Buttons: the main one across the top, the others sharing the line under it. */
  .iv-wide .modal-footer > .spacer { display: none; }
  .iv-wide .modal-footer > .btn { flex: 1 1 auto; justify-content: center; }
  .iv-wide .modal-footer > .btn-primary { order: -1; flex-basis: 100%; }
  /* "Allow partial payments", its note on the line under it. */
  .iv-partial { flex-wrap: wrap; row-gap: 2px; }
  .iv-partial .muted { flex: 1 0 100%; padding-left: calc(var(--cb) + var(--space-2)); }

  /* 10. Communications cards (user 2026-11-08: "These cards don't look good on mobile": a card was 3/4 of the thread and its
         action icons kept their place beside the title, so the title, the From -> To line and the date had about 90px and broke
         a word per line). On a phone a card is nearly the whole width (from the client at the left, from the firm at the right,
         16px apart; the tint still tells them apart), the title block takes the whole line beside the kind's icon, and the
         actions (Reply, Edit, Add time, Delete, the files, the caret) sit on a row of their own under it, at the right, sized
         for a finger. Every kind uses this header: email, fax, call, text, client portal message, meeting. */
  .co-stream { padding-left: var(--space-2); padding-right: var(--space-2); }
  .co-call { width: calc(100% - 16px); max-width: none; }
  .co-call.co-mid { width: 100%; }
  .co-call-bar { flex-wrap: wrap; row-gap: 0; padding: 10px 10px 6px 12px; }
  .co-call-tt { flex: 1 1 calc(100% - 32px); }
  .co-call-route, .co-call-meta { overflow-wrap: anywhere; }
  .co-call-acts { flex: 1 0 100%; justify-content: flex-end; gap: 0; }
  .co-call-acts:not(:has(*)) { display: none; }
  .co-call-act { width: 36px; height: 36px; }
  .co-call-act .icon { width: 18px; height: 18px; }
  .co-call-act.co-mail-exp .icon { width: 14px; height: 14px; }
  .co-call-body { padding: 10px 12px 12px; }
}

/* Opened from the home screen (app.webmanifest, display standalone): a footer pinned to the bottom stays above the
   iPhone's home bar. env() is 0 everywhere else, so nothing moves on a computer. */
.ec-footer { padding-bottom: env(safe-area-inset-bottom, 0px); }
.form-footer { padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px)); }

/* A finger, not a mouse (phones and tablets): tick boxes and the small text buttons get room to hit. Measured
   against Apple's and Google's guidance (44pt / 48dp), the portal's 38px buttons are close; the 16px tick boxes
   and 21px "Add" links were not. */
@media (pointer: coarse) {
  :root { --cb: 20px; }
  @supports (width: round(nearest, 1px, 1px)) { :root { --cb: round(nearest, 20px, var(--dp)); } }
  .ec-add, .page-crumb, .btn-link { min-height: 32px; }
}

/* A small phone (an iPhone SE is 375px wide, most are 390-430). */
@media (max-width: 768px) {
  /* The task window's reminder rows: who gets it on a line of its own, then how long before. */
  .tm-rem { grid-template-columns: 64px minmax(0, 1fr) auto auto; }
  .tm-rem > select:first-child, .tm-rem > .ui-select:first-child { grid-column: 1 / -1; }
}
@media (max-width: 420px) {
  .topbar-brand-logo { max-width: 112px; }
  .topbar-right { gap: var(--space-1); }
  .kpi-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}

/* The topbar timer on a phone (timer.js, user 2026-11-04; 2026-11-11): the play button alone (40px, green while it runs), which opens
   the timer's panel; no room for the time or the Timekeeper's clock. */
@media (max-width: 768px) {
  .tt-btn, .tk-btn { display: none !important; }
  .tt-seg { border-radius: var(--r); }
  .tt-play-btn { width: 40px; padding: 0; justify-content: center; }
}

/* Settings > Pages on a phone (2026-11-09): the table scrolls sideways in itself, so its head does not stick under the topbar (inside its
   own scroll box that pushed it over the first row); the page names stay at the left while the levels scroll; no drag handles (a finger
   cannot drag a row; reorder on a computer). */
@media (max-width: 768px) {
  .pg-table thead th { position: static; }
  .pg-table .pg-grip-cell { display: none; }
  .pg-table thead th.pg-name, .pg-table td.pg-name, .pg-table td.pg-tab-label { position: sticky; left: 0; z-index: 1; min-width: 160px; max-width: 180px;
    white-space: normal; background-color: var(--surface); box-shadow: inset -1px 0 0 var(--divider); }
  .pg-table thead th.pg-name { top: auto; z-index: 3; background-color: var(--pg-head-bg); }
  .pg-table tbody tr > td:nth-child(2) { border-left: 1px solid var(--divider); }
  .pg-table thead th:nth-child(2) { border-left: 1px solid var(--border); border-top-left-radius: var(--r); }
}

/* 13. The Timesheet page on a phone: the totals two across; every table scrolls sideways in its own box at its natural width (user
   2026-11-11, the Team and PTO allowances tables: the standard table's width: 100% beat the list table's max-content while its fixed layout
   stayed, so the columns were squeezed to the screen and their words ran over each other). The same for a Settings page's tables. The
   office networks: one per two lines (office and X, then the address). */
@media (max-width: 768px) {
  .tsh-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  :is(.settings-detail, .tsh-page) .tr-scroll { overflow-x: auto; }
  :is(.settings-detail, .tsh-page) .tr-scroll > table:not(.pg-table) { table-layout: auto; width: max-content; min-width: 100%; }
  .tsh-page .tsh-table > thead > tr > th { width: auto; }
  .tsh-page .tsh-table > tbody > tr > td:first-child { min-width: 120px; }
  /* My timesheet fits the screen instead: the weekday over the date, each clock in and out on its line, its place under it. */
  :is(.settings-detail, .tsh-page) .tr-scroll > table.tsh-mine-table { width: 100%; min-width: 0; }
  .tsh-mine-table .tsh-day { white-space: normal; min-width: 0 !important; }
  .tsh-mine-table .tsh-dow { display: block; width: auto; }
  .tsh-mine-table > tbody > tr > td, .tsh-mine-table > thead > tr > th { padding-left: 8px !important; padding-right: 8px !important; }
  .tsh-mine-table .tsh-in, .tsh-mine-table .tsh-out { white-space: nowrap; }
  .ss-page .tsh-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .tsh-pto-in { width: 84px; }
  .tsh-office-row { grid-template-columns: minmax(0, 1fr) auto; }
  .tsh-office-row > :nth-child(2) { grid-column: 1; grid-row: 2; }
  .tsh-office-row > :nth-child(3) { grid-column: 2; grid-row: 1; }
  .tsh-office-head { display: none; }
}
