/* ============================================================
   RESPONSIVE — everything that changes on a narrow screen.

   The application was built desktop-only: one media query in 2,430 lines when
   the August 2026 audit measured it (G29). That is not a cosmetic gap. Time
   Log is the screen an employee needs at the end of a day away from a desk,
   and the target operating model assumes mobile time entry; today the sidebar
   alone takes 240px of a 375px phone and the two-column layouts render a
   400px detail panel beside a table on a 360px viewport.

   It lives in ONE file, loaded last, for two reasons. Scattering media queries
   through eighteen page stylesheets is how the desktop rules drifted apart in
   the first place - `.slide-panel` was defined twice, at two widths, and the
   later file won silently. And a reader asking "what does this look like on a
   phone" has one place to read rather than eighteen.

   Two breakpoints, and no more:
     900px  the two-column layouts stop fitting side by side
     640px  a phone: the sidebar goes off-canvas and controls go full width

   Everything here is a max-width override of a desktop rule, so the desktop
   rendering is untouched by construction.
   ============================================================ */

/* ============================================================
   ≤ 900px — tablets, split screens, small laptops
   ============================================================ */
@media (max-width: 900px) {

  /* The two-column pattern, all fourteen of them. Matching on the class
     suffix rather than listing the modules: the list would go stale the first
     time a nineteenth page was added, and a stale list here renders as a
     broken screen rather than a failing check. */
  [class$="-layout"] {
    flex-direction: column;
    height: auto;
    overflow: visible;
  }

  /* The detail panel stops being a column and becomes a sheet over the list.
     Width, not display, so the open/close transition still runs. */
  .slide-panel {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 60;
    width: 0;
    transition: transform 200ms ease;
    transform: translateX(100%);
    box-shadow: -8px 0 24px rgba(0, 0, 0, 0.16);
  }
  /* Scoped through the layout, because twelve page stylesheets set their own
     panel width that way - .invoices-layout .slide-panel.open is 480px for the
     line items, .commlog-layout is 420px - and those are deliberate, not
     duplication. A bare .slide-panel.open here is (0,2,0) and loses to every
     one of them; matching their shape makes this (0,3,0) too, and load order
     does the rest. Found by measuring a 400px panel on a 375px screen. */
  [class$="-layout"] .slide-panel.open {
    width: min(420px, 100vw);
    min-width: 0;
    transform: translateX(0);
    border-radius: 0;
    border-left: 1px solid var(--border);
  }
  [class$="-layout"] .slide-panel-inner { width: 100%; }

  /* The list keeps its own scroll rather than inheriting a calc() height that
     assumed a header, a page header and a filter bar of fixed heights. */
  [class$="-table-wrap"] {
    border-radius: var(--radius-lg);
    max-height: none;
  }

  .kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  .modal { max-width: calc(100vw - 32px); }
  .modal-lg { max-width: calc(100vw - 32px); }
}

/* ============================================================
   ≤ 640px — a phone held in one hand
   ============================================================ */
@media (max-width: 640px) {

  /* The sidebar goes off-canvas. It is 240px of a 375px viewport, and the
     alternative - collapsing it to icons - needs an icon per route, which this
     codebase does not have and would be a worse thing to invent than a drawer. */
  .sidebar {
    position: fixed;
    top: 0;
    bottom: 0;
    /* `left`, not `transform: translateX(-100%)`. The transform version did not
       apply - not from the stylesheet and not set inline - and rather than
       keep a drawer whose closed state could not be demonstrated, this uses
       the one property whose effect is a number anyone can read back off the
       element. A 240px slide on a phone does not need compositor animation. */
    left: calc(-1 * var(--sidebar-w));
    z-index: 80;
    transition: left 220ms ease;
  }
  #app-shell.nav-open .sidebar { left: 0; }

  .nav-scrim {
    position: fixed;
    inset: 0;
    z-index: 70;
    background: rgba(0, 0, 0, 0.45);
    border: 0;
    padding: 0;
  }

  /* Only shown below this breakpoint. Above it the sidebar is always there and
     a button that opens what is already open is worse than no button. */
  .nav-toggle { display: inline-flex; }

  #main-content { padding: 14px; }

  .header { padding: 0 14px; gap: 8px; }
  .header-title { font-size: 15px; }

  .page-header {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
  }
  .page-header-actions { flex-wrap: wrap; }

  /* A filter bar that scrolls sideways hides its own controls. Stack.
     
     These selectors were `.filter-bar` until step 4 was run against the real
     application, and `.filter-bar` DOES NOT EXIST: every module names its own
     bar - fifteen of them, ending -search, -filter-bar or -filters. The rule
     styled nothing, and the browser check that "verified" it had been run
     against a div this session created with the class it assumed. Testing your
     own fixture confirms the assumption, not the software.
     
     Nothing in the gate could have caught it: rule 19 asserts every class the
     JavaScript names exists in CSS, and this is the opposite direction - a
     selector naming a class nothing uses. */
  [class$="-search"],
  [class$="-filter-bar"],
  [class$="-filters"] {
    flex-direction: column;
    align-items: stretch;
  }
  [class$="-search"] .form-control,
  [class$="-filter-bar"] .form-control,
  [class$="-filters"] .form-control,
  [class$="-search"] select,
  [class$="-filter-bar"] select,
  [class$="-filters"] select,
  [class$="-search"] input,
  [class$="-filter-bar"] input,
  [class$="-filters"] input { width: 100%; max-width: none; }
  .filter-compact { max-width: none; }

  .kpi-grid { grid-template-columns: 1fr; }

  /* Full-bleed. A 420px sheet on a 360px screen is a horizontal scrollbar. */
  [class$="-layout"] .slide-panel.open { width: 100vw; }

  /* The modal fills the width the overlay leaves it, and keeps its corners.
     An earlier version said `width: 100vw; border-radius: 0` for a full-bleed
     sheet - and .modal-overlay is a centred flex container with 20px padding,
     so the 100vw was clamped to 335 anyway and only the squared corners
     survived. A rule whose visible effect is the half you did not intend is
     worse than no rule. */
  .modal {
    width: 100%;
    max-width: 100%;
    max-height: calc(100vh - 40px);
  }
  .modal-body { max-height: calc(100vh - 172px); }
  .modal-footer .btn { flex: 1; }

  /* Tables keep their columns and scroll, rather than being reflowed into
     cards. A card layout would need a per-module decision about which column
     is the title and which are secondary - eighteen decisions, none of them
     checkable - and a horizontally scrolled table still shows the same data
     the desktop does. */
  .table-wrapper { -webkit-overflow-scrolling: touch; }
  thead th, tbody td {
    padding-left: 10px;
    padding-right: 10px;
    /* Scroll, do not wrap. Without this a 375px viewport breaks 2026-08-29
       across two lines and a three-word task title across three, so eight rows
       fill four screens and the horizontal scroll - the whole reason for
       keeping the columns - never happens. */
    white-space: nowrap;
  }
  /* Free text has no useful width. There is no per-column class to target -
     the only one this codebase sets is td-actions - so the cap is on every
     cell, which is what a nowrap table needs anyway: one long note must not
     make the whole table twenty screens wide. */
  tbody td {
    max-width: 240px;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  tbody td.td-actions { max-width: none; overflow: visible; }

  /* Touch targets. 34px is fine for a mouse and small for a thumb. */
  .btn { min-height: 40px; }
  .nav-item { padding-top: 11px; padding-bottom: 11px; }
}
