/**
 * mobile.css — shared mobile layer for 1008.
 *
 * INVARIANT I1: Desktop (>=769px) is frozen. Every rule here lives inside a
 * `@media (max-width: 768px)` / `@media (max-width: 480px)` block, or is one of
 * the provably desktop-neutral preamble declarations at the top of the file.
 * Nothing here may alter the >=769px cascade.
 *
 * Loaded LAST on every page, after all other stylesheets, so its mobile rules
 * win the source-order tie at equal specificity.
 *
 * Spec: docs/specs/MOBILE_RESPONSIVENESS_SPEC.md
 * Phase 0 (foundation): §5.2 shell, §5.6 touch targets, §5.7 16px, §5.9 viewport.
 */

/* ── Preamble — desktop-neutral (§5.2 items 1-2) ───────────────────────────── */
html { -webkit-text-size-adjust: 100%; }
* { -webkit-tap-highlight-color: rgba(0, 0, 0, 0.08); }   /* D17 */
:root { --vh: 1vh; }   /* set by mobile.js; consumed only inside mobile queries */

/* ── Drawer breakpoint (§5.1) — must match side-menu.css's 1024 block ───────────
   side-menu.css clears `.main-content { margin-right }` once the menu becomes an
   off-canvas drawer, but TWO page stylesheets redefine `.main-content` with their
   own margin (hr-management.css: 280px, manage-emdot.css) and, loading after
   side-menu.css at equal specificity, win on source order — which squeezed those
   pages into a ~110px column. mobile.css loads last, so clearing it here fixes every
   such page at once, including any added later. */
@media (max-width: 1024px) {
  .main-content { margin-right: 0; margin-left: 0; }
}

@media (max-width: 768px) {

  /* ── §5.7 The 16px rule (I4) ────────────────────────────────────────────────
     Below 16px Safari zooms on focus and never zooms back. Force every editable
     control to ≥16px on the phone.

     Dozens of offenders are single-class rules (e.g. `.filter-select`,
     `.location-input`, `.date-input input`) that out-rank a bare `input` blanket.
     Rather than enumerate them, we lift the selector's own specificity above any
     single-class rule using attribute `:not()`s: each `:not([attr])` adds a
     (0,1,0) unit, so `input:not(...):not(...)` computes to (0,2,1) — beating any
     `.foo` (0,1,0) or `.foo input` (0,1,1) offender. All inside ≤768 ⇒ desktop
     (I1) is untouched. The `:not`s also exclude non-text controls (checkbox,
     radio, range, color) whose sizing is set in §5.6. */
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]),
  select:not([size]),
  textarea:not([data-fixed-size]) { font-size: 16px; }

  /* emda-select's base rule is all-!important (side-menu.css :301-313), so the
     override must match its 4-class specificity AND carry !important (§5.4). */
  .side-menu .menu-user-info .emda-selector .emda-select { font-size: 16px !important; }

  /* ── §5.2 Page shell & global hygiene ─────────────────────────────────────── */
  html { overflow-x: clip; }   /* D4 / I3 — clip (not hidden) so sticky descendants survive */

  .main-content { padding: 12px; min-height: auto; }   /* was 20px + 100vh (D14) */
  .container    { padding: 12px 10px; min-height: auto; }   /* D16 — mobile.css wins, keep identical app-wide */

  /* Safe-area (notch / home indicator).
     ALWAYS give env() an explicit fallback. There is no `safe-area-inset-inline`
     variable (only -left/-right/-top/-bottom), and an unknown env() with no fallback
     makes the whole declaration "invalid at computed-value time" — which does not fall
     back to the earlier `padding: 12px`, it resets the property to 0. That silently
     stripped .main-content's padding on every page. */
  .main-content {
      padding-left: max(12px, env(safe-area-inset-left, 0px));
      padding-right: max(12px, env(safe-area-inset-right, 0px));
  }
  .side-menu          { padding-bottom: env(safe-area-inset-bottom, 0px); }
  .mobile-action-bar  { padding-bottom: max(10px, env(safe-area-inset-bottom, 0px)); }

  /* ── §5.9 Viewport units (D14) ────────────────────────────────────────────── */
  .main-content, .container, body { min-height: auto; }
  /* dvh first, then JS --vh fallback: on modern browsers the last valid
     declaration (the calc) wins with the JS-driven value; on old ones dvh is
     dropped and 100vh-equivalent calc applies. */
  .side-menu { height: 100dvh; height: calc(var(--vh, 1vh) * 100); }
  .ui-modal-dialog, .modal-content { max-height: 88dvh; }

  /* ── §5.6 Touch targets — 44×44 min; no mobile query may shrink below desktop ─ */
  .filter-btn, .export-btn, .clear-btn, .control-btn,
  .search-btn, .clear-search           { min-height: 44px; }
  .filter-select, .bulk-action-select  { min-height: 44px; }
  .pagination-btn, .pagination-number  { min-width: 44px; height: 44px; }
  .table-actions .btn,
  .data-table td .btn                  { min-height: 44px; padding: 10px 14px; font-size: 14px; }
  .close-btn, .remove-item-btn,
  .remove-pluga-btn, .remove-group-btn { min-width: 44px; min-height: 44px; }
  .release-opt, .tray-flip-btn, .restore-btn { min-height: 40px; padding: 9px 14px; }  /* dense tray: 40px deliberate (§8.4) */
  input[type="checkbox"], input[type="radio"] { width: 22px; height: 22px; }
  a, button, [role="button"], summary  { touch-action: manipulation; }   /* kills 300ms delay; NOT on signature canvas (§8.5) */

  /* ── Utilities (§6) ───────────────────────────────────────────────────────── */
  .desktop-only { display: none !important; }
}

/* ── §5.4 Side menu — h1 clearance & touch (Phase 1) ─────────────────────────── */
@media (max-width: 768px) {
  /* D7 — the fixed 50px hamburger sits at the top-right; in RTL the page h1 also
     starts at the right edge, directly under it. Reserve room. `.page-title-row`
     is the real fix (added per page in §7); this selector list is the safety net. */
  /* The hamburger is physically top-RIGHT (side-menu.css: right:20px) at all times;
     in this RTL app the page title also starts at the right edge, directly under it.
     Reserve physical right space.

     Do NOT enumerate wrapper chains here: pages nest their heading differently
     (items_list is .container > .items-list-container > .page-header > h1, others are
     .container > h1), and any list of ancestors silently misses a page. Match the
     heading itself, wherever it sits. */
  .main-content h1,
  .admin-header h1,
  .page-title-row { padding-right: 62px; }   /* 50px btn + 12px gap */

  /* emda-select base rule is all-!important, so match specificity + !important. */
  .side-menu .menu-user-info .emda-selector .emda-select { min-height: 44px !important; }
  .side-restore-btn, #restore-original-emda-btn { min-width: 44px; min-height: 44px; }
}

/* ── §5.5 Modals → bottom sheets, toasts → bottom ───────────────────────────── */
@media (max-width: 768px) {
  /* UIModal (the shared component) */
  .ui-modal-overlay { align-items: flex-end; padding: 0; }
  .ui-modal-dialog {
      max-width: 100%;
      width: 100%;
      max-height: 88dvh;
      border-radius: var(--radius-card) var(--radius-card) 0 0;
  }
  .ui-modal-header h2 { white-space: normal; overflow: visible; }   /* was nowrap+ellipsis */
  .ui-modal-close { width: 44px; height: 44px; }                    /* was 36 */
  .ui-modal-footer { flex-direction: column-reverse; gap: 10px; }
  .ui-modal-footer .ui-btn { width: 100%; min-height: 48px; }

  /* The 12 bespoke modals (allocations, catalog, templates, signature, qr, …) do
     not inherit UIModal. !important is needed (several set width inline / at high
     specificity) and is scoped to ≤768 so I1 holds. Verify each at 390px. */
  .modal-content,
  .signature-modal-content,
  .modal-overlay > *,
  .qr-confirm-content {
      width: 100% !important; max-width: 100% !important;
      margin: auto 0 0 !important;
      max-height: 88dvh; overflow-y: auto;
      border-radius: var(--radius-card) var(--radius-card) 0 0;
  }

  /* Toasts + the two other fixed notifications → out of the hamburger's band,
     down into the natural glance zone (D10). */
  .ui-toast-container {
      top: auto;
      bottom: calc(16px + env(safe-area-inset-bottom, 0px));
      width: calc(100vw - 24px);
      left: 12px; right: 12px; transform: none;
  }
  .emda-feedback {
      top: auto;
      bottom: calc(16px + env(safe-area-inset-bottom, 0px));
      left: 12px; right: 12px; transform: none;
      width: auto; text-align: center;
  }
}

@media (max-width: 768px) and (prefers-reduced-motion: no-preference) {
  .ui-modal-overlay.is-open .ui-modal-dialog { animation: ui-sheet-up 0.22s ease; }
}
@keyframes ui-sheet-up { from { transform: translateY(100%); } to { transform: none; } }

/* ── §5.3 Tables → card stacks (the centrepiece) ────────────────────────────
   Generalised from mekabel-form.css:435-485. Applies to `.data-table` and to an
   opt-in `.card-stack` class (for the bespoke tables not named `.data-table`).
   `<thead>` stays in the DOM (display:none) so screen readers keep table context
   — do NOT delete it server-side (§10.4). */
@media (max-width: 768px) {
  .table-container,
  .items-table-container {
      overflow-x: visible;            /* kill the horizontal scroller (D1) */
      margin: 0;
      border-radius: var(--radius-sm);
  }

  .data-table, .card-stack {
      min-width: 0 !important;        /* D1 — the ONE justified !important; overrides
                                         inline style="min-width:800px" (mekablim_list) */
      display: block;
      font-size: 14px;
      border-collapse: separate;
  }
  .data-table thead, .card-stack thead { display: none; }
  .data-table tbody, .card-stack tbody { display: block; }

  /* A flex COLUMN (not block) so the headline can lead and actions can trail no
     matter which column they occupy in the table — e.g. audit_log's headline is the
     6th column, and left in DOM order it would render in the middle of the card. */
  .data-table tr, .card-stack tr {
      display: flex;
      flex-direction: column;
      position: relative;             /* anchor for .cell-check */
      background: var(--color-surface);
      border: 1px solid var(--color-border);
      border-radius: var(--radius-sm);
      box-shadow: var(--shadow-soft);
      padding: 10px 12px;
      margin-bottom: 8px;
  }

  /* Rows read as a tight "label: value" line — label and value GROUPED at the start
     (not pushed to opposite edges, which read as scattered text). No per-row divider
     lines; even vertical rhythm carries the list. */
  .data-table td, .card-stack td {
      display: flex;
      justify-content: flex-start;
      align-items: baseline;
      gap: 6px;
      padding: 3px 0;
      min-width: 0;                   /* D2 */
      white-space: normal;            /* D2 */
      overflow-wrap: anywhere;
      border: none;
      text-align: start;
      color: var(--color-text);       /* the value — darker than the label */
      font-weight: 600;
  }

  .data-table td::before, .card-stack td::before {
      content: attr(data-label) ":";
      font-weight: 400;
      color: var(--color-text-muted);
      flex: 0 0 auto;
      font-size: 13px;
  }
  /* A cell with no data-label (spacer / action cell) renders full-bleed, no gutter */
  .data-table td:not([data-label])::before,
  .card-stack td:not([data-label])::before { content: none; }

  /* (a) Headline row — the card title, on its own line with a hairline separator
     before the label/value list. Always first, wherever its column sits. */
  .data-table td.cell-title, .card-stack td.cell-title {
      order: -1;
      display: block;
      font-size: 15px;
      font-weight: 700;
      color: var(--color-text);
      margin-bottom: 6px;
      padding-bottom: 8px;
      padding-inline-end: 40px;       /* clear the absolutely-positioned checkbox */
      border-bottom: 1px solid var(--color-border);
  }
  .data-table td.cell-title::before, .card-stack td.cell-title::before { content: none; }

  /* (b) Actions cell — full-width wrapping button row, always last. */
  .data-table td.cell-actions, .card-stack td.cell-actions {
      order: 10;
      display: flex;
      flex-wrap: wrap;
      gap: 8px;
      padding-top: 12px;
      border-top: 1px solid var(--color-border);
  }
  .data-table td.cell-actions::before, .card-stack td.cell-actions::before { content: none; }
  .data-table td.cell-actions .btn, .card-stack td.cell-actions .btn,
  .table-actions .btn {
      flex: 1 1 auto;
      min-height: 44px;               /* undoes D11's ~16px */
      padding: 10px 14px;
      font-size: 14px;
      justify-content: center;
  }
  .table-actions { flex-direction: row; flex-wrap: wrap; }

  /* (c) Checkbox cell — floated into the card's top corner. */
  .data-table td.cell-check, .card-stack td.cell-check {
      position: absolute;
      top: 8px;
      left: 8px;                      /* physical LEFT — the RTL title starts at the
                                         right edge, so inset-inline-start (= right in
                                         RTL) would collide with it */
      padding: 0;
      border: none;
      margin: 0;
      z-index: 1;
  }
  .data-table td.cell-check::before, .card-stack td.cell-check::before { content: none; }
  .data-table td.cell-check input[type="checkbox"],
  .card-stack td.cell-check input[type="checkbox"] {
      width: 24px; height: 24px;
      margin: 8px;                    /* 24px box inside a 40px tap slop */
  }

  /* (d) Empty cells render as a lonely label — hide them. */
  .data-table td:empty, .card-stack td:empty { display: none; }
  .data-table td:has(> .cell-empty:only-child),
  .card-stack td:has(> .cell-empty:only-child) { display: none; }

  /* Column budget — low-value cells hidden until the per-card "הצג עוד" toggle
     (mobile.js, §5.3) adds .card-expanded to the row. */
  .data-table tr:not(.card-expanded) td.cell-secondary,
  .card-stack tr:not(.card-expanded) td.cell-secondary { display: none; }
  .card-more-cell { display: block; padding: 0; border: none; }
  .card-more-cell::before { content: none; }
  .card-more-btn {
      margin-top: 10px;
      width: 100%;
      min-height: 40px;
      background: none;
      border: 1px dashed var(--color-border-strong);
      border-radius: var(--radius-control);
      color: var(--color-primary);
      font-family: var(--font);
      font-size: 14px;
      cursor: pointer;
  }
}

/* ── Compact list card (`.card-compact`) ─────────────────────────────────────
   The label:value card above is right for LOW-VOLUME record pages (manage_users,
   audit_log, pluga_integrity) where you read one record. It is the wrong shape for
   HIGH-VOLUME scanning lists: measured at 390px it costs ~290px per item (~2.5 per
   screen) on a 1,333-row list, and repeats the same six labels on every card.

   `.card-compact` is the scanning variant: one headline line (name + status chip),
   one unlabelled muted meta line, everything else behind `הצג עוד`. ~80px per item.
   Inline editors are suppressed here (see .cell-editable + mobile.js) — editing goes
   through tap → context menu → the full edit modal. */
@media (max-width: 768px) {
  .card-compact tbody tr {
      display: flex;
      /* MUST restate row: the base card sets flex-direction:column (so its headline can
         lead regardless of column position), and without this the compact card inherits
         it and every meta value stacks onto its own line. */
      flex-direction: row;
      flex-wrap: wrap;
      align-items: center;
      gap: 3px 14px;   /* column gap separates label:value pairs on the meta line */
      padding: 9px 12px;
      margin-bottom: 6px;
  }
  .card-compact td { padding: 0; border: none; }

  /* Visual order is set explicitly — the DOM column order (name, serial, qty,
     status, …) is not the order we want to read on a phone. An unclassed cell
     defaults to the detail band, never to the front of the card. */
  .card-compact td              { order: 4; }
  .card-compact td.cell-title    { order: 0; }
  .card-compact td.cell-chip     { order: 1; }
  /* Zero-height, full-width item that deterministically ends line 1. Relying on
     flex-basis arithmetic instead is fragile — when title + chip + the first meta
     happen to fit within a pixel, the meta silently joins the headline row and
     collides with the absolutely-positioned checkbox. Inserted by mobile.js on
     phones only, so no extra column ever exists on desktop. */
  .card-compact td.card-break {
      /* MUST restate display: this cell is empty by design and the §5.3
         `td:empty { display: none }` rule would otherwise swallow it. */
      display: block;
      order: 2;
      flex: 0 0 100%;
      height: 0;
      padding: 0;
      margin: 0;
      border: none;
  }
  .card-compact td.card-break::before { content: none; }
  .card-compact td.cell-meta     { order: 3; }
  .card-compact td.cell-editable,
  .card-compact td.cell-secondary { order: 4; }
  /* Same order as the meta cells (and appended last in the DOM) so the toggle rides
     the END of the meta line instead of costing a full 32px row per card. */
  .card-compact .card-more-cell  { order: 3; }
  /* Actions sit last, on their own line, without the base card's top border. */
  .card-compact td.cell-actions {
      order: 5;
      flex: 1 1 100%;
      padding-top: 6px;
      border-top: none;
      gap: 6px;
  }
  .card-compact td.cell-actions .btn,
  .card-compact td.cell-actions .edit-link { flex: 0 0 auto; }

  /* Line 1 — headline + status chip. The title's basis reserves the chip's width so
     line 1 is always exactly those two and the meta cells wrap to line 2. */
  .card-compact td.cell-title {
      /* Natural width: .card-break already ends line 1, so the title no longer needs
         to reserve the chip's width via calc — which was forcing a short title and its
         chip onto separate rows and costing a whole line per card. */
      flex: 0 1 auto;
      font-size: 14.5px;
      font-weight: 700;
      margin: 0;
      padding: 0;
      border: none;
      min-width: 0;
  }
  /* Only reserve the checkbox gutter on cards that actually have one. The chip sits
     at the END of line 1, which in RTL is the physical LEFT — exactly where the
     absolutely-positioned checkbox lives — so it needs the gutter as much as the
     title does. */
  .card-compact tr:has(td.cell-check) td.cell-title,
  .card-compact tr:has(td.cell-check) td.cell-chip { padding-left: 36px; }

  /* Row-level actions (history) belong in the tap menu, not on every card. */
  .card-compact td.cell-title .history-link,
  .card-compact td.cell-title .history-modal-btn { display: none; }

  /* Grows to eat the remainder of line 1 (the badge itself stays flush to the end via
     justify-content), which is what forces the meta cells onto line 2.
     USE .cell-chip ONLY for a value that reads on its own — a status badge ("מוקצה",
     "פנוי"). Anything numeric (a count, an ID) must be .cell-meta so it keeps its
     label; an unlabelled "1" floating in the corner tells the reader nothing. */
  .card-compact td.cell-chip {
      flex: 0 0 auto;
      margin-inline-start: auto;   /* push to the end of the headline row */
      display: flex;
      align-items: center;
      font-size: 11px;
  }
  .card-compact td.cell-chip::before { content: none; }

  /* Line 2 — compact "label: value" pairs.
     These KEEP their labels. An unlabelled meta line reduces to floating values —
     "1", "7722744", "פלס״ם" — which is unreadable: the reader cannot tell a personal
     ID from an item count. Density comes from putting the pairs on one wrapping line
     at a small size, NOT from deleting the labels. The label itself delimits each
     pair, so no middot separator is needed. */
  .card-compact td.cell-meta {
      flex: 0 1 auto;
      gap: 4px;
      font-size: 12.5px;
      font-weight: 600;
      color: var(--color-text);
  }
  .card-compact td.cell-meta::before {
      content: attr(data-label) ":";
      font-size: 11.5px;
      font-weight: 400;
      color: var(--color-text-muted);
  }
  /* Badges inside the meta line read as plain text, not as pills. */
  .card-compact td.cell-meta .quantity-badge,
  .card-compact td.cell-meta .item-serial {
      background: none;
      color: inherit;
      padding: 0;
      font-size: 12px;
  }

  /* Editable cells: the live input is suppressed on the phone (it competes with
     scrolling and inflates every card); mobile.js renders its value as text. */
  .card-compact td.cell-editable { flex: 1 1 100%; font-size: 12px; color: var(--color-text-muted); }
  .card-compact td.cell-editable::before { font-size: 11px; }
  .card-compact td.cell-editable .location-autocomplete-container,
  .card-compact td.cell-editable input { display: none; }
  .card-compact td.cell-editable .cell-readonly-value { color: var(--color-text); }

  .card-compact .card-more-cell { flex: 0 0 auto; margin-inline-start: auto; }
  .card-compact .card-more-btn {
      min-height: 24px;
      width: auto;
      font-size: 12px;
      border: none;
      background: none;
      text-align: end;
      padding: 0 2px;
      margin: 0;
  }
  /* Expanded rows fall back to the labelled layout for the detail rows. */
  .card-compact tr.card-expanded td.cell-secondary {
      flex: 1 1 100%;
      font-size: 13px;
      font-weight: 600;
      color: var(--color-text);
      gap: 6px;
  }
  .card-compact tr.card-expanded td.cell-secondary::before {
      font-weight: 400;
      color: var(--color-text-muted);
      font-size: 12px;
  }
}

/* ── §7.1 items_list — the JS-positioned fixed panels + the touch context menu ─── */
@media (max-width: 768px) {
  /* Six position:fixed dropdowns are positioned from getBoundingClientRect() against
     cells that just moved; clamp them into the viewport. */
  .location-autocomplete-dropdown,
  .date-picker-dropdown,
  .inspection-date-dropdown-content,
  .catalog-items-dropdown-content,
  .pluga-dropdown-content,
  .counting-method-dropdown-content {
      inset-inline: 8px;
      max-width: calc(100vw - 16px);
      min-width: 0;
  }

  /* The row context menu is positioned at the tap point on desktop; on a phone that
     lands half off-screen. Make it a bottom sheet (JS still sets left/top inline, so
     these need !important). */
  .context-menu {
      position: fixed !important;
      inset-inline: 0 !important;
      left: 0 !important; right: 0 !important;
      top: auto !important;
      bottom: 0 !important;
      width: 100% !important;
      max-width: 100% !important;
      border-radius: var(--radius-card) var(--radius-card) 0 0;
      padding-bottom: max(8px, env(safe-area-inset-bottom, 0px));
      z-index: var(--z-modal-overlay);
      box-shadow: 0 -4px 24px rgba(0,0,0,.18);
  }
  .context-menu .context-menu-item { min-height: 52px; display: flex; align-items: center; font-size: 15px; }
}

/* ── §7.2 catalog.php — force the existing grid (card) view on phones ─────────── */
@media (max-width: 768px) {
  .view-toggle { display: none; }
  .catalog-list-view { display: none !important; }
  .catalog-grid { display: grid !important; }
}

/* ── §5.8 D13 — the flat .search-bar / .search-form variant (never had a mobile
   rule; .search-form min-width:300px overflowed a 390px phone). ───────────────── */
@media (max-width: 768px) {
  .search-bar   { flex-direction: column; align-items: stretch; padding: 14px 12px; gap: 10px; }
  .search-form  { min-width: 0; flex-direction: column; align-items: stretch; gap: 10px; width: 100%; }
  .search-form > * { width: 100%; }
  .live-search-feedback { min-width: 0; }
}

/* ══ §8 The Form (client/index.php) — targeted fixes only ═══════════════════════
   I2: the existing mobile layout is preserved. These are defects inside it. */
@media (max-width: 768px) {

  /* §8.1 The מחלקה field was ~100px narrower than every sibling. `.dept-autocomplete`
     carries `width: calc(100% - 100px)` to leave room for the inline label — but at
     ≤768 the label is hidden and every other input is widened to 100%, and the
     wrapper was never overridden. Most visible defect on the phone. */
  .mekabel-data .dept-autocomplete { width: 100%; }

  /* §8.2 Autocomplete dropdowns were clipped. `.items-table-container` had
     `overflow-x: auto`, and per CSS `overflow-y: visible` computes to `auto` when the
     other axis is not visible — making it a clip box for every absolutely-positioned
     dropdown inside. The horizontal scroll is vestigial here: at ≤768 the line item is
     already a flex COLUMN, so nothing can overflow sideways. */
  .items-table-container { overflow: visible; }

  /* A dropdown near the bottom of the screen would sit behind the soft keyboard;
     .dropdown-flip-up (set by index.js) flips it above its input. */
  .autocomplete-dropdown.dropdown-flip-up,
  .serial-autocomplete-dropdown.dropdown-flip-up { top: auto; bottom: 100%; }

  /* §8.2 A form number like 23-9164976 was truncated to a ~21px sliver.
     The top row is also `.form-data`, not an h1, so the §5.4 heading clearance did not
     cover it — the fixed hamburger (x 320-370, y 20-70) sat directly ON the date
     input, making its right half untappable. Reserving that 62px leaves too little for
     both fields side by side, so the row is allowed to wrap instead of crushing them. */
  .form-data { padding-right: 62px; flex-wrap: wrap; }
  .form-data .form-number-input,
  .form-data .date-input { flex: 1 1 auto; min-width: 150px; }
  .form-number-input input { width: 100%; min-width: 70px; }

  /* §8.3 Template groups had no mobile rules at all — the box cost 26px of width and
     its header was a non-wrapping space-between row. */
  .template-group { padding: 8px 8px 4px; }
  .template-group-header { flex-wrap: wrap; gap: 8px; }
  .template-group-name { min-width: 0; overflow-wrap: anywhere; }
  .template-group .remove-group-btn { min-height: 40px; padding: 9px 14px; font-size: 14px; }

  /* §8.4 Removed-items tray had no mobile rules either. Giving .release-toggle its own
     full-width line is deliberate: the two options stay side by side (the whole point
     of a segmented control) but the row no longer depends on the pluga name's length. */
  .removed-item { align-items: stretch; }
  .release-toggle { margin-inline-start: 0; width: 100%; }
  .release-opt { flex: 1; min-height: 40px; font-size: 14px; white-space: normal; }
  .restore-btn { min-height: 40px; padding: 8px 12px; }
  .tray-flip-btn { flex: 1; min-height: 40px; }
  .removed-summary { min-height: 48px; font-size: 15px; }

  /* §8.5 Signature. touch-action:none is REQUIRED on a drawing surface or the browser
     may claim the gesture as a scroll mid-stroke. The fullscreen/keyboard affordances
     are desktop/stylus features with no touch fallback — hide them on a phone. */
  .signature-modal-canvas { touch-action: none; max-height: none; aspect-ratio: 2 / 1; }
  .signature-modal-content { max-height: 92dvh; }
  .fullscreen-signature-btn, .keyboard-controls, .signature-instructions-desktop { display: none; }

  /* §8.7 The submit button is the page's single most important control and required
     scrolling past every item. sticky (not fixed) keeps it in flow, so it occludes
     nothing and needs no body-padding hack. */
  form { padding-bottom: 8px; }
  .submit-btn {
      position: sticky;
      bottom: max(8px, env(safe-area-inset-bottom, 0px));
      z-index: 5;
      min-height: 52px;
      font-size: 1.05em;
      box-shadow: 0 4px 16px rgba(40, 167, 69, .35);
  }

  /* §8.8 Form history — reclaim 16px of width; keep the toggle thumb-sized. */
  .history-group { padding: 10px 12px; }
  .form-history-toggle { min-height: 48px; }
}

/* ══ §5.11 Pagination ═══════════════════════════════════════════════════════════
   renderPagination() already windows the strip, but at 390px it still wraps to two
   rows of buttons. Leave prev / current−1 / current / current+1 / next. The active
   page is a <span>, not an <a>, so the sibling selectors must work on both. */
@media (max-width: 768px) {
  .pagination { flex-wrap: wrap; gap: 8px; justify-content: center; }
  .pagination-ellipsis { display: none; }
  .pagination-numbers .pagination-number { display: none; }
  .pagination-numbers .pagination-number.active,
  .pagination-numbers .pagination-number.active + .pagination-number,
  .pagination-numbers .pagination-number:has(+ .active) { display: inline-flex; }
  .pagination-btn, .pagination-number { min-width: 44px; height: 44px; font-size: 15px; }
  .pagination-info { flex-basis: 100%; text-align: center; font-size: 14px; }
}

/* ══ §5.10 Bulk-action bars ═════════════════════════════════════════════════════
   A bulk bar that scrolls away with the list is useless on a phone. body.has-bulk-bar
   (set by mobile.js) reserves room so the last card is never permanently covered —
   the classic mistake with this pattern. */
@media (max-width: 768px) {
  /* Only bars that are SHOWN ON SELECTION are pinned. hr-management's `.bulk-actions`
     is always in the document, so pinning it would permanently steal ~100px of a
     844px screen for a control the user has not invoked — it stays in flow. */
  .bulk-actions-bar, .mobile-action-bar {
      position: fixed;
      inset-inline: 0;
      bottom: 0;
      z-index: 880;                      /* below the menu overlay (890) */
      background: var(--color-surface);
      border-top: 1px solid var(--color-border-strong);
      box-shadow: 0 -4px 16px rgba(0, 0, 0, .12);
      padding: 10px 12px max(10px, env(safe-area-inset-bottom, 0px));
      display: flex; flex-direction: column; gap: 8px;
      margin: 0;
  }
  .bulk-actions-bar .btn, .mobile-action-bar .btn { width: 100%; min-height: 48px; }
  .bulk-actions { flex-direction: column; gap: 8px; }
  .bulk-actions > * { width: 100%; }
  body.has-bulk-bar { padding-bottom: 130px; }
  /* pluga_pool's bar is already `position: sticky; bottom: 0`, which stays in flow and
     needs none of the above — excluded deliberately. */
}

/* ══ §5.8 Filter sheet ══════════════════════════════════════════════════════════
   Collapsed by default on phones; mobile.js injects the toggle so no page markup
   changes. Three container shapes exist in the wild and all three are named here. */
@media (max-width: 768px) {
  .mobile-filters-toggle {
      display: flex;
      align-items: center;
      gap: 8px;
      width: 100%;
      min-height: 48px;
      margin-bottom: 10px;
      padding: 10px 14px;
      background: var(--color-primary);
      color: var(--color-text-invert);
      border: none;
      border-radius: var(--radius-control);
      font-family: var(--font);
      font-size: 15px;
      font-weight: 600;
      cursor: pointer;
  }
  .mobile-filters-toggle .filter-count-badge {
      background: var(--color-danger);
      color: var(--color-text-invert);
      border-radius: var(--radius-pill);
      padding: 1px 8px;
      font-size: 12px;
  }
  .mobile-filters-toggle .toggle-icon { margin-inline-start: auto; transition: transform var(--transition-fast); }
  .mobile-filters-toggle[aria-expanded="true"] .toggle-icon { transform: rotate(180deg); }

  .filter-sheet[hidden] { display: none; }

  /* Name EVERY filter-row shape. allocations.php uses `.controls-section > .filters`,
     which is neither of the two shared shapes — left out, its `flex-direction: row;
     flex-wrap: nowrap` kept two 150px groups side by side while their inputs were
     280px wide, so the controls overlapped and ran off the edge. */
  .filters-row,
  .controls-section .filters { flex-direction: column; flex-wrap: wrap; gap: 10px; }

  .filter-group { width: 100%; max-width: none; min-width: 0; }
  .filter-group input,
  .filter-group select { width: 100%; max-width: none; box-sizing: border-box; }

  .filter-actions { flex-direction: column; gap: 8px; }
  .filter-actions > * { width: 100%; }

  /* allocations' action row (רענן / הוסף פלוגה) sits in the same section. */
  .controls-section .filter-actions,
  .controls-section .action-buttons { flex-direction: column; gap: 8px; width: 100%; }
  .controls-section .action-buttons > * { width: 100%; min-height: 44px; }
}

/* ══ §7.6 allocations.php — the ONE table that must NOT become a card stack ═════
   Its columns are DATA (one per pluga), generated dynamically, not fields. Card-
   stacking a matrix destroys it, so this is the justified exception to the
   "no horizontal scrollers" decision. */
@media (max-width: 768px) {
  /* §5.3 sets `.table-container { overflow-x: visible }` to kill the scrollers on
     card-stacked pages — which would also kill the one scroller we still need. */
  .table-container:has(.allocations-table) {
      overflow-x: auto;
      -webkit-overflow-scrolling: touch;
  }
  /* Pin the item name so a row stays identifiable while scrolling across plugot.
     RTL: the leading edge is the physical RIGHT. */
  .allocations-table .item-column {
      position: sticky;
      right: 0;
      background: var(--color-surface);
      z-index: 3;
  }
  .allocations-table th.item-column { z-index: 4; }
  /* An editable numeric cell must not be a 12px iOS-zoom trigger. */
  .allocated-input { min-height: 44px; text-align: center; }

  .allocations-mobile-hint {
      display: flex;
      gap: 8px;
      align-items: flex-start;
      margin: 10px 0 0;
      padding: 10px 12px;
      background: var(--color-warning-soft);
      border-radius: var(--radius-sm);
      font-size: 13px;
      color: var(--color-text);
  }
}

/* ══ §7.10 Form pages (add_user, edit_user, hr_mekabel_form, login, change_password) */
@media (max-width: 768px) {
  /* user-management.css has NO media queries at all — `.form-row { display:flex }`
     never wrapped, so two fields sat side by side at 390px. */
  .form-row { flex-direction: column; gap: 14px; }
  .form-row > * { width: 100%; }

  /* hr-management.css's own @768 block forces `min-width: 180px` on form buttons,
     which overflows a stacked column. */
  .hr-form .btn { min-width: 0; width: 100%; }

  /* login.css: 100px of dead space above the fold on a ~670px screen. */
  .login-container { margin: 24px 12px; padding: 20px; max-width: none; }

  /* Action rows stack instead of squeezing. */
  .form-actions, .form-buttons { flex-direction: column; gap: 10px; }
  .form-actions > *, .form-buttons > * { width: 100%; min-height: 48px; }
}

/* ══ §7.12 Print pages — layout deliberately left alone (fixed-geometry documents).
   Only the on-screen action bar is made usable. */
@media (max-width: 768px) {
  .no-print { display: flex; flex-direction: column; gap: 10px; }
  .no-print .btn, .no-print button, .no-print a.btn { width: 100%; min-height: 48px; }
}

@media (min-width: 769px) {
  .mobile-only { display: none !important; }
}
