/* ============================================================
   Phones and tablets — the WGL screens below a desk.

   Plan of record: docs/superpowers/plans/2026-10-23-mobile-responsive.md.

   LOADED LAST (see appsettings.bundles.json), and that is the whole design of this
   file. Every rule here restates an existing one at a narrower width or for a
   finger, so a tie on specificity goes to the responsive rule and the desktop files
   keep their own structure untouched. A tie is not always enough: legacy-shapes.css
   scopes its rules `.s-WglPage .x`, and several list rows carry a modifier
   (`.wgl-rlist-6 .wgl-saved`) that outranks the base collapse in builder.css — which
   is exactly how those rows kept six desktop tracks on a phone. Each restatement
   below matches or beats the selector it overrides, and says so where it matters.

   Same rules as the files beside it: tokens only, never a colour literal, and never
   a star followed by a slash inside a comment.

   Three conditions, matching the breakpoints the other files already use:

     phone         max-width: 47.99rem   Serenity's own isMobileView() switch (768px)
     narrow phone  max-width: 30rem      where a 210px auto-fit grid is one column
     touch         pointer: coarse       input method, not width — an iPad at 1024px
                                         still has a finger on it

   Responsiveness, not a redesign: the 2px outlines, the hard offset shadows, the
   black title band and the yellow rules all stay.
   ============================================================ */


/* ══ TOUCH ══════════════════════════════════════════════════════════════════
   Measured on width it would miss the till's iPad in landscape, which is the one
   device here that is never used with a mouse. */
@media (pointer: coarse) {

  /* iOS zooms the page into any focused field set below 16px, and the viewport no
     longer forbids zoom (it blocked pinch-zoom on Android, WCAG 1.4.4). GLOBAL on
     purpose: a Serenity CRUD dialog under Setup has inputs too, and a zoom on focus
     there is the same jump. Checkboxes and radios have no text to size, and the
     till's scan box is already larger (1.15rem) and must stay the biggest field. */
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not(.wgl-scan-input),
  select,
  textarea {
    font-size: 16px !important;
  }

  /* 44px floor on every control a WGL screen draws. `min-height`, never `height`:
     a label that wraps onto a second line must not be clipped. The till already
     does this for itself (`--pos-touch` in screens.css); this is the same floor for
     the other nine screens and every dialog. */
  .s-WglPage .wgl-btn,
  .wgl-dlg .wgl-btn,
  .s-WglPage .s-Toolbar .tool-button,
  .s-WglPage .wgl-pager-btn,
  .s-WglPage .wgl-cart-tab {
    min-height: 44px;
  }

  /* `.wgl-btn-sm` is a row action, and a row action is still a finger's target. It
     keeps its smaller type; it gains the height. */
  .s-WglPage .wgl-btn-sm,
  .wgl-dlg .wgl-btn-sm {
    min-height: 44px;
    padding-inline: 0.75rem;
  }

  /* A link drawn as a button has no intrinsic vertical centring the way <button>
     does, so the extra height would sit under the word. */
  .s-WglPage a.wgl-btn,
  .wgl-dlg a.wgl-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* Chips are FIXED at 30px in legacy-shapes.css (`height`, not `min-height`), so
     the height has to be released before the floor can apply. */
  .s-WglPage .wgl-chip,
  .wgl-dlg .wgl-chip {
    height: auto;
    min-height: 44px;
  }

  /* Glyph buttons keep their light look and get the hit area (Apple HIG: extend the
     hit region beyond the ink). Not the zoom glyph on a gallery tile: 44px is more
     than half of a 5rem photograph, and the tile itself already opens the image. */
  .s-WglPage .wgl-icon-btn:not(.wgl-thumb-zoom),
  .wgl-dlg .wgl-icon-btn:not(.wgl-thumb-zoom) {
    min-width: 44px;
    min-height: 44px;
  }

  /* Every field on a WGL screen and in a WGL dialog. */
  .s-WglPage .wgl-field input.editor:not([type="checkbox"]),
  .s-WglPage .wgl-field select.editor,
  .wgl-dlg .wgl-field input.editor:not([type="checkbox"]),
  .wgl-dlg .wgl-field select.editor {
    min-height: 44px;
  }

  /* The sidebar drawer: ~37px links, the thing pressed on every page change. */
  .s-sidebar-link {
    min-height: 44px;
  }

  /* No hover on glass — the 1px "lift" fired on tap and stayed until the next tap
     elsewhere, so a pressed button looked raised rather than pressed. */
  .s-WglPage .wgl-btn:hover:not(:disabled),
  .wgl-dlg .wgl-btn:hover:not(:disabled),
  .s-WglPage .s-Toolbar .tool-button:hover:not(.disabled) {
    transform: none;
    box-shadow: var(--wgl-pop);
  }

  /* No 300ms double-tap wait on the controls pressed at speed. */
  .s-WglPage button,
  .s-WglPage .tool-button,
  .wgl-dlg button {
    touch-action: manipulation;
  }
}


/* ══ NO HOVER ═══════════════════════════════════════════════════════════════
   The gallery tile's zoom glyph is revealed on hover and is opacity 0 otherwise, so
   on a tablet it did not exist — the same fault the supplier directory's message
   button was fixed for (see `.wgl-crm-row-chat`). */
@media (hover: none) {
  .wgl-thumb .wgl-thumb-zoom {
    opacity: 1;
  }
}


/* ══ PHONE ══════════════════════════════════════════════════════════════════ */
@media (max-width: 47.99rem) {

  /* ── The shell ─────────────────────────────────────────────
     sidebar.css pads the content 2.2rem on every side, `!important` — 70px of a
     360px phone spent on gutter before a single panel has drawn its own padding.
     Same selector, same `!important`, later in the cascade. The top stays: the
     floating hamburger sits there. */
  section.content {
    padding: 0.75rem 0.75rem 1rem !important;
  }

  /* The hamburger was 40×40; 44 is the floor everywhere else. */
  .s-sidebar-toggler {
    width: 44px;
    height: 44px;
  }

  /* Serenity's frame inset — the title band, the tabs, the category rules on a
     Setup grid or form all hang off it. Same (0,1,0) as serenity-shapes.css. */
  .s-DataGrid,
  .s-Panel {
    --wgl-frame-inset: 14px;
  }

  /* ── The page toolbar ──────────────────────────────────────
     Serenity's toolbar wraps, but raggedly: every child carries a right and bottom
     margin (`.s-Toolbar > *` in common-theme), each `.tool-group` wraps on its own
     inside the bar, and `align-items: flex-start` lets an icon button and a button
     whose label broke onto two lines sit at different heights on one row. On the
     till, Products and Supplier accounts — eight to eleven buttons — that read as
     three loose clusters of mismatched pills ("the buttons at the top are not
     aligned").

     On a phone it is a GRID: the groups dissolve (`display: contents`, so their
     buttons become the grid's own cells), every cell is the same width, a row's
     cells stretch to one height, and the label is centred in it. Every button stays
     visible — a sideways scroll strip would hide half the screen's actions behind an
     edge nobody thinks to swipe.

     `[hidden]` has to be restated: Serenity hides a button whose `visible` callback
     says no with the `hidden` ATTRIBUTE (Fluent.toggle), and the UA's
     `[hidden] { display: none }` loses to any author `display` — without this every
     conditional button (Open session beside Close session, the cashier's money
     buttons) would come back. Bootstrap's clearfix `::after` would also take a cell. */
  .s-WglPage > .s-Toolbar {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(9rem, 100%), 1fr));
    gap: 8px;
    align-items: stretch;
    /* Room under the last row for the 2px offset shadow, and the same left edge as
       the panels below (the page content has no inset of its own). */
    padding: 12px 0 4px;
    margin: 0;
  }

  .s-WglPage > .s-Toolbar::before,
  .s-WglPage > .s-Toolbar::after,
  .s-WglPage > .s-Toolbar > .clear {
    display: none;
  }

  .s-WglPage > .s-Toolbar > .tool-group {
    display: contents;
  }

  .s-WglPage > .s-Toolbar > * {
    margin: 0;
  }

  .s-WglPage > .s-Toolbar .tool-button {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 0;
    min-height: 44px;
    margin: 0;
    padding: 8px 10px;
    text-align: center;
  }

  .s-WglPage > .s-Toolbar .tool-button[hidden] {
    display: none !important;
  }

  .s-WglPage > .s-Toolbar .tool-button .button-inner {
    justify-content: center;
    align-items: center;
    line-height: 1.25;
    min-width: 0;
    overflow-wrap: anywhere;
  }

  /* The black band on a WGL screen. (0,2,0), as in legacy-shapes.css. */
  .s-WglPage > .grid-title {
    padding: 12px 14px;
  }

  .s-WglPage > .grid-title .title-text {
    font-size: 1.2rem;
  }

  /* Panels: 22px each side is 12% of the phone. `--wgl-panel-pad-x` moves WITH the
     padding, because the filter band bleeds by exactly that value — repaint one
     without the other and the band stops short of the edge (the note in
     legacy-shapes.css records that exact 2px sliver). */
  .s-WglPage .wgl-panel {
    --wgl-panel-pad-x: 14px;
    padding: 16px var(--wgl-panel-pad-x);
  }

  /* ── Panel heads ───────────────────────────────────────────
     A flex row with `space-between` and no wrap: a title and three buttons simply
     ran off the right edge of the panel (Expenses, Jobs, Import, and the builder's
     items head with its sort and its 14rem search). The actions take a line of their
     own under the title rather than squeezing it. (0,2,0) beats the base (0,1,0)
     and ties the `:has()` variant in builder.css, which also wraps. */
  .s-WglPage .wgl-panel-head {
    flex-wrap: wrap;
    row-gap: 0.6rem;
  }

  .s-WglPage .wgl-panel-actions {
    flex-wrap: wrap;
  }

  /* The builder's items head: sort and search are `nowrap` and the search box is a
     fixed 14rem. Each takes the full line and the box fills it. */
  .s-WglPage .wgl-items-sort,
  .s-WglPage .wgl-items-search {
    flex: 1 1 100%;
    white-space: normal;
  }

  .s-WglPage .wgl-items-search .editor {
    flex: 1 1 auto;
    width: auto;
    min-width: 0;
  }

  /* ── Archive / report list rows ────────────────────────────
     builder.css collapses `.wgl-saved` to two tracks at 860px, but the Reports
     modifiers below are (0,2,0) against its (0,1,0) and kept their desktop tracks —
     ~37rem of fixed columns inside a 360px phone. Restated at their own
     specificity; the group, sub and item rows already collapse themselves. */
  .wgl-rlist-6 .wgl-saved,
  .wgl-rlist-5 .wgl-saved {
    grid-template-columns: minmax(0, 1fr) auto;
    row-gap: 0.2rem;
  }

  /* ── The sticky totals bar ─────────────────────────────────
     Builder, rental, expenses, statement and dashboard all draw `.wgl-totals`, and
     it is STICKY at the foot of the viewport. Five to seven figures wrapping into
     four rows covered a third of a phone, permanently. On a phone it is one line
     that scrolls sideways inside itself; every figure is still there, and the edge
     cutting through the next one is the cue that there is more. (0,2,0), as the
     legacy-shapes.css rule it tightens. */
  .s-WglPage .wgl-totals {
    flex-wrap: nowrap;
    gap: 18px;
    padding: 10px 14px;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: thin;
    -webkit-overflow-scrolling: touch;
  }

  .s-WglPage .wgl-totals > * {
    flex: 0 0 auto;
  }

  .s-WglPage .wgl-totals .wgl-total-value {
    font-size: 1.0667rem;
    white-space: nowrap;
  }

  /* The note is `flex-basis: 100%` so it wraps under the figures on a desk. On one
     scrolling line that would make it a screen-wide item; it reads as the last cell
     instead. */
  .s-WglPage .wgl-totals .wgl-total-note {
    flex: 0 0 auto;
    max-width: 16rem;
    align-self: center;
  }

  /* ── Tables the markup gives no scroller ───────────────────
     The import report's five tables and the jobs history nowrap their cells and had
     no wrapper, so a long path pushed the PAGE sideways. A table made `block` scrolls
     inside its own box (the rows get an anonymous table wrapper), which is the one
     way to do it without touching the markup. */
  .s-WglPage .wgl-import-table,
  .s-WglPage .wgl-jobs-runs {
    display: block;
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }

  /* ── Dashboard ─────────────────────────────────────────────
     The money-flow chart is one grid column per month: twelve of them in a 290px
     panel is 24px a month with four bars in each. It keeps a readable floor and
     scrolls inside itself instead. */
  /* The floor is the CAPTION, not the bars: each month carries "$43,830.00" or
     "12 q · $43,830.00" under it, and at 3.25rem that figure bled into the next
     month's. 4.75rem holds a five-figure amount at the caption's 0.66rem; the
     caption may still break at its spaces. Six months then scroll inside the panel
     — the panel, and the page, stay the width of the phone. */
  .s-WglPage .wgl-flow {
    grid-auto-columns: minmax(4.75rem, 1fr);
    max-width: 100%;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    padding-bottom: 0.25rem;
    -webkit-overflow-scrolling: touch;
  }

  .s-WglPage .wgl-flow-sub,
  .s-WglPage .wgl-flow-label {
    overflow-wrap: anywhere;
  }

  /* Legends hold one swatch per series; a long label ("Approved consignments on
     the ladder: 85") must break rather than set the panel's width. */
  .s-WglPage .wgl-legend {
    gap: 0.4rem 0.9rem;
  }

  .s-WglPage .wgl-key {
    min-width: 0;
    overflow-wrap: anywhere;
  }

  .s-WglPage .wgl-segbar,
  .s-WglPage .wgl-slice-track {
    max-width: 100%;
  }

  /* Nothing in a panel may set the panel's width. A panel is a flex or grid item on
     every screen, and an item's automatic minimum is its content's min-content — one
     unbreakable chart caption or select was enough to push the card, and the page,
     past the phone's edge. */
  .s-WglPage .wgl-panel {
    min-width: 0;
  }

  /* A breakdown row is label | bar | count | value with ~19rem of the four fixed,
     which left the BAR — the point of the row — zero wide. The three words share a
     line and the bar takes the full width under them. Children, in order: label,
     track, count, value. */
  .s-WglPage .wgl-slice {
    grid-template-columns: minmax(0, 1fr) auto auto;
    row-gap: 0.3rem;
  }

  .s-WglPage .wgl-slice > .wgl-slice-label { grid-column: 1; grid-row: 1; }
  .s-WglPage .wgl-slice > .wgl-slice-count { grid-column: 2; grid-row: 1; }
  .s-WglPage .wgl-slice > .wgl-slice-value { grid-column: 3; grid-row: 1; }
  .s-WglPage .wgl-slice > .wgl-slice-track { grid-column: 1 / -1; grid-row: 2; }

  /* The period control beside the dashboard's title drops under it whole. */
  .s-WglPage .wgl-dash-head-control {
    margin-left: 0;
    flex-wrap: wrap;
  }

  /* ── POS ───────────────────────────────────────────────────
     A cart line is five tracks with ~23rem fixed — thumb, the ± pair, the 7.5rem
     price box and remove — so on a phone the description track got zero width and
     the line overflowed the panel. Two rows: what it is (thumb, description, remove),
     then what it costs (quantity, price). Children, in order: thumb, desc, qty,
     price, remove. `:not(.wgl-space-line)` — the rental's space line has no thumb
     and is handled below. */
  .wgl-pos .wgl-cart-line:not(.wgl-space-line) {
    grid-template-columns: 2.75rem minmax(0, 1fr) 7.5rem;
    row-gap: 0.4rem;
  }

  .wgl-pos .wgl-cart-line:not(.wgl-space-line) > :nth-child(1) { grid-column: 1; grid-row: 1; }
  .wgl-pos .wgl-cart-line:not(.wgl-space-line) > :nth-child(2) { grid-column: 2; grid-row: 1; }
  .wgl-pos .wgl-cart-line:not(.wgl-space-line) > :nth-child(5) {
    grid-column: 3;
    grid-row: 1;
    justify-self: end;
  }
  .wgl-pos .wgl-cart-line:not(.wgl-space-line) > :nth-child(3) { grid-column: 1 / 3; grid-row: 2; }
  .wgl-pos .wgl-cart-line:not(.wgl-space-line) > :nth-child(4) { grid-column: 3; grid-row: 2; }

  /* The description may take two lines now that it has the room; one line with an
     ellipsis at 200px cut "Zara wool coat, double-breas…" before the noun. */
  .wgl-pos .wgl-cart-title {
    white-space: normal;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
  }

  /* The till's "did you mean" list: thumb | 9rem ref | description | price left the
     description nothing. The reference sits above the description. Children: thumb,
     ref, desc, price. */
  .wgl-pos .wgl-match {
    grid-template-columns: 2.75rem minmax(0, 1fr) auto;
    row-gap: 0.1rem;
  }

  .wgl-pos .wgl-match > :nth-child(1) { grid-column: 1; grid-row: 1 / span 2; }
  .wgl-pos .wgl-match > :nth-child(2) { grid-column: 2; grid-row: 1; }
  .wgl-pos .wgl-match > :nth-child(3) { grid-column: 2; grid-row: 2; }
  .wgl-pos .wgl-match > :nth-child(4) { grid-column: 3; grid-row: 1 / span 2; }

  /* "3 item(s) · TOTAL · $42.00" plus a subtotal line when discounted: four cells
     at a 1.6rem gap, no wrap. */
  .wgl-pos .wgl-cart-total {
    flex-wrap: wrap;
    gap: 0.3rem 1rem;
  }

  /* STICKY MONEY. Two things on the till must never need hunting for on a phone:
     what the customer owes and the button that takes it.

     The cart's black total bar sticks to the bottom of the viewport while the cart
     is being scrolled. It sits inside the checkout panel, so it releases where the
     panel ends — and the tender follows it in that panel, so by the time the
     payment is on screen the bar is in its own place and nothing stacks.

     The checkout buttons then stick to the bottom while the tender is on screen
     (they are its last child, so they release with it). Submit as PAID is never
     below the fold. The two cannot overlap: the total's natural position is above
     the tender, so it has always let go first.

     Both bleed to the panel's edges so the stuck bar reads as a tray across the
     card rather than a loose strip floating inside it. */
  .wgl-pos .wgl-checkout-panel > .wgl-cart-total {
    position: sticky;
    bottom: 0;
    z-index: 4;
    box-shadow: 0 -6px 12px -8px var(--s-wgl-edge);
  }

  .wgl-pos .wgl-tender > .wgl-checkout-actions {
    position: sticky;
    bottom: 0;
    z-index: 4;
    margin-inline: calc(-1 * var(--wgl-panel-pad-x, 14px));
    padding: 0.6rem var(--wgl-panel-pad-x, 14px) calc(0.6rem + env(safe-area-inset-bottom, 0px));
    background: var(--s-wgl-surface);
    border-top: var(--wgl-edge-thin);
  }

  /* Submit as PAID stays a full-width 56px bar; on a phone the row under it is two
     buttons, and Void keeps its own size at the far end. */
  .s-WglPage .wgl-pos .wgl-checkout-pay {
    min-height: 52px;
  }

  /* The orders head: title, count and the Today/All scope chips on one non-wrapping
     line. The chips take their own line under the title. The same component is the
     supplier account's Items head (scope + "show sold") and the cash-flow pane's
     direction chips, so it is not scoped to the till. */
  .s-WglPage .wgl-orders-scope {
    flex-wrap: wrap;
    margin-inline-start: 0;
  }

  /* THE ORDERS FILTERS. Five selects and a Clear at `flex: 1 1 8.5rem` with an
     8.5rem minimum — and a <select>'s own minimum is its longest option ("As the
     chips say", "Not fulfilled", "Any method"), which the 44px till padding widened
     again. The row ran past the panel. Two to a line, each allowed to be narrower
     than its longest option (the open list still shows it in full). */
  .wgl-pos .wgl-orders-filters .wgl-field {
    flex: 1 1 calc(50% - 0.75rem);
    min-width: 0;
  }

  .wgl-pos .wgl-orders-filters select.editor,
  .wgl-pos .wgl-orders-search .editor,
  .wgl-pos .wgl-orders-head .wgl-field .editor {
    width: 100%;
    min-width: 0;
    max-width: 100%;
  }

  .wgl-pos .wgl-orders-filters > .wgl-btn {
    flex: 1 1 100%;
  }

  /* An order row's tool cell holds up to seven 44px glyphs (lines, settle, deliver,
     cancel, clawback, receipt, return) and never wrapped — ~330px in a ~290px row,
     the last of them past the edge. On a phone the cell takes the row's full width
     and wraps, start-aligned under the order it acts on. */
  .s-WglPage .wgl-saved > .wgl-saved-tools {
    grid-column: 1 / -1;
    flex-wrap: wrap;
    justify-content: flex-start;
  }

  /* Supplier accounts needs nothing here: `.wgl-crm` is one column below 62rem and
     its directory row places its three cells explicitly (name | owed | a 44px
     message glyph), which fits a phone as it stands. */

  /* The archive's segmented status track is an `inline-flex` pill of five or six
     chips that never wraps; it scrolls inside its own pill rather than pushing the
     panel sideways. */
  .s-WglPage .wgl-filter-track {
    max-width: 100%;
    overflow-x: auto;
    scrollbar-width: none;
  }

  /* ── Pager ─────────────────────────────────────────────────
     Already wraps; the range text takes its own line so the buttons stay together. */
  .s-WglPage .wgl-pager-range {
    flex: 1 1 100%;
  }
}


/* ══ NARROW PHONE ═══════════════════════════════════════════════════════════
   Below 480px an auto-fit grid of 210px tracks is one column anyway — so it is
   stated as one column, which also stops a NESTED grid (a field grid inside the
   document sheet, inside a dialog) from holding a 210px minimum in a 190px box. */
@media (max-width: 30rem) {

  /* (0,2,0) beats `.wgl-field-grid` and ties the modifiers in builder.css that set
     their own columns, all of which are already one column at this width. */
  .s-WglPage .wgl-field-grid,
  .wgl-dlg .wgl-field-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  /* THE OVERFLOW BUG. `.wgl-span-2` is `grid-column: span 2`, and in a one-column
     grid spanning two tracks CREATES an implicit second one — the field, and the
     page, overflow by a whole track (Products, Returns, Expenses, the rental
     header). Full width is what span-2 means at this size. */
  .s-WglPage .wgl-field-grid > .wgl-span-2,
  .wgl-dlg .wgl-field-grid > .wgl-span-2 {
    grid-column: 1 / -1;
  }

  /* 20rem and 16rem auto-fit tracks: one 320px minimum inside a ~290px panel. */
  .s-WglPage .wgl-dash-pair,
  .s-WglPage .wgl-cf-grid,
  .s-WglPage .wgl-terms-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Twenty-eight key numbers in one column is twenty-eight rows of scrolling. Two
     across: a tile is a label over a figure and 130px holds both. */
  .s-WglPage .wgl-stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .s-WglPage .wgl-stat {
    padding: 0.7rem 0.75rem;
  }

  .s-WglPage .wgl-stat-value {
    font-size: 1.1rem;
    overflow-wrap: anywhere;
  }

  /* The filter strip: two to a line, each a full half. `max-width: 16rem` was a desk
     cap; on a phone it left a ragged right edge. */
  .s-WglPage .wgl-filters .wgl-field {
    flex: 1 1 calc(50% - 0.6rem);
    max-width: none;
  }

  /* The archive's filter band: the 4.6rem key column beside its chips becomes a
     caption above them, which gives the chips the whole width to wrap in. */
  .s-WglPage .wgl-filter-band {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 0.35rem;
  }

  /* The rental's space line: name | × qty | 6rem price | remove. The name takes its
     own row. Children: desc, qty, price, remove. */
  .wgl-cart-line.wgl-space-line {
    grid-template-columns: minmax(0, 1fr) auto auto;
    row-gap: 0.35rem;
  }

  .wgl-cart-line.wgl-space-line > :nth-child(1) { grid-column: 1 / -1; }

  /* The builder's quick-add row: a 9rem price beside a 5.5rem qty and a 240px
     description wraps to three lines of one field each; qty and price share one. */
  .s-WglPage .wgl-add-desc { flex: 1 1 100%; }
  .s-WglPage .wgl-add-qty,
  .s-WglPage .wgl-add-price { flex: 1 1 0; min-width: 0; }

  /* The till's checkout buttons under PAID: Partial and Void on one line, each a
     half — Void still the smaller, but no longer pushed off by an 8rem minimum. */
  .s-WglPage .wgl-pos .wgl-checkout-actions .wgl-checkout-void {
    min-width: 0;
  }
}


/* ══ DIALOGS ════════════════════════════════════════════════════════════════
   WglDialog renders a Bootstrap modal with `.wgl-dlg` on the `.modal`. Below 576px
   Bootstrap already drops the side margin; what it does not do is keep a long form
   inside the screen. */
@media (max-width: 47.99rem) {

  /* Never taller than the phone: the header and the buttons stay put and the body
     scrolls between them. Bootstrap's `.modal-content` is already a flex column. */
  .wgl-dlg .modal-dialog {
    margin: 0.5rem auto;
    max-width: calc(100vw - 1rem);
  }

  .wgl-dlg .modal-content {
    max-height: calc(100dvh - 1rem);
    /* The 4px offset shadow is cut by the viewport on a full-width dialog and reads
       as a misprint along the right edge; 2px fits inside the margin. */
    box-shadow: var(--wgl-pop);
  }

  .wgl-dlg .modal-body {
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  /* The two widened dialogs clamp to the viewport like the rest. (0,2,0), as their
     own rules in builder.css and screens.css. */
  .wgl-dlg-wide .modal-dialog,
  .wgl-dlg-list .modal-dialog {
    max-width: calc(100vw - 1rem);
  }

  /* `min(26rem, 80vw)` — 80vw is 288px on a 360 phone and the dialog body is
     ~310px, so it fit; it also forced a minimum on dialogs that put two of these
     side by side. Full width of whatever box it is in. */
  .wgl-dlg-form {
    min-width: 0;
  }

  /* OK and Cancel are the two things a dialog is FOR; on a phone they share the
     line, each half of it, and stack only when a third button arrives. */
  .wgl-dlg .modal-footer {
    flex-wrap: wrap;
    gap: 0.5rem;
  }

  .wgl-dlg .modal-footer > .btn,
  .wgl-dlg .modal-footer > .wgl-btn {
    flex: 1 1 8rem;
    margin: 0;
  }
}
