/* ============================================================
   Re-Order CRM — mobile-first layer
   ------------------------------------------------------------
   Loaded last, after style.css and theme.css.

   The problem this fixes: on a 375px phone the customer list
   put ~1300px of page furniture — two rows of action buttons
   and six full-width filter selects — above the first customer.
   A rep standing in a market had to scroll past all of it to
   reach the thing they opened the app for.

   The rules here are min-width where they add desktop richness
   and max-width only where a desktop pattern has to be undone
   on small screens. Nothing here changes desktop layout above
   768px except where marked.
   ============================================================ */

/* ============================================================
   1. Page head — actions become a scrollable strip on phones
      instead of wrapping into stacked full-width rows.
   ============================================================ */
@media screen and (max-width: 768px) {
  .page-head {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sp-2);
    align-items: start;
  }
  .page-head h1 {
    font-size: var(--fs-xl);
    margin: 0;
  }
  .page-head .actions {
    display: flex;
    flex-wrap: nowrap;
    gap: var(--sp-2);
    overflow-x: auto;
    scrollbar-width: none;
    /* Bleed to the screen edges so the strip reads as scrollable
       and the last chip is not visually clipped mid-air. */
    margin-inline: calc(var(--sp-4) * -1);
    padding-inline: var(--sp-4);
    padding-bottom: var(--sp-1);
    -webkit-overflow-scrolling: touch;
  }
  .page-head .actions::-webkit-scrollbar { display: none; }

  /* style.css's own mobile block sets `flex: 1 1 auto; min-width: 0` on these
     at .page-head .actions .btn — one step more specific than a `> *` rule —
     which let every button shrink until the labels overlapped. Matched here
     selector-for-selector so the strip scrolls instead of squashing. */
  .page-head .actions > *,
  .page-head .actions .btn,
  .page-head .actions a.btn,
  .page-head .actions button.btn {
    flex: 0 0 auto;
    min-width: max-content;
    width: auto;
    font-size: var(--fs-xs);
    padding: var(--sp-2) var(--sp-3);
    white-space: nowrap;
  }
}

/* ============================================================
   2. Filters — collapsed into a disclosure on phones.
      The markup is a plain <form class="filters">; wrapping it
      would mean touching every page, so instead it is hidden
      behind a sticky "Filters" summary injected by app.js and
      styled here. Desktop is untouched.
   ============================================================ */
@media screen and (max-width: 768px) {
  .filters-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-2);
    width: 100%;
    padding: var(--sp-3) var(--sp-4);
    margin-bottom: var(--sp-3);
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-xs);
    font: inherit;
    font-size: var(--fs-sm);
    font-weight: var(--fw-semi);
    color: var(--text-soft);
    cursor: pointer;
  }
  .filters-toggle .filter-badge {
    background: var(--primary);
    color: #fff;
    border-radius: var(--radius-pill);
    padding: 1px var(--sp-2);
    font-size: var(--fs-3xs);
  }
  .filters[hidden] { display: none !important; }

  .filters {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-2);
    padding: var(--sp-3);
  }
  /* Search and the submit button want the full width; the
     selects pair up two-across so the sheet stays short. */
  .filters > input[type="search"],
  .filters > input[type="text"],
  .filters > .btn,
  .filters > button { grid-column: 1 / -1; }
  .filters select,
  .filters input { font-size: var(--fs-base); } /* ≥16px: stops iOS zooming on focus */
}
/* The toggle is a phone-only affordance. */
@media (min-width: 769px) {
  .filters-toggle { display: none; }
  .filters[hidden] { display: flex !important; }
}

/* ============================================================
   3. Bottom navigation — the five things a rep actually opens.
      Replaces hunting through the hamburger for the daily work.
   ============================================================ */
.bottom-nav { display: none; }

@media screen and (max-width: 768px) {
  .bottom-nav {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 60;
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    background: var(--card);
    border-top: 1px solid var(--border);
    box-shadow: 0 -1px 3px rgba(15, 23, 42, 0.06);
    /* Clear the iOS home indicator. */
    padding-bottom: env(safe-area-inset-bottom, 0);
  }
  .bottom-nav a {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    padding: var(--sp-2) var(--sp-1);
    min-height: 56px;              /* comfortable touch target */
    text-decoration: none;
    color: var(--muted);
    font-size: var(--fs-3xs);
    font-weight: var(--fw-medium);
    line-height: var(--lh-none);
  }
  .bottom-nav a .bn-icon { font-size: 19px; line-height: 1; }
  .bottom-nav a.active { color: var(--primary); }
  .bottom-nav a.active .bn-icon { transform: translateY(-1px); }
  .bottom-nav .bn-count {
    position: absolute;
    transform: translate(14px, -8px);
    background: var(--error);
    color: #fff;
    font-size: 10px;
    font-weight: var(--fw-bold);
    border-radius: var(--radius-pill);
    padding: 0 5px;
    min-width: 16px;
    text-align: center;
  }

  /* Keep the last row of every page clear of the bar. */
  body { padding-bottom: calc(56px + env(safe-area-inset-bottom, 0)); }
}

@media print {
  .bottom-nav { display: none !important; }
  body { padding-bottom: 0 !important; }
}

/* ============================================================
   4. Dense tables → cards on phones.
      .table-cards is opted into per page; the generic .table
      keeps its horizontal scroll so nothing regresses on a
      page that has not been converted yet.
   ============================================================ */
@media screen and (max-width: 768px) {
  .table-cards thead { display: none; }
  .table-cards,
  .table-cards tbody,
  .table-cards tr,
  .table-cards td { display: block; width: 100%; }

  .table-cards tr {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-xs);
    padding: var(--sp-3);
    margin-bottom: var(--sp-3);
  }
  .table-cards td {
    border: 0;
    padding: var(--sp-1) 0;
  }
  /* data-label turns each cell into a labelled row. */
  .table-cards td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-size: var(--fs-3xs);
    font-weight: var(--fw-semi);
    letter-spacing: var(--ls-caps);
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 2px;
  }
  /* Cells carrying nothing but a dash add noise in a card. */
  .table-cards td:empty { display: none; }
}

/* ============================================================
   5. Touch targets — WCAG 2.2 asks for 24px minimum; 44px is
      the comfortable figure for a thumb on a moving train.
   ============================================================ */
@media (pointer: coarse) {
  .btn, .icon-btn-call, .icon-btn-whatsapp, .cell-action-btn, .btn-snooze {
    min-height: 44px;
  }
  .btn-sm { min-height: 38px; }
}

/* ============================================================
   6. Desktop enrichment — wider container and a roomier grid
      once there is room for it.
   ============================================================ */
@media (min-width: 1280px) {
  .container { max-width: 1400px; }
  .stats { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
}

/* ============================================================
   7. Dashboard / Stages / Reports / Activity — mobile layout
      ------------------------------------------------------
      Owned by the dashboard+board+reports conversion.

      Everything here is `@media screen and (...)` on purpose.
      The ≤768px blocks in style.css carry no media type, so
      they also match narrow *print* — copying that pattern
      would turn the printed stage board into a clipped strip
      and the printed day list into a scroller. Scoping to
      `screen` leaves every @media print rule exactly as it was.
   ============================================================ */

/* ---- 7a. Dashboard hero — decorative, so it must not own the
        first screen. Trim the padding, the quote and the figure
        sizes, and lay the three hero figures out as a fixed
        3-up grid instead of a wrapping 32px-gap flex row. ---- */
@media screen and (max-width: 768px) {
  .hero-card {
    padding: var(--sp-35) var(--sp-4);
    margin-bottom: var(--sp-3);
    box-shadow: var(--shadow-sm);
  }
  /* The two blurred blobs are pure decoration and cost a full-card
     repaint on a mid-range Android. */
  .hero-card::before,
  .hero-card::after { display: none; }

  .hero-quote {
    font-size: var(--fs-md);
    line-height: var(--lh-snug);
    margin-bottom: var(--sp-3);
  }
  .hero-stats-row {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--sp-2);
    margin-bottom: var(--sp-25);
  }
  .hero-stat { min-width: 0; }
  .hero-stat-value { font-size: var(--fs-xl); }
  .hero-stat-label {
    font-size: var(--fs-3xs);
    letter-spacing: var(--ls-caps);
    line-height: var(--lh-tight);
    margin-top: var(--sp-05);
  }
  .hero-compare {
    font-size: var(--fs-3xs);
    padding: var(--sp-1) var(--sp-25);
  }
}

/* ---- 7b. Stat tiles stay 2-across all the way down.
        style.css drops .stats to a single column at ≤480px,
        which pushes the day's real work off a 375px screen. ---- */
@media screen and (max-width: 480px) {
  .stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sp-2);
    margin-bottom: var(--sp-4);
  }
  .stat {
    min-width: 0;
    padding: var(--sp-25) var(--sp-25) var(--sp-25) var(--sp-3);
  }
  .stat-value { font-size: var(--fs-xl); margin-top: var(--sp-05); }
  .stat-foot  { line-height: var(--lh-tight); }
}

/* ---- 7c. stages.php board → snap-scrolling carousel.
        style.css stacks .stage-board to one column at ≤768px;
        a rep then scrolls past every stage to reach the last.
        A card per screen with a peek of the next one keeps the
        columns readable and the whole board one swipe away. ---- */
@media screen and (max-width: 768px) {
  .stage-board {
    grid-template-columns: none;
    grid-auto-flow: column;
    /* A definite track size, NOT minmax(0, 86%). With a zero minimum the
       implicit tracks are allowed to shrink to fit the container, so the
       board never overflowed and never scrolled — seven stages collapsed
       to ~40px each and every firm name rendered one letter per line. */
    grid-auto-columns: 86%;
    gap: var(--sp-3);
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: 0;
    /* Room for the card shadow, which an overflow container clips. */
    padding: var(--sp-05) var(--sp-05) var(--sp-3);
    margin-bottom: var(--sp-4);
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    scrollbar-color: var(--border-strong) transparent;
  }
  /* No scroll-snap-stop:always — with ten-plus stages a rep must be able to
     flick several columns at once and still land on a card edge. */
  .stage-board > .stage-board-card {
    scroll-snap-align: start;
    min-width: 0;
  }
  .stage-board::-webkit-scrollbar { height: 6px; }
  .stage-board::-webkit-scrollbar-track { background: transparent; }
  .stage-board::-webkit-scrollbar-thumb {
    background: var(--border-strong);
    border-radius: var(--radius-pill);
  }
  /* A long firm name must wrap inside its column, never widen it. */
  .stage-board-head { min-width: 0; }
  .stage-board-name { min-width: 0; overflow-wrap: anywhere; }
  .stage-customer-row {
    min-width: 0;
    gap: var(--sp-15);
  }
  .stage-customer-row strong { min-width: 0; overflow-wrap: anywhere; }
  /* The followup / days-since chip must stay whole; the name gives way. */
  .stage-customer-row .badge { flex: 0 0 auto; }
}

/* ---- 7d. reports.php charts — one column, and nothing wider
        than the card it sits in. ---- */
@media screen and (max-width: 768px) {
  .chart-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sp-3);
  }
  .chart-card {
    min-width: 0;
    padding: var(--sp-35) var(--sp-3);
  }
  .chart-card.span-2 { grid-column: auto; }
  .chart-canvas-wrap {
    min-width: 0;
    max-width: 100%;
    height: 230px;
  }
  /* Chart.js sizes the canvas itself; this is the backstop for the
     frame between a viewport resize and the next redraw. */
  .chart-canvas-wrap canvas {
    max-width: 100%;
    display: block;
  }
}
@media screen and (max-width: 480px) {
  .chart-canvas-wrap { height: 210px; }
}

/* ---- 7e. activity.php day strip — a real horizontal scroller
        rather than 14 squeezed grid columns. Flex means the
        count of days can change without a new rule. ---- */
@media screen and (max-width: 768px) {
  .activity-strip {
    display: flex;
    grid-template-columns: none;
    gap: var(--sp-15);
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    scroll-snap-type: x proximity;
    padding-bottom: var(--sp-2);
    margin: var(--sp-3) 0 var(--sp-4);
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    scrollbar-color: var(--border-strong) transparent;
  }
  .activity-strip::-webkit-scrollbar { height: 6px; }
  .activity-strip::-webkit-scrollbar-track { background: transparent; }
  .activity-strip::-webkit-scrollbar-thumb {
    background: var(--border-strong);
    border-radius: var(--radius-pill);
  }
  .activity-day {
    flex: 0 0 auto;
    min-width: 56px;
    scroll-snap-align: center;
  }
}

/* ============================================================
   7. Customer pages — customer_view, customer_edit,
      customer_report, customer_brands, court_case_edit.
   ------------------------------------------------------------
   customer_view is the densest screen in the app: details,
   Take Action, insights, court case and the followup timeline
   all on one route. Each of those is now a <details> using the
   existing .collapsible-section pattern, and .view-jump is the
   phone-only strip that jumps between them so a rep does not
   scroll a customer's whole history to reach the form.
   ============================================================ */

/* --- 7a. Section jump strip (customer_view) --------------- */
/* Desktop shows every panel at once, so the strip is phone-only. */
.view-jump { display: none; }

@media screen and (max-width: 768px) {
  .view-jump {
    display: flex;
    gap: var(--sp-2);
    margin: 0 0 var(--sp-3);
    padding-bottom: var(--sp-1);
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .view-jump::-webkit-scrollbar { display: none; }
  .view-jump a {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    min-height: 38px;
    padding: var(--sp-2) var(--sp-3);
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    color: var(--text-soft);
    font-size: var(--fs-2xs);
    font-weight: var(--fw-semi);
    line-height: var(--lh-none);
    text-decoration: none;
    white-space: nowrap;
  }
  .view-jump a:active {
    background: var(--frost);
    border-color: var(--primary-bright);
    color: var(--primary);
  }

  /* The topbar is sticky, so an anchor jump has to stop short of it
     or the panel heading lands underneath the bar. */
  #details, #action, #insights, #court, #history {
    scroll-margin-top: calc(var(--sp-12) + var(--sp-5));
  }
}

/* --- 7b. Quick stage bar ---------------------------------- */
/* style.css pins the select at min-width: 240px, which leaves it
   wider than the room a 375px screen has once the label and the
   bar's own padding are taken off. Let it take a line of its own. */
@media screen and (max-width: 640px) {
  .stage-bar { flex-wrap: wrap; }
  .stage-bar select {
    flex: 1 1 100%;
    width: 100%;
    min-width: 0;
  }
}

/* --- 7c. Form fields -------------------------------------- */
/* .grid-2 already drops to one column at 640px, so every field is
   full width on a phone and nothing here re-does that. What the
   ≤768px block in style.css misses is `tel` — the two mobile
   number boxes on customer_edit — which iOS zooms into on focus
   at anything under 16px. */
@media screen and (max-width: 768px) {
  .form-card input,
  .form-card select,
  .form-card textarea,
  .inline-edit-form input,
  input[type="tel"],
  input[type="url"],
  input[type="time"],
  input[type="month"] {
    font-size: var(--fs-base);   /* ≥16px: stops iOS zooming on focus */
  }
}

/* Comfortable to hit with a thumb. Scoped to the form cards so the
   filter sheets on the list pages keep their compact rows. */
@media (pointer: coarse) {
  .form-card input:not([type="checkbox"]):not([type="radio"]),
  .form-card select,
  .stage-bar select,
  .view-jump a {
    min-height: 44px;
  }
  .form-card .stage-check {
    min-height: 44px;
    padding: var(--sp-2) var(--sp-15);
  }
  .form-card .stage-check input[type="checkbox"] {
    width: 20px;
    height: 20px;
  }
}

/* --- 7d. Followup timeline at 375px ----------------------- */
/* The rich rows carry a timestamp, an outcome and a row of badges.
   Side by side they break mid-date on a phone, so the head stacks
   and each badge is kept whole. */
@media screen and (max-width: 768px) {
  .timeline-date { white-space: nowrap; }
  .timeline-tags .badge { white-space: nowrap; }
  .timeline-tags { gap: var(--sp-1); }
}

@media screen and (max-width: 480px) {
  .timeline-rich .timeline-head {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-05);
    margin-bottom: var(--sp-15);
  }
  .timeline-rich .timeline-outcome { line-height: var(--lh-snug); }
  .timeline-note { padding: var(--sp-15) var(--sp-25); }
}

/* --- 7e. Print -------------------------------------------- */
/* A folded <details> prints nothing. The panels that were open on
   paper before this change carry .print-expand so they still are,
   whatever the screen folded away. Panels that were closed by
   default — Details on a phone, Stage history everywhere — are
   deliberately left folded, exactly as they printed before. */
@media print {
  .view-jump { display: none !important; }
  .collapsible-section.print-expand > *:not(summary) { display: block !important; }
  .collapsible-section.print-expand::details-content {
    content-visibility: visible !important;
    display: block !important;
  }
  .collapsible-section.print-expand > summary .collapsible-chevron { display: none; }
}

/* ============================================================
   reports.php addendum (belongs with section 7d above).
   ------------------------------------------------------------
   The 30-day line and the per-assignee bars need more vertical
   room than the square charts. That used to be an inline
   `style="height:…"` on the wrapper, which no media query could
   reach; it is now a class so the phone can size it down.
   Charts are hidden in print by style.css, so there is no print
   variant to keep in step.
   ============================================================ */
.chart-canvas-wrap.chart-tall { height: 280px; }

@media screen and (max-width: 768px) {
  .chart-canvas-wrap.chart-tall { height: 250px; }
}
@media screen and (max-width: 480px) {
  .chart-canvas-wrap.chart-tall { height: 225px; }
}

/* ============================================================
   9. Admin pages — auth cards, masters, WhatsApp, card tables
      ------------------------------------------------------
      Owned by the admin-pages conversion:
        login.php · install.php · masters.php · users.php ·
        user_edit.php · backup.php · restore.php ·
        date_audit.php · wa_send.php · wa_templates.php ·
        customers_import.php

      Same rule as section 7: everything that only undoes a
      desktop pattern is `@media screen and (...)`, so the
      @media print behaviour in style.css is left untouched.
   ============================================================ */

/* ---- 9a. Card tables must still print as tables.
        Section 4 above sits in a bare `max-width: 768px` query.
        A print media query is evaluated against the *page box*,
        and A4 at the 0.5cm/0.6cm margins style.css sets is only
        ~750px wide — so a converted table would come out of the
        printer as stacked cards, losing the repeated thead that
        style.css's print block deliberately sets up. This puts
        it back; @media print is later, so it wins. ---- */
@media print {
  .table-cards       { display: table !important; }
  .table-cards thead { display: table-header-group !important; }
  .table-cards tbody { display: table-row-group !important; }
  .table-cards tr {
    display: table-row !important;
    width: auto !important;
    background: transparent !important;
    border: 0 !important;
    border-radius: 0 !important;
    box-shadow: none !important;
    padding: 0 !important;
    margin: 0 !important;
  }
  .table-cards td {
    display: table-cell !important;
    width: auto !important;
  }
  .table-cards td[data-label]::before { content: none !important; }
}

/* ---- 9b. The actions cell inside a card.
        .row-actions is right-aligned and nowrap for a table row;
        in a card that pushes the buttons off the edge. ---- */
@media screen and (max-width: 768px) {
  .table-cards td.row-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2);
    text-align: left;
    white-space: normal;
    padding-top: var(--sp-3);
  }
  .table-cards td.row-actions form { display: inline-flex; margin: 0; }
  /* style.css spaces .btn + .btn by hand; the flex gap does it here. */
  .table-cards td.row-actions .btn + .btn { margin-left: 0; }

  /* Backup filenames and CSV codes are long single tokens. */
  .table-cards td code,
  .table-cards td .customer-code-small { overflow-wrap: anywhere; }
}

/* ---- 9c. login.php / install.php.
        These two render their own <head> and never draw a bottom
        nav, so the body padding section 3 reserves for the bar is
        dead space at the end of the form. Below 480px the card
        goes full-bleed — no side border, no radius, no shadow —
        and keeps a comfortable inner gutter. Desktop keeps the
        centred, 440px-constrained card exactly as it was. ---- */
@media screen and (max-width: 768px) {
  .auth-body { padding-bottom: var(--sp-5); }
}
@media screen and (max-width: 480px) {
  .auth-body {
    display: block;
    padding: 0;
    min-height: 100vh;
  }
  .auth-card {
    max-width: none;
    min-height: 100vh;
    margin: 0;
    padding: var(--sp-10) var(--sp-5) var(--sp-8);
    border-width: 0 0 0 0;
    border-radius: 0;
    box-shadow: none;
  }
  .auth-brand { font-size: var(--fs-xl); }
  .auth-card form { margin-top: var(--sp-5); gap: var(--sp-5); }
  /* One full-width primary action, thumb-sized. */
  .auth-card form .btn,
  .auth-card > p > .btn {
    width: 100%;
    justify-content: center;
    min-height: 48px;
  }
  .auth-foot { margin-top: var(--sp-8); }
}

/* ---- 9d. masters.php — the collapsible settings sections.
        The page's own <style> block comes after this file in the
        document, so a plain `.master-section > summary` here
        would lose on equal specificity; matching the .master-head
        class as well takes it. ---- */
.master-section > summary.master-head { list-style: none; }
.master-section > summary.master-head::marker { content: ""; }
.master-section > summary.master-head::-webkit-details-marker { display: none; }

/* The whole header row is the tap target, not just the chevron. */
@media (pointer: coarse) {
  .master-section > summary.master-head { min-height: 44px; }
}
@media screen and (max-width: 768px) {
  .master-section > summary.master-head {
    min-height: 44px;
    padding: var(--sp-3) var(--sp-35);
    gap: var(--sp-25);
  }
  .master-section > summary.master-head .master-title,
  .master-section > summary.master-head strong {
    font-size: var(--fs-base);
    min-width: 0;
    overflow-wrap: anywhere;
  }
  .master-section > summary.master-head .master-chevron { margin-left: auto; }
  .master-section > summary.master-head .muted { min-width: 0; }
}

/* Bulk toolbar: on a phone the two buttons take the row to
   themselves rather than being squeezed against the count. */
.master-toolbar-actions { margin-left: auto; display: flex; gap: var(--sp-2); }
@media screen and (max-width: 768px) {
  .master-toolbar { gap: var(--sp-2); padding: var(--sp-2) 0 var(--sp-3); }
  .master-toolbar-actions { margin-left: 0; width: 100%; }
  .master-toolbar-actions .btn {
    flex: 1 1 0;
    justify-content: center;
    min-height: 44px;
  }
}

/* ---- 9e. wa_send.php — customer picker and message editor.
        wa_send.php carries its own <style> after this file, so
        each selector here is one step more specific than the
        page's (`.panel` ancestor, `.two-col` ancestor). ---- */
@media screen and (max-width: 768px) {
  .panel .wa-cust-results { max-height: 45vh; }
  .panel .wa-cust-result {
    padding: var(--sp-3);
    min-height: 44px;            /* a whole result row is the tap target */
    font-size: var(--fs-sm);
  }
  .panel .wa-cust-card {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-2);
    padding: var(--sp-3);
  }
  .panel .wa-cust-card > div:first-child { width: 100%; min-width: 0; }
  .panel .wa-cust-card > div:first-child strong { overflow-wrap: anywhere; }
  .panel .wa-cust-card .btn { align-self: flex-end; }

  /* 280px of empty textarea buried the Send button below the fold. */
  .two-col #wa-message { min-height: 170px; }
}

/* ---- 9f. customers_import.php — the unknown-stage mapping cells
        hold a select and a code input; both want the full card. ---- */
@media screen and (max-width: 768px) {
  .table-cards .map-choice,
  .table-cards td[data-label="Map to"] input[type="text"] { width: 100%; }
}

/* ---- 9g. backup.php prints a scheduler command in a <pre>;
        it is one long path and must scroll, not stretch. ---- */
@media screen and (max-width: 768px) {
  .form-card pre,
  .panel pre {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
}


/* ============================================================
   7. PRINT GUARD — keep paper as tables
   ------------------------------------------------------------
   A4 at this app's print margins is roughly 756px wide, so a
   bare `@media (max-width: 768px)` matches PAPER as well as
   phones. style.css hit this exact trap in v0.14 and reversed
   its mobile block inside @media print for `.table`; nothing
   did the same for the newer `.table-cards`, so a converted
   list would have printed as a column of cards.

   Every mobile block above is now `@media screen and (...)`,
   which fixes it at the source. This block stays as a backstop
   for any rule appended later that forgets the `screen`.
   ============================================================ */
@media print {
  .table-cards,
  .table-cards tbody,
  .table-cards tr,
  .table-cards td { display: revert !important; }

  .table-cards thead { display: table-header-group !important; }
  .table-cards tr {
    page-break-inside: avoid;
    background: none !important;
    border: 0 !important;
    border-radius: 0 !important;
    box-shadow: none !important;
    padding: 0 !important;
    margin: 0 !important;
  }
  /* The card-mode field labels must not print in front of every cell. */
  .table-cards td[data-label]::before { content: none !important; }
  .table-cards td:empty { display: table-cell !important; }

  /* Mobile-only chrome that must never reach paper. */
  .bottom-nav,
  .filters-toggle,
  .view-jump { display: none !important; }
  .filters[hidden] { display: revert !important; }
  body { padding-bottom: 0 !important; }
}
/* ============================================================
   10. Followup lists · customer list · category report · trash
   ------------------------------------------------------------
   Added by the card conversion of includes/followup_views.php
   (overdue / due_today / upcoming), customers.php,
   category_report.php and trash.php.

   Nothing here restyles a component for its own sake. Every rule
   undoes a *table* rule that a card physically cannot honour —
   a 140px column width, a centred column, a hidden phone line —
   or keeps a control reachable that the card pattern would
   otherwise bury. Tokens only, and desktop is untouched.
   ============================================================ */

/* The "select every row shown" tick lives in the <thead>. Card mode
   hides the head, so the tick needs a visible label there; on desktop
   the bare checkbox with its tooltip is the established header. */
.bulk-all-label {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semi);
  color: var(--text-soft);
  text-transform: none;
  letter-spacing: normal;
  cursor: pointer;
}
.bulk-all-label > span { display: none; }

/* ---- 10a. Card reading order and the card headline.
        A dense row leads with a code or a tick column; a card has to
        lead with the name the rep is scanning for, then the phone,
        then the two badges that say what to do about it. Flex `order`
        does that without moving one cell in the markup, so the print
        column order, the sort links and every JS selector are
        untouched. Cells with no `order` keep DOM order after these. ---- */
@media screen and (max-width: 768px) {
  .table-cards tr {
    display: flex;
    flex-direction: column;
    position: relative;
  }
  .table-cards td.customer-cell { order: -4; }
  .table-cards td.cell-phone    { order: -3; }
  .table-cards td.cell-stage    { order: -2; }
  .table-cards td.cell-followup { order: -1; }

  /* The followup lists lead their row with the quick-log button; in a
     card the action belongs at the end, where every other card puts it. */
  .table-cards td.col-action-cell { order: 1; text-align: left; }

  /* style.css clamps this cell to 140px and the firm line to 15ch so a
     six-column table still fits a phone. A card is the full width. */
  .table-cards td.customer-cell {
    width: auto;
    max-width: none;
    padding-bottom: var(--sp-1);
  }
  .table-cards td.customer-cell .customer-firm,
  .table-cards td.customer-cell .customer-contact { max-width: none; }
  .table-cards td.customer-cell .customer-firm {
    font-size: var(--fs-base);
    line-height: var(--lh-snug);
  }
  .table-cards td.customer-cell .customer-contact { font-size: var(--fs-xs); }

  /* Stage and next-followup are centred as table columns; as labelled
     card lines they have to align with everything above them. */
  .table-cards td.cell-stage,
  .table-cards td.cell-followup { text-align: left; }

  /* The digits are the point of the row. style.css hides .phone-number
     at this width because a table column only had room for the call and
     WhatsApp icons — a card has room for the number and the buttons. */
  .table-cards .phone-number {
    display: block;
    font-weight: var(--fw-semi);
  }
  .table-cards td.cell-phone .contact-buttons { margin-top: var(--sp-2); }

  /* .table-followup sets `padding: 8px 6px !important` on every cell for
     the dense layout; the card's own padding already provides that. */
  .table-cards.table-followup td { padding: var(--sp-1) 0 !important; }

  /* .table-scroll + .table-sticky draw a rule above every cell, which
     inside a card reads as a line between each field. */
  .table-scroll .table-cards tbody td { border-top: 0; }
}

/* ---- 10b. customers.php — the tick column and the bulk bar.
        Both have to survive card mode: the per-row tick without
        pushing the customer name off the top of the card, and the
        bulk bar without hiding under the fixed bottom nav. ---- */
@media screen and (max-width: 768px) {
  /* Tick sits in the card's top-right corner, 44px of hit area. */
  .table-cards[data-customers-table] td.col-tick {
    position: absolute;
    top: 0;
    right: 0;
    width: auto;
    margin: 0;
    padding: var(--sp-3);
    z-index: 1;
  }
  .table-cards[data-customers-table] td.col-tick input {
    width: 20px;
    height: 20px;
  }
  /* Keep a long firm name clear of it. */
  .table-cards[data-customers-table] td.customer-cell { padding-right: var(--sp-12); }

  /* The code is already a line inside the customer cell at this width,
     so its own column would print it twice in the card. */
  .table-cards[data-customers-table] td.col-code { display: none; }

  /* Re-show just the select-all header cell as a slim bar above the
     cards. Every other heading stays hidden with the rest of the head. */
  .table-cards[data-customers-table] thead { display: block; }
  .table-cards[data-customers-table] thead tr {
    display: flex;
    align-items: center;
    background: var(--card-soft);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: none;
    padding: var(--sp-2) var(--sp-3);
    margin-bottom: var(--sp-3);
  }
  .table-cards[data-customers-table] thead th { display: none; }
  .table-cards[data-customers-table] thead th.col-tick {
    display: block;
    position: static;         /* .table-sticky makes header cells sticky */
    width: auto;
    padding: 0;
    background: none;
    box-shadow: none;
    text-align: left;
  }
  .bulk-all-label > span { display: inline; }

  /* A card list scrolls with the page. Left inside the desktop
     `calc(100vh - 22rem)` box it would be two scrollers fighting for
     the same thumb, and on a 375px screen that box is three cards tall.
     Desktop keeps its capped list and sticky header. */
  .table-scroll-cards {
    max-height: none;
    min-height: 0;
    overflow: visible;
    border: 0;
    border-radius: 0;
    background: transparent;
  }

  /* .bulk-bar is `position: sticky; bottom: 0`, which parks it behind
     the fixed bottom nav. Lift it clear of the bar and its safe-area
     inset, keep it under the nav's z-index, and cap it so a phone
     never loses the whole list to the toolbar. */
  .bulk-bar {
    bottom: calc(56px + env(safe-area-inset-bottom, 0px));
    z-index: 55;
    max-height: 45vh;
    overflow-y: auto;
  }
}

/* ---- 10c. Print guard, second half.
        The blocks above that put card tables back to real tables do it
        with `.table-cards td { display: table-cell !important }` — one
        class more specific than `.no-print`, so without this the tick,
        level, snooze and assignee cells would reappear on paper while
        their `<th>`s stayed hidden, and every printed row would shift a
        column. Field staff print these lists; restore both. ---- */
@media print {
  .table-cards tr.no-print,
  .table-cards th.no-print,
  .table-cards td.no-print { display: none !important; }
}
/* Same trap for the columns style.css drops on narrow paper. Scoped to
   the same width so wide paper keeps printing every column. */
@media print and (max-width: 768px) {
  .table-cards th.hide-on-mobile,
  .table-cards td.hide-on-mobile { display: none !important; }
}


/* ============================================================
   8. PRINT — undo the mobile treatment paper inherits
   ------------------------------------------------------------
   style.css's `📱 MOBILE OVERHAUL` block is a bare
   `@media (max-width: 768px)` with no media type, and A4 at
   this app's margins is ~756px — so paper matches it. The
   printed followup lists were therefore rendering in phone
   mode: the quick-log button force-shown with
   `display: inline-flex !important`, and customer names
   clamped to 140px / 15ch so a name like "KOTDWAR KIDS ZONE
   (DM)" wrapped to three lines across a full sheet.

   Paper is wide. Give it back the room.
   ============================================================ */
@media print {
  /* The ⚡ quick-log button is a control, not information — and it
     printed as a filled circle on every single row. */
  .cell-action-btn,
  .col-action-cell .cell-action-btn { display: none !important; }

  /* With the button gone the leading column holds nothing: its code
     chip is hidden on narrow widths and the code already prints under
     the customer name. Drop the column and give the width to the
     names and the remarks people write in. */
  th.col-action-cell,
  td.col-action-cell { display: none !important; }

  /* Names get the full column width back. */
  .customer-cell-th,
  .customer-cell {
    width: auto !important;
    max-width: none !important;
  }
  .customer-cell .customer-firm,
  .customer-cell .customer-contact {
    max-width: none !important;
    word-break: normal !important;
    overflow-wrap: normal !important;
  }
  .customer-cell .customer-firm { font-size: 11pt !important; }

  /* The code stays under the name — that is where it prints today,
     and the column that used to carry it has gone. */
  .customer-cell .customer-code-line {
    display: inline-block !important;
    border: 0 !important;
    background: none !important;
    padding: 0 !important;
  }
}
