/* ============================================================
   The screens the legacy-parity slices added: POS, Products,
   Supplier accounts and the shop Dashboard.

   Same rule as builder.css, which this sits beside: never a colour
   literal. Every value resolves through --wgl-*, or through the
   --bs-* and --s-* that the theme files map onto them, so light and
   dark both follow.

   And the same warning: never let a star be followed by a slash
   inside a comment. It closes the comment early, and CSS then eats
   everything up to the next open brace — which took out the
   `.wgl-pos` rule below and left the till in a single column.

   The page frame, title bar and toolbar are NOT here. WglPage
   reuses Serenity's own s-DataGrid / grid-title / grid-toolbar
   markup, and the panel, field, button, tag, empty-state and totals
   classes these screens use all come from builder.css.
   ============================================================ */

/* ── POS terminal — Slice 2 ─────────────────────────────────
   Two columns on a desktop till, one on a tablet. The cart is the
   tall column because it is what grows during a sale; tender and
   drawer sit beside it at a fixed height so Charge never scrolls
   off the screen mid-transaction. */

/* ONE COLUMN. A sale is one downward line — scan, cart, who, how, how much,
   press — and the two-column version broke it in half: the cart on the left, the
   payment beside it on the right, and the three buttons that END the sale at the
   bottom of a 22rem rail, below the fold on a counter screen. "Where are Partial
   and Void" is the question that layout asks of everybody who uses it.

   The legacy is one card, top to bottom, and the width is spent INSIDE it — the
   client fields three across, the money four across — rather than on a rail. See
   `.wgl-field-grid`, which does that and reflows on a tablet for free. */
.wgl-pos {
  display: flex;
  flex-direction: column;
  gap: var(--s-row-gap);
  /* Top only. The page foot is single-sourced on .wgl-page-content. */
  padding-top: var(--s-row-gap);
  min-width: 0;

  /* FULL WIDTH. This was capped at 68rem — the legacy's own `.wrap` — on the theory
     that a stretched cart line puts the description hard left and the price hard
     right with nothing between them. That was the wrong fix for a real problem: the
     slack does not go to waste, it goes to `.wgl-cart-title`, which is `nowrap` with
     an ellipsis and was truncating item names at 1060px. The width buys legible
     descriptions; the price, quantity and remove controls sit in fixed tracks and do
     not move. What the cap actually did was leave a third of a 1600px till empty
     while the panels stopped short of the toolbar above them.

     The two panels that do NOT want a whole screen each are handled below, in
     `.wgl-pos-below`, rather than by shrinking everything. */

  /* THREE INTERVALS, AND THEY MEAN DIFFERENT THINGS. Before this the checkout had
     exactly one — every step carried `margin-top: .9rem; padding-top: .9rem` and a
     hairline, five times over — so nothing on the screen led anything else, and the
     band above the cart had the opposite problem: five different ad-hoc values
     (11, 6, 7, 8, 15px) inside 60px.

       tight   within one thing        (a label and its field)
       step    between rows of a step  (the scan row and its hint)
       group   between the steps       (the cart, then the payment)
       commit  spent ONCE, above the buttons

     Local to the till: `.wgl-panel`, `.wgl-empty` and `.wgl-total` are shared with
     six other screens, so everything below reaches them through `.wgl-pos` only. */
  --pos-tight: 0.35rem;
  --pos-step: 0.75rem;
  --pos-group: 1.35rem;
  --pos-commit: 2rem;
}

/* Below the sale: the drawer and the orders list.
   Stacked on a narrow till, side by side once the screen can hold both — the drawer
   is a seven-row table that gains nothing from 1500px, while the orders list is a
   six-column row that does. Splitting them here is what makes full width worth
   having: it uses the space instead of stretching one panel across it, and it takes
   the taller of the two off the bottom of the page rather than adding them up. */
.wgl-pos-below {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s-row-gap);
  align-items: start;
  min-width: 0;
}

@media (min-width: 78rem) {
  .wgl-pos-below { grid-template-columns: 22rem minmax(0, 1fr); }
}

/* The checkout is ONE panel, not four stacked ones. Four cards for one continuous
   act put three borders across the middle of a sale, each reading as "this part is
   finished" at exactly the points where it is not. The hairlines below do that job
   where it IS true. */
.wgl-checkout-panel {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* A step within the sale, separated by SPACE.
   It used to carry a hairline as well, and so did the four steps after it, so the
   checkout read as five equal slabs with a rule between each — the squint test found
   no lead anywhere below the cart. Space groups perfectly well here because each row
   is already a run of labelled fields; the rules were compensating for a proximity
   problem that did not exist. */
.wgl-checkout-row { margin-top: var(--pos-group, 1.35rem); }

/* The one rule left, and the one generous interval: above it the page describes the
   sale, below it the sale happens. Nothing else on the till earns a line. */
.wgl-checkout-row.is-seam {
  margin-top: var(--pos-commit, 2rem);
  padding-top: var(--pos-commit, 2rem);
  border-top: 1px solid var(--bs-border-color);
}

.wgl-checkout-row > .wgl-field-label { display: block; margin-bottom: var(--pos-tight); }
.wgl-checkout-row > .wgl-chips { margin: 0; }

/* MORE ABOVE THAN BELOW. A heading belongs to what follows it, and this one used
   to sit in 15px of air on both sides — which reads as a divider between two equal
   things rather than as the top of the cart. */
.wgl-checkout-head {
  margin-top: var(--pos-group, 1.35rem);
  margin-bottom: var(--pos-step, 0.75rem);
}

/* THE COUNT BELONGS TO THE WORD IT COUNTS.
   `.wgl-panel-head` is `justify-content: space-between`, which on a two-child head
   throws the sticker to the far edge of the panel — so at full width the Cart's
   count sat 1500px away from "Cart", and the eye had to cross the whole till to
   read a number that qualifies the heading. The legacy writes it inline, inside
   the heading: `<h2>Orders <span class="tagno">0</span></h2>`.

   `flex-start` here, not a change to `.wgl-panel-head` itself: six other screens
   share that class and several of them genuinely want their right-hand slot. The
   Orders head keeps its scope chips on the right — those are a control, not a
   label, and `margin-inline-start: auto` still carries them there. */
.wgl-pos .wgl-panel-head {
  justify-content: flex-start;
  gap: 0.55rem;
  margin-bottom: var(--pos-step, 0.75rem);
}

/* The cart's own placeholder is ONE quiet line, not a 112px block. `.wgl-empty` is
   a panel-level empty state — right for a panel that has nothing else in it, wrong
   in the middle of a checkout where the scan box above and the payment below are
   both live. It is also the DEFAULT state of a till between customers, so those
   112px were on screen more of the day than not. */
.wgl-checkout-panel > .wgl-empty {
  padding: var(--pos-step) 0;
  text-align: start;
}

.wgl-checkout-panel > .wgl-empty .wgl-empty-title {
  display: inline;
  font-weight: 400;
  color: var(--bs-secondary-color);
}

.wgl-checkout-panel > .wgl-empty .wgl-empty-body { display: inline; }

.wgl-checkout-panel > .wgl-empty .wgl-empty-title::after { content: ' '; }

/* Still a real empty state, just not a whole screen of one. */
.wgl-pos .wgl-orders .wgl-empty,
.wgl-pos .wgl-drawer .wgl-empty { padding: var(--pos-group) 1rem; }

/* Whose store credit. Given its own row under the chips because choosing it is a
   second question that only exists once Store credit is the answer to the first. */
.wgl-credit-picker { margin-top: var(--pos-step); max-width: 32rem; }

/* The contact line sits ON the button row rather than under it: it is the ANSWER to
   Find contact and Clear, and a line of its own put a paragraph of grey between the
   buttons and the payment method. */
.wgl-contact-line {
  min-height: 0;
  align-self: center;
  font-size: 0.82rem;
  color: var(--bs-secondary-color);
}

/* The scan field is the primary input, so it is the largest control
   on the screen and reads as one before it has focus. */
.wgl-scan-input {
  font-size: 1.15rem;
  padding: 0.7rem 0.85rem;
}

/* NO RESERVED HEIGHT. It carried `min-height: 1.25rem` so the layout would not
   jump when a message arrived — but the till is idle between customers, which is
   most of the day, and that reserved a permanent 19px of nothing plus its margin
   directly under the scan box. It collapses instead, and the thing below it does
   not move far enough to matter: a scan replaces the line and the cart underneath
   grows by more than this line's height anyway. */
.wgl-scan-note {
  margin-top: var(--pos-tight, 0.35rem);
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--bs-secondary-color);
}

.wgl-scan-note:empty { display: none; }

/* Same again: an empty shortlist kept its 8px top margin, so two invisible
   elements were spending ~34px between the scan box and the Cart heading on every
   idle till. */
.wgl-matches:empty { display: none; }

.wgl-scan-note.is-error {
  color: var(--s-danger-text);
  font-weight: 600;
}

.wgl-parked {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.75rem;
}

.wgl-cart {
  display: flex;
  flex-direction: column;
}

.wgl-cart-line {
  display: grid;
  /* 7.5rem for the price, not 6rem: it holds an editable box now and the box was
     wider than the track it sits in. */
  grid-template-columns: 2.75rem minmax(0, 1fr) auto 7.5rem auto;
  align-items: center;
  gap: var(--s-col-gap);
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--bs-border-color);
}

/* A rented space has no photograph, so its row has four cells where the till's has
   five. Without this it inherits the grid above and every cell lands one track to
   the left: the space's NAME went into the 2.75rem thumbnail slot and was clipped to
   "Box…", while "× 2" sat in the 1fr track with room to spare. A Medium and a Mini
   then read identically on an agreement someone is about to sign. */
.wgl-cart-line.wgl-space-line {
  grid-template-columns: minmax(0, 1fr) auto 6rem auto;
}

/* The item's photograph beside its line, at the till.
   Tappable: the global lightbox picks up `img[data-lightbox]` and opens the
   original. Two black dresses at $18 are one reference apart, and the reference is
   on a label somewhere inside the garment. */
.wgl-pos-thumb {
  width: 2.75rem;
  height: 2.75rem;
  object-fit: cover;
  border-radius: 6px;
  border: 1px solid var(--bs-border-color);
  background: var(--bs-tertiary-bg);
  cursor: zoom-in;
}

/* The slot with nothing in it. It holds the column open so a photoless row does not
   pull every field on that line out of alignment with the rows above it. */
.wgl-pos-thumb.is-empty {
  display: block;
  border-style: dashed;
  cursor: default;
}

.wgl-cart-line:last-child { border-bottom: 0; }

.wgl-cart-desc {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
}

.wgl-cart-ref,
.wgl-cart-meta {
  font-size: 0.78rem;
  color: var(--bs-secondary-color);
}

.wgl-cart-title {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wgl-cart-qty {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-variant-numeric: tabular-nums;
}

/* The line's price, and what it was before somebody typed over it. A column, so
   the "was $12.00" sits under the box rather than pushing it out of its track. */
.wgl-cart-price {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.15rem;
  text-align: end;
  font-weight: 600;
}

/* Narrow, right-aligned and tabular: it is one figure in a column of figures, and
   a full-width editor here would make every cart line read as a form. The spinners
   go because a price is typed, not stepped, and they steal a third of the width. */
.wgl-cart-price-input {
  width: 100%;
  text-align: end;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  padding-inline: 0.45rem;
}

.wgl-cart-price-input::-webkit-outer-spin-button,
.wgl-cart-price-input::-webkit-inner-spin-button {
  appearance: none;
  margin: 0;
}

.wgl-cart-price-input { appearance: textfield; -moz-appearance: textfield; }

/* Shown only once the agreed price and the ladder's differ, and it is a BUTTON:
   the one thing anybody wants from "was $12.00" is $12.00 back. */
.wgl-cart-was {
  appearance: none;
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--s-danger-text, var(--wgl-red));
  text-decoration: underline dotted;
  cursor: pointer;
}

.wgl-cart-was:hover { text-decoration-style: solid; }

/* The legacy's `.postotal`: a black bar closing the cart off, with the count on the
   left and the figure on the right. It is not the same thing as `.wgl-totals`, the
   fixed strip at the foot of the window — this one belongs to the cart above it and
   is the last thing read before the money below. */
.wgl-cart-total {
  display: flex;
  align-items: center;
  gap: 1.6rem;
  margin-top: var(--pos-step, 0.7rem);
  padding: 0.6rem 1rem;
  border-radius: var(--bs-border-radius-sm);
  background: var(--wgl-black);
  color: var(--wgl-white);
  font-size: 0.82rem;
}

/* THE FIGURE HAD NO COLOUR OF ITS OWN AND WAS INVISIBLE.
   `.wgl-money` sets `color: var(--bs-body-color)` on the element itself, so the
   white this bar sets on its PARENT lost to it and the total rendered near-black
   on black — present in the DOM, unreadable on the counter, and a money figure a
   cashier reads out loud. Same failure as the drawer panel's white-on-white.
   Inherit is the fix, not a second literal. */
.wgl-cart-total .wgl-money { color: inherit; }

/* ...and the total itself takes the brand's headline colour, which needs the same
   specificity to get past the rule above. Yellow on black is what TO PAY uses on
   the fixed strip below, so the eye lands in the same place on both. */
.wgl-cart-total .wgl-cart-total-v { color: var(--wgl-yellow); }

.wgl-cart-total-n,
.wgl-cart-total-sub { color: var(--wgl-white); opacity: 0.7; }

/* Drawn only when a discount exists — see renderTotals. */
.wgl-cart-total-sub { font-variant-numeric: tabular-nums; }

/* Pushed right together, as the legacy's `.postotal` is: it is a summary, and a
   label spread to one end with its figure at the other is two things to read. */
.wgl-cart-total-l {
  margin-inline-start: auto;
  font-weight: 700;
  letter-spacing: 0.09em;
}

/* Yellow on black — the same pairing the fixed totals strip uses for TO PAY, which
   is the one figure on that bar the eye is meant to land on. (Yellow is a FILL on
   light and never type; on black it is the brand's own headline colour.) */
.wgl-cart-total-v {
  font-size: 1.1rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--wgl-yellow);
}

/* ── Search by photo ────────────────────────────────────────────
   A panel the legacy has and the operator knows by sight, so unlike every other AI
   affordance in this app it is drawn even when the server says it cannot run — with
   the server's own sentence under it. An absent panel reads as "missing", and the
   first thing it costs is somebody's afternoon looking for it. */
/* Heading and button on ONE row. This is a fallback for a rubbed-off label — used
   rarely, and it was taking 139px in the primary column at the same weight as the
   payment method. Wrapping only when there is genuinely no room. */
.wgl-photo-search {
  display: flex;
  align-items: baseline;
  gap: var(--pos-step) 1rem;
  flex-wrap: wrap;
}

/* `.is-section` — the Products page, where this lives INSIDE the Products panel
   under the filter grid rather than being a panel of its own.
 
   Everything here is on the modifier and not on the base, because the TILL draws the
   same component (`.wgl-photo-search.wgl-checkout-row.is-seam`) and its border is a
   deliberate, single, load-bearing rule in the checkout column. Styling the base
   would have given that row a second border and moved its buttons. */
.wgl-photo-search.is-section {
  align-items: center;
  gap: 0.55rem 1rem;
  margin-top: 0.9rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--bs-border-color);
}

/* The heading takes the slack so the buttons sit hard right of it rather than
   floating a word away at a wide viewport. Modifier-scoped for the same reason. */
.wgl-photo-search.is-section .wgl-photo-h {
  flex: 1 1 18rem;
  min-width: 0;
}

/* The two buttons travel together and wrap together. Loose in the flex row they
   were two independent items, so at a narrow width the camera stayed up beside the
   heading and Upload dropped to a line of its own. */
.wgl-photo-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.wgl-photo-h {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  flex-wrap: wrap;
  margin: 0;
  font-size: 0.9rem;
  font-weight: 700;
}

/* Optically centred on the cap height rather than sat on the baseline, which is
   where a 0.9rem glyph beside 0.9rem bold text reads a pixel low. */
.wgl-photo-h .fa {
  align-self: center;
  color: var(--bs-secondary-color);
}

.wgl-photo-sub {
  font-size: 0.78rem;
  font-weight: 400;
  color: var(--bs-secondary-color);
}

.wgl-photo-why {
  flex: 1 0 100%;
  margin: 0;
  max-width: 46rem;
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--bs-secondary-color);
}

/* The panel IS the drop target — the legacy's `lkDrop`, minus its dashed box, which
   would carry the same weight as the payment method for something used once a week.
   Nothing is drawn until a file is actually over it. */
.wgl-photo-search.is-over {
  outline: 2px dashed var(--s-wgl-accent-fg);
  outline-offset: 6px;
  border-radius: 8px;
}

/* ── The photo search's answers ──────────────────────────────
   Rows with the photographs IN them, for the same reason .wgl-matches is rows and not
   a dropdown: this is a VISUAL search. A <select> of references and prices asks the
   operator to confirm a look-alike without letting them look — and the server has sent
   a picture with every match since the feature shipped. Both screens threw it away. */
.wgl-dlg-list .modal-dialog { max-width: 36rem; }

.wgl-lookalikes {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 26rem;
  overflow-y: auto;
}

.wgl-lookalike {
  display: grid;
  grid-template-columns: 3.5rem minmax(0, 1fr) auto;
  gap: 0.7rem;
  align-items: center;
  width: 100%;
  text-align: start;
  padding: 8px 10px;
  border: 1.5px solid var(--bs-border-color);
  border-radius: 10px;
  background: var(--bs-body-bg);
  color: var(--bs-body-color);
  cursor: pointer;
  font-size: 0.85rem;
}

.wgl-lookalike:hover {
  border-color: var(--s-wgl-accent-fg);
  background: var(--s-wgl-tint-bg-2);
}

.wgl-lookalike:focus-visible { outline: none; box-shadow: var(--s-focus-ring); }

/* The chosen one, said twice — border and fill — because the OK button commits it and
   a single tint is easy to miss in a list of eight photographs. */
.wgl-lookalike.is-chosen {
  border-color: var(--s-wgl-accent-fg);
  background: var(--s-wgl-tint-bg-2);
  box-shadow: inset 0 0 0 1.5px var(--s-wgl-accent-fg);
}

.wgl-lookalike-img {
  width: 3.5rem;
  height: 3.5rem;
  object-fit: cover;
  border-radius: 8px;
  border: 1px solid var(--bs-border-color);
  background: var(--bs-tertiary-bg);
}

.wgl-lookalike-img.is-empty { display: block; border-style: dashed; }

.wgl-lookalike-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.wgl-lookalike-desc {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wgl-lookalike-meta {
  font-size: 0.75rem;
  color: var(--bs-secondary-color);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wgl-lookalike-side {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 3px;
  text-align: end;
}

.wgl-lookalike-conf {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 2px 7px;
  border-radius: 999px;
  border: 1px solid var(--bs-border-color);
  background: var(--s-wgl-tint-bg-2);
  color: var(--bs-body-color);
}

/* .wgl-money sets `color` on the element itself, so it wins over anything set on a
   parent. Stated here rather than assumed — the same rule has twice put a money
   figure on a dark panel in a colour nobody could read. */
.wgl-lookalike-side .wgl-money { color: inherit; font-weight: 700; }

.wgl-tender-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin: var(--pos-step, 0.6rem) 0 0;
}

/* ── The checkout, at the foot of the money ─────────────────────
   Submit as PAID, Partial / loan and Void live UNDER the amount received
   and the change, not in the page toolbar. That is where the legacy kept
   them, and it is the reading order at a counter: scan, cart, payment,
   change, press. In the toolbar they sat two feet up the screen at the
   same weight as Refresh and read as chrome rather than as the end of the
   transaction. See PosPage.checkoutActions().

   The primary takes the whole row because there is exactly one of it and
   it is the commonest press in the shop. The other two share the row
   below at ordinary weight — a Void drawn the size of a Submit is a Void
   somebody eventually presses by reflex.

   Nothing here needs a locked-register rule of its own: `.wgl-pos-locked`
   hides `.wgl-tender`, and these are inside it. */
/* No rule and no big gap of its own: the seam above the photo block already said
   "the sale commits here", and a second hairline 139px later said it again. These
   buttons belong to that block. */
.wgl-checkout-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: var(--pos-group, 1.35rem);
}

.wgl-checkout-pay {
  flex: 1 0 100%;
  padding: 0.65rem 1rem;
  font-size: 1rem;
  font-weight: 700;
}

.wgl-checkout-actions .wgl-btn:not(.wgl-checkout-pay) { flex: 1 1 auto; }

.wgl-checkout-note {
  margin: var(--pos-tight, 0.35rem) 0 0;
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--bs-secondary-color);
}


/* ══ COUNTER ERGONOMICS ═════════════════════════════════════════════════════
   Everything below is scoped to `.wgl-pos` and nothing else. The controls it
   resizes — `.wgl-btn`, `.wgl-chip`, `.wgl-icon-btn`, `.editor` — are shared
   with eight other screens, and those screens are read sitting down with a
   mouse. This one is worked standing up, at speed, often on a touchscreen, by
   somebody with a garment in the other hand.

   Measured before it was changed: all 42 interactive controls on the till were
   under 44px tall, and the three pressed most — the quantity minus, the
   quantity plus and the remove on every cart line — were 29x29. Apple's
   minimum is 44x44pt and Material's is 48x48dp; 29 is barely half of either,
   and a mis-press on the remove takes an item out of a sale that is being
   counted out loud.

   The rows do not grow for it. A cart line is 85px tall with 19px of padding,
   so a 44px control fits inside what the photograph and the two-line
   description already claim. */
.wgl-pos {
  /* One number, so nothing here can drift from anything else here.

     IN PIXELS, DELIBERATELY, and this repo has the bug that proves why: the
     comment above `.wgl-item-head` in builder.css says "2.75rem = 44px" and it
     is not — this theme sets the root font to 15px, so 2.75rem is 41.25 and
     every control written that way lands three pixels short of the standard it
     was written to meet. A finger is a fixed physical size. It does not scale
     with the page's type, so neither does this. */
  --pos-touch: 44px;
}

/* The row actions: quantity down, quantity up, remove.
   Kept visually light — this is still a glyph on a transparent ground, not a
   button with an outline — and simply given the area a finger needs. A hit area
   larger than the ink is the standard answer (Apple HIG: extend the hit region
   beyond the visual bounds), and it costs nothing here because the three sit in
   `auto` grid tracks that take their width from their content. */
.wgl-pos .wgl-icon-btn {
  width: var(--pos-touch);
  height: var(--pos-touch);
  font-size: 1.05rem;
  line-height: 1;
}

/* Every button and every field on the till, to the same floor. `min-height`
   rather than `height`: `Cash out takings` wraps on a narrow drawer panel and a
   fixed height would clip its second line. */
.wgl-pos .wgl-btn,
.wgl-pos .editor,
.wgl-pos select.editor,
.wgl-pos .wgl-field-static {
  min-height: var(--pos-touch);
}

/* A <select> renders with `line-height: normal` where an <input> inherits the
   page's 22.5px, so the currency box came out 38px beside two 42px money boxes
   in the same four-column row — a 4px step in a line of fields the eye reads as
   one. The floor above fixes the height; this puts the text back on the same
   baseline as its neighbours. */
.wgl-pos select.editor { line-height: 1.5; }

/* The cart tabs. Two people at the counter at once is what these are for, so
   they are pressed while somebody is waiting. 27px was the smallest control on
   the screen after the row actions. */
.wgl-pos .wgl-cart-tab { min-height: 36px; }

/* ── The tender chips are not filters ──────────────────────────────────────
   `.wgl-chip` was written for a filter band: 30px tall, 11px type, a quiet pill
   that turns yellow when it is narrowing a list. At the till the same component
   is asking HOW THIS PERSON IS PAYING — a required choice that decides which
   ledger the money lands in, whether a supplier gets paid and whether the drawer
   should move — and it was rendering smaller than any other control on the page,
   "Cash" at 56x30.

   It keeps the pill and it keeps the yellow fill, because "the one thing wearing
   the brand fill is the thing that is on" is a rule the whole product follows. It
   gains the size the decision deserves. The orders-panel scope chips below are
   left exactly as they were: those really are filters. */
.wgl-pos .wgl-tender .wgl-chip {
  min-height: var(--pos-touch);
  padding: 0 1.05rem;
  font-size: 13px;
}

/* ── The money reads across a counter ──────────────────────────────────────
   Two figures on this screen are said out loud to a customer: what they owe and
   what they get back. Both were set smaller than the description of the dress
   above them. */
.wgl-pos .wgl-cart-total-v { font-size: 1.5rem; }

/* The change had no class at all, so it drew as `.wgl-field-static` — 0.8rem in
   secondary grey, identical to the LABEL sitting above it. See cashReceived(),
   which now marks it. Tabular, because it sits under a typed amount and the two
   are compared digit by digit. */
.wgl-pos .wgl-change-value {
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--bs-body-color);
  font-variant-numeric: tabular-nums;
}

/* Short keeps its own colour — the rule that sets it is `.wgl-short`, one class,
   which the selector above beats on specificity. Restated rather than reordered:
   the whole point of the red is that it wins. */
.wgl-pos .wgl-change-value.wgl-short { color: var(--s-danger-text, var(--wgl-red)); }

/* ── One primary action, one destructive one kept out of its way ───────────
   Submit as PAID is the commonest press in the shop and it was 39px tall — the
   same height as Clear — and it carried a text tick rather than an icon. It is a
   full-width bar already; it now has the height of one.

   PREFIXED WITH `.s-WglPage`, and it has to be. `legacy-shapes.css` loads AFTER
   this file (see appsettings.bundles.json) and declares `.s-WglPage .wgl-btn`
   with its own `font-size`, at two classes. A bare `.wgl-pos .wgl-checkout-pay`
   is also two, so it would lose the tie on order and the button would take the
   height set here and keep the 12.5px type — which is the same cascade trap
   that left `.wgl-btn-sm` doing nothing on four screens. */
.s-WglPage .wgl-pos .wgl-checkout-pay {
  min-height: 56px;
  font-size: 1.05rem;
  gap: 0.5rem;
}

.s-WglPage .wgl-pos .wgl-checkout-pay i { font-size: 1.1em; }

/* Partial / loan takes the slack. Void does NOT: it shrinks to its label and is
   pushed to the far end, so the two are no longer a matched pair of 640px slabs
   with one of them destructive. The comment on `.wgl-checkout-actions` above
   already argued this — half a row is still a Void drawn the size of a Submit.

   Four classes deep because the rule it is overriding —
   `.wgl-checkout-actions .wgl-btn:not(.wgl-checkout-pay)` — is three: `:not()`
   takes the specificity of its argument. */
.s-WglPage .wgl-pos .wgl-checkout-actions .wgl-checkout-void {
  flex: 0 0 auto;
  margin-inline-start: auto;
  min-width: 8rem;
}

/* ── The sale is being written ─────────────────────────────────────────────
   `call()` passes `blockUI: false` on purpose — a scanner firing four times a
   second must not raise an overlay — so a checkout in flight used to change
   nothing on screen at all. The pressed button says so; see setCheckoutBusy. */
.wgl-pos .wgl-btn.is-busy {
  position: relative;
  color: transparent;
}

.wgl-pos .wgl-btn.is-busy i { visibility: hidden; }

.wgl-pos .wgl-btn.is-busy::after {
  content: "";
  position: absolute;
  inset-block-start: calc(50% - 0.55rem);
  inset-inline-start: calc(50% - 0.55rem);
  width: 1.1rem;
  height: 1.1rem;
  border: 2px solid currentColor;
  border-block-start-color: transparent;
  border-radius: 50%;
  color: var(--wgl-yellow);
  animation: wgl-pos-spin 0.7s linear infinite;
}

@keyframes wgl-pos-spin { to { transform: rotate(1turn); } }

/* ── Reduced motion ────────────────────────────────────────────────────────
   `.wgl-btn` nudges itself a pixel on hover and a pixel back on press, which is
   what makes the hard offset shadow read as a physical lift. Somebody who has
   asked the OS for less movement gets the shadow and none of the travel, and the
   spinner stops turning and simply sits there as a mark that something is in
   flight. */
@media (prefers-reduced-motion: reduce) {
  /* Same cascade note as the primary button above: the travel is set by
     `.s-WglPage .wgl-btn:hover:not(:disabled)` in the later file, which is four,
     so cancelling it takes five. */
  .s-WglPage .wgl-pos .wgl-btn:hover:not(:disabled),
  .s-WglPage .wgl-pos .wgl-btn:active:not(:disabled),
  .s-WglPage .wgl-pos .wgl-chip:hover { transform: none; }

  .wgl-pos .wgl-btn.is-busy::after {
    animation: none;
    border-block-start-color: currentColor;
    opacity: 0.6;
  }
}

/* Today / All, in the orders panel head.
   `margin-inline-start: auto` rather than a third slot in the head's
   space-between: the scope decides what the count beside it MEANS, so the two
   belong together at the end. Left to spread, the pair sat a third of the way
   across the panel and read as an unrelated control. */
/* The till's Orders panel keeps its chrome — title, count, scope chips, search box
   and the pager's top row — in a container of its own, built ONCE. It used to be
   rebuilt on every load, which re-parented the search input 250ms after each
   keystroke and blurred it mid-word; see PosPage.ordersHeadEl.

   That put the results one level down, where builder.css's
   `.wgl-saved-list:not(:first-child)` no longer fires — and the gap that rule exists
   to create is the one its own comment names, "the search field on the till's Orders
   panel". So it comes from this container instead. */
.wgl-orders-list > .wgl-saved-list { margin-top: 0.9rem; }

.wgl-orders-scope {
  display: flex;
  gap: 0.3rem;
  margin-inline-start: auto;
}

/* A shade tighter than a filter-band chip: this pair sits beside a 1.05rem
   panel title, not on a row of its own. */
.wgl-orders-scope .wgl-chip {
  padding: 0.18rem 0.6rem;
  font-size: 0.78rem;
}

.wgl-orders-scope .wgl-chip:disabled {
  opacity: 0.55;
  cursor: default;
}

/* Two pairs of chips in one strip: which list, then which dates. The rule between
   them says they are separate questions — without it, four chips in a row read as
   one four-way choice and "All" looks like it belongs with "Void & returned". */
.wgl-orders-scope-sep {
  width: 1px;
  align-self: stretch;
  margin: 0.1rem 0.15rem;
  background: var(--wgl-line, rgba(0, 0, 0, 0.15));
}

/* What is still owed on a loan, under the item count. Red because it is the one
   thing on this row somebody has to act on, and it is money. */
.wgl-saved-owed {
  display: block;
  margin-top: 0.15rem;
  font-weight: 700;
  font-size: 0.78rem;
  color: var(--wgl-danger, #dc2626);
}

/* The foot of the sold-items list. It adds up the rows above it and nothing else,
   which is the whole reason it is drawn: a filtered list under an unfiltered total
   is two different answers stacked. */
.wgl-stmt-line-foot {
  font-weight: 700;
  border-top-width: 2px;
}

/* The heading over one consignment's items, drawn only when a supplier has more
   than one. It has to read as a divider rather than as another item, or a reader
   scanning the share column counts the subtotal in with the rows under it — so it
   takes the tinted ground and the rule above, and its own items keep the plain
   row. Drawn after .wgl-stmt-line in the cascade and carrying both classes, so it
   inherits that list's five columns and only overrides what it changes. */
.wgl-saved.wgl-stmt-group {
  background: var(--bs-tertiary-bg);
  border-top: 2px solid var(--bs-border-color);
  font-weight: 700;
}

/* Not the first thing in the list — that one sits under the panel heading already
   and a second rule there reads as a stray line. */
.wgl-saved-list > .wgl-saved.wgl-stmt-group:first-child {
  border-top-width: 1px;
}

/* ── The drawer's figures ───────────────────────────────────────
   Label left, figure right, on one line. `.wgl-total` is a column elsewhere — it is
   the fixed totals strip's cell, where a label ABOVE its figure is right — and the
   drawer borrowed it for seven stacked pairs at 43px each. That made this panel
   445px, the tallest thing on the till, for figures a cashier reads twice a day.
   Scoped to `.wgl-pos` so the strip's own cells keep their shape. */
.wgl-pos .wgl-drawer-row {
  flex-direction: row;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.28rem 0;
}

.wgl-pos .wgl-drawer-row .wgl-total-label { white-space: normal; }

/* The one figure anybody acts on: it is what the cash in the tray has to match.
   Seven identical rows made it the hardest of the seven to find. */
.wgl-pos .wgl-drawer-row.is-strong {
  margin-top: var(--pos-tight);
  padding-top: var(--pos-step);
  border-top: 1px solid var(--bs-border-color);
}

.wgl-pos .wgl-drawer-row.is-strong .wgl-total-value {
  font-size: 1.05rem;
  font-weight: 700;
}

/* ── The register gate ──────────────────────────────────────────
   Not a warning above the checkout — the checkout itself. With no same-day session
   the scan box, the cart and the tender panel are removed from the page and this
   stands in their place, carrying the one button that fixes whichever of the two
   states the till is in.

   Hiding rather than disabling is the point. A greyed-out Charge over a cart full
   of scanned items invites somebody to find the way around it; nothing to press
   but "Open register" does not. */
.wgl-pos-locked .wgl-checkout-panel { display: none !important; }

.wgl-reg-gate-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.55rem;
  padding: 2.2rem 1.5rem;
  text-align: center;
  border-style: dashed;
}

.wgl-reg-gate-icon {
  font-size: 2rem;
  line-height: 1;
}

.wgl-reg-gate-title {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 800;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.wgl-reg-gate-msg {
  max-width: 34rem;
  margin: 0;
  font-size: 0.86rem;
  line-height: 1.55;
  color: var(--wgl-muted, #6b6b6b);
}

/* ── Products — Slice 3 ─────────────────────────────────────── */

.wgl-products {
  display: flex;
  flex-direction: column;
  gap: var(--s-row-gap);
  padding-top: var(--s-row-gap);
}

.wgl-product {
  display: grid;
  grid-template-columns: auto 6rem minmax(0, 1fr);
  gap: var(--s-col-gap);
  align-items: start;
  background: var(--bs-body-bg);
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-card-border-radius);
  box-shadow: var(--s-shadow-xs);
  padding: 0.9rem 1rem;
}

/* The photo is the first thing to go on a narrow screen: it helps
   recognition and carries no information the row does not. */
@media (max-width: 48rem) {
  .wgl-product { grid-template-columns: auto minmax(0, 1fr); }
  .wgl-product-photo { display: none; }
}

.wgl-product-pick { padding-top: 0.35rem; }

.wgl-product-photo {
  width: 6rem;
  height: 6rem;
  border-radius: var(--bs-border-radius-sm);
  overflow: hidden;
  background: var(--bs-secondary-bg);
  display: flex;
  align-items: center;
  justify-content: center;
}

.wgl-product-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.wgl-product-nophoto {
  font-size: 0.72rem;
  color: var(--bs-secondary-color);
}

.wgl-product-body {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  min-width: 0;
}

.wgl-product-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
}

/* ── Supplier accounts — Slice 5 ────────────────────────────── */

.wgl-crm {
  display: grid;
  grid-template-columns: 26rem minmax(0, 1fr);
  gap: var(--s-col-gap);
  /* Top only. The page foot is single-sourced on .wgl-page-content. */
  padding-top: var(--s-row-gap);
  align-items: start;
}

@media (max-width: 62rem) {
  .wgl-crm { grid-template-columns: minmax(0, 1fr); }
}

.wgl-crm-list .wgl-saved { cursor: pointer; }

/* A supplier in the directory.
   Two lines, because this list lives in a 26rem sidebar. It used to borrow
   .wgl-saved, whose six fixed tracks add up to 31.5rem — the flexible track
   collapsed to nothing, phone numbers wrapped one digit per line and every
   name was clipped mid-word. */
.wgl-crm-row {
  display: grid;
  /* name | amount owed | message. Three real columns, so nothing sits on top of
     anything: the button used to be position:absolute in the top-right corner,
     which is exactly where the amount is. */
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: baseline;
  gap: 0.15rem 0.6rem;
  padding: 0.6rem 0.7rem;
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-border-radius-sm);
  background: var(--bs-body-bg);
  cursor: pointer;
  transition: background var(--s-transition), border-color var(--s-transition);
}

.wgl-crm-row:hover {
  background: var(--bs-tertiary-bg);
  border-color: var(--s-wgl-accent-fg);
}

.wgl-crm-row:focus-visible { outline: none; box-shadow: var(--s-focus-ring); }

/* Placed explicitly rather than by source order, so a row without a phone — and
   therefore without the button — still lays out identically. */
.wgl-crm-row-name { grid-column: 1; grid-row: 1; }
.wgl-crm-row-due  { grid-column: 2; grid-row: 1; }
.wgl-crm-row-chat { grid-column: 3; grid-row: 1; }
.wgl-crm-row-meta { grid-column: 1 / -1; grid-row: 2; }
.wgl-crm-row .wgl-item-tags { grid-column: 1 / -1; grid-row: 3; }

.wgl-crm-row-name {
  font-weight: 600;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wgl-crm-row-due {
  text-align: end;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  white-space: nowrap;
}

/* The second line: everything that identifies them, wrapping freely. */
.wgl-crm-row-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.2rem 0.6rem;
  font-size: 0.78rem;
  color: var(--bs-secondary-color);
}

.wgl-crm-row-no { font-variant-numeric: tabular-nums; font-weight: 600; }

/* Never broken across lines — a phone number split down a column is unreadable
   and unusable, which is the bug this whole block replaced. */
.wgl-crm-row-phone { white-space: nowrap; font-variant-numeric: tabular-nums; }

.wgl-crm-row .wgl-item-tags:empty { display: none; }

/* Always visible. It was revealed on hover, and the shop works on a tablet where
   there is no hover at all — the button simply did not exist there. It is quiet
   rather than hidden: muted until the row is hovered or it takes focus. */
.wgl-crm-row-chat {
  align-self: center;
  flex: none;
  color: var(--bs-secondary-color);
  transition: color var(--s-transition);
}

.wgl-crm-row:hover .wgl-crm-row-chat,
.wgl-crm-row-chat:hover,
.wgl-crm-row-chat:focus-visible { color: var(--s-wgl-accent-fg); }
.wgl-crm-row-chat:focus-visible { opacity: 1; }

/* ── Shop dashboard — Slice 6 ───────────────────────────────
   The action centre comes first and is visually loudest: it is the
   only part of this screen that changes what somebody does next.
   The legacy put its charts on top and the to-do list below the
   fold, which is why nobody read it. */

.wgl-dash {
  display: flex;
  flex-direction: column;
  gap: var(--s-row-gap);
  padding-top: var(--s-row-gap);
  /* The foot is otherwise single-sourced on .wgl-page-content, which was enough
     while this screen ended in a full-width panel. It now ends in the tile grid,
     whose last row sits hard against the bottom of the scroll area with nothing
     under it. */
  padding-bottom: var(--s-row-gap);
}

/* Title, date, then the period control pushed right — the legacy's own header row.
   `.wgl-panel-head` alone is space-between, which with three children strands the
   date chip in the middle of the screen instead of beside the title it belongs to. */
.wgl-dash-head {
  justify-content: flex-start;
  gap: 0.6rem;
  flex-wrap: wrap;
}

.wgl-dash-head-control {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-left: auto;
}

.wgl-dash-period { width: auto; }

/* `align-items: stretch` — the two panels are one row and are read as one row,
   so a short aging list next to a ten-category stock list left the right-hand
   card floating with a ragged bottom edge. Stretching costs the shorter panel
   some empty space and buys a level baseline; its content still starts at the
   top because the panel is not itself a flex container. */
.wgl-dash-pair {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  gap: var(--s-col-gap);
  align-items: stretch;
}

.wgl-action {
  display: flex;
  align-items: flex-start;
  /* Wraps so the buttons drop under the text on a narrow tablet rather than
     squeezing the sentence that says what needs doing. */
  flex-wrap: wrap;
  gap: 0.75rem;
  padding: 0.7rem 0;
  border-bottom: 1px solid var(--bs-border-color);
}

.wgl-action:last-child { border-bottom: 0; }
.wgl-action.is-clickable { cursor: pointer; }
.wgl-action.is-clickable:hover .wgl-action-title { text-decoration: underline; }

.wgl-action i {
  margin-top: 0.15rem;
  width: 1.25rem;
  text-align: center;
  color: var(--s-wgl-accent-fg);
}

/* Overdue under the signed terms. The icon changes colour rather than the whole
   row: the action centre is a list to work down, not a wall of alarm. */
.wgl-action.is-over i { color: var(--s-danger-text); }

.wgl-action-title {
  font-weight: 600;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* Every action now carries the terms engine's own sentence, so the detail line
   is prose rather than a count and needs to read like it. */
/* The doing, on the card. A card that only navigates turns a morning's work into a
   list of places to go — which is what the legacy's actionBtns() avoided. */
.wgl-action-buttons {
  display: flex;
  gap: 0.4rem;
  flex-shrink: 0;
  align-self: center;
  /* margin rather than a flex:1 on the body — this has to sit right whatever the
     body's own sizing turns out to be, and it must not disturb the two-column
     icon/body layout that was already working. */
  margin-left: auto;
}

.wgl-action-detail {
  font-size: 0.82rem;
  line-height: 1.45;
  color: var(--bs-secondary-color);
}

.wgl-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: var(--s-col-gap);
}

/* The loading and failed states are ONE child of a grid built for twenty-eight, so
   without this they render as a lone 12rem column against a wall of white space. */
.wgl-stats > .wgl-skeleton,
.wgl-stats > .wgl-empty { grid-column: 1 / -1; }

.wgl-stat {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  background: var(--bs-body-bg);
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-card-border-radius);
  box-shadow: var(--s-shadow-xs);
  padding: 0.85rem 1rem;
}

.wgl-stat-label {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--bs-secondary-color);
}

.wgl-stat-value {
  font-size: 1.3rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.wgl-stat-note {
  font-size: 0.72rem;
  color: var(--bs-secondary-color);
}

/* The legacy's `.kpi.hot`. Reserved for the figures that only mean something when
   they are NOT zero — new this week, sold this week, expenses, renewals, and the
   action count. Tinting a standing total would tint it every day, and a tile that
   is always lit is a tile nobody sees.

   Fill is not the only cue: every hot tile also carries a note or a non-zero value
   that says the same thing in words. */
.wgl-stat.is-hot {
  background: var(--s-wgl-tint-bg-2);
  border-color: var(--s-wgl-accent-fg);
}

/* The legacy's `.kpi.link`: four tiles that are a way in to a screen rather than a
   figure to read. Keyboard-reachable here, which the legacy's was not. */
.wgl-stat.is-link { cursor: pointer; }

.wgl-stat.is-link:hover,
.wgl-stat.is-link:focus-visible {
  border-color: var(--s-wgl-accent-fg);
  box-shadow: var(--s-shadow-sm);
}

/* Bars rather than a charting library: six months of four series
   is not a data-visualisation problem, and the dependency would be
   paid for on every admin page load. */
.wgl-flow {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: var(--s-col-gap);
  align-items: end;
  min-height: 11rem;
}

.wgl-flow-month {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.wgl-flow-bars {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 0.25rem;
  height: 9rem;
}

.wgl-bar {
  width: 0.8rem;
  min-height: 2px;
  border-radius: var(--bs-border-radius-sm) var(--bs-border-radius-sm) 0 0;
  background: var(--bs-secondary-bg);
}

/* Intake is the money coming IN and everything beside it is money going out, so
   it takes the neutral paper tone rather than a fifth hue — the reader is meant
   to compare its height against the group, not learn another colour. */
.wgl-bar.is-intake { background: var(--s-wgl-edge); }
.wgl-bar.is-sales { background: var(--wgl-yellow); }
.wgl-bar.is-commission { background: var(--wgl-green); }
.wgl-bar.is-payouts { background: var(--wgl-gray); }
.wgl-bar.is-expenses { background: var(--wgl-red); }

.wgl-flow-label {
  text-align: center;
  font-size: 0.72rem;
  color: var(--bs-secondary-color);
}

.wgl-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  margin-bottom: 0.75rem;
  font-size: 0.78rem;
  color: var(--bs-secondary-color);
}

.wgl-key {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

.wgl-key::before {
  content: "";
  width: 0.7rem;
  height: 0.7rem;
  border-radius: 2px;
  background: var(--bs-secondary-bg);
}

.wgl-key.is-intake::before { background: var(--s-wgl-edge); }
.wgl-key.is-sales::before { background: var(--wgl-yellow); }
.wgl-key.is-commission::before { background: var(--wgl-green); }
.wgl-key.is-payouts::before { background: var(--wgl-gray); }
.wgl-key.is-expenses::before { background: var(--wgl-red); }

/* Inventory: what is left against what has gone. */
.wgl-key.is-available::before { background: var(--wgl-yellow); }
.wgl-key.is-sold::before { background: var(--s-wgl-edge); }

/* The pipeline's five statuses and four ladder bands. Same hues as the pills
   those states wear elsewhere, so a legend swatch and a stamp agree. */
.wgl-key.is-st-draft::before { background: var(--bs-secondary-bg); }
.wgl-key.is-st-submitted::before { background: var(--wgl-yellow); }
.wgl-key.is-st-approved::before { background: var(--wgl-green); }
.wgl-key.is-st-rejected::before { background: var(--wgl-red); }
.wgl-key.is-st-cancelled::before { background: var(--wgl-gray); }

.wgl-key.is-band-0::before { background: var(--wgl-green); }
.wgl-key.is-band-1::before { background: var(--wgl-yellow); }
.wgl-key.is-band-2::before { background: var(--wgl-amber); }
.wgl-key.is-band-3::before { background: var(--wgl-red); }

.wgl-slices {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
}

/* The count track is 6rem, not 3rem: the inventory pane puts "1141 / 1167" in it
   and a 3rem column wrapped that onto two lines, which made every row a
   different height down a list whose whole job is comparison. */
.wgl-slice {
  display: grid;
  grid-template-columns: minmax(6rem, 10rem) minmax(0, 1fr) 6rem 5.5rem;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.85rem;
}

.wgl-slice-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A flex row, so a track can carry more than one fill: the inventory pane draws
   available and sold as two segments of the same bar, which is the comparison
   that makes a category that never moves distinguishable from one that clears. */
.wgl-slice-track {
  display: flex;
  height: 0.5rem;
  border-radius: var(--bs-border-radius-pill);
  background: var(--bs-secondary-bg);
  overflow: hidden;
}

.wgl-slice-fill {
  display: block;
  height: 100%;
  background: var(--s-wgl-accent-fg);
}

.wgl-slice-fill.is-available { background: var(--wgl-yellow); }
.wgl-slice-fill.is-sold { background: var(--s-wgl-edge); }

.wgl-slice-count,
.wgl-slice-value {
  text-align: end;
  font-variant-numeric: tabular-nums;
  color: var(--bs-secondary-color);
}

/* ── Pager ──────────────────────────────────────────────────
   For the card lists that Serenity's SlickPager does not cover — the product
   catalogue and the quotation archive. Same order of controls as SlickPager so
   it reads as the same thing. */

.wgl-pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  margin-top: 0.75rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--bs-border-color);
  border-bottom: 1px solid var(--bs-border-color);
  padding-bottom: 0.6rem;
  font-size: 0.85rem;
}

/* The twin above the list. Without this bar the only pager sits under twenty-five
   tall cards, which is a control nobody scrolls to find.

   The rule stays ON TOP, exactly as on the bottom bar: it closes the filter block
   above it and the pager reads as the first thing in the results, not as the last
   line of the filters. It used to be mirrored — rule underneath — which on the
   Products screen drew the divider along the very bottom edge of the panel and
   left the pager floating inside the filter card. */
.wgl-pager-top {
  margin-bottom: 0;
}

/* The count above the top pager — "1–25 of 1243 item(s)." on Products, the
   owed/paid summary on Supplier accounts.

   It is a caption for the RESULTS, not a hint for the last filter field, and at
   the field-hint's own distance it read as belonging to the Markdown select
   directly above it. A row gap of air above and the pager's own rule close
   underneath groups it with what it counts. */
.wgl-list-count {
  margin-top: var(--s-row-gap);
}

.wgl-pager-btn {
  min-width: 2rem;
  height: 2rem;
  padding: 0 0.4rem;
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-border-radius-sm);
  background: var(--bs-body-bg);
  color: var(--bs-body-color);
  line-height: 1;
  cursor: pointer;
}

.wgl-pager-btn:hover:not(:disabled) {
  border-color: var(--s-wgl-accent-fg);
  background: var(--s-wgl-tint-bg);
}

.wgl-pager-btn:disabled {
  opacity: 0.4;
  cursor: default;
}

.wgl-pager-label {
  padding: 0 0.5rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* Pushed to the far end so the buttons stay in one group on the left, wherever
   the panel happens to be wide. */
.wgl-pager-range {
  margin-inline-start: auto;
  color: var(--bs-secondary-color);
  font-variant-numeric: tabular-nums;
}

.wgl-pager-size {
  width: auto;
  min-width: 4.5rem;
  padding: var(--s-input-padding-v) 0.4rem;
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-border-radius-sm);
  background: var(--bs-body-bg);
  color: var(--bs-body-color);
}

/* ── WglDialog ──────────────────────────────────────────────
   The ask-the-user surface. Replaces thirteen browser `prompt()` calls, so it has
   to carry everything they could not: a title, typed inputs, a hint under a field,
   an inline error, and a named OK button.

   Shapes come from the legacy `.enh-box` in Slice 7.5; this file only lays out the
   contents. */

.wgl-dlg-msg {
  margin-bottom: 1rem;
  color: var(--bs-body-color);
  font-size: 0.9rem;
  line-height: 1.55;
}

/* Newlines in a message are meaningful — the legacy wrote multi-line prompts, and
   the close-drawer dialog is a six-line reconciliation. */
.wgl-dlg-msg p { margin: 0 0 0.3rem; }
.wgl-dlg-msg p:last-child { margin-bottom: 0; }

.wgl-dlg-form {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  min-width: min(26rem, 80vw);
}

.wgl-dlg-form .wgl-field input.editor:not([type="checkbox"]),
.wgl-dlg-form .wgl-field select.editor,
.wgl-dlg-form .wgl-field textarea.editor {
  width: 100%;
}

/* A field showing an answer the operator does not get to change — the consignment a
   payout was opened against. It has to read as SETTLED rather than as broken, so it
   keeps full-strength text and gives up only the white field and the cursor; a greyed
   value would say "this did not load", which is the opposite of what it means. The
   hint underneath says who decided it. */
.wgl-dlg-form .wgl-field.is-fixed .editor:disabled {
  background: var(--s-wgl-tint-bg-2);
  color: var(--bs-body-color);
  opacity: 1;
  cursor: default;
}

/* Checkbox rows read left-to-right, unlike the stacked label-over-input default. */
.wgl-dlg-form .wgl-field-check {
  flex-direction: row-reverse;
  align-items: center;
  justify-content: flex-end;
  gap: 0.6rem;
  padding-top: 0;
}

.wgl-dlg-form .wgl-field-check .wgl-field-label {
  margin: 0;
  cursor: pointer;
}

.wgl-dlg-form .wgl-field-check input {
  width: auto;
  flex: 0 0 auto;
}

/* Empty until something is wrong, so it takes no space in the common case. */
.wgl-dlg-error:empty { display: none; }

/* Was --wgl-red-dk on a solid --wgl-red-lt: 2.2:1, and unreadable on BOTH
   themes — the two are a light and a dark step of the same hue, which is
   exactly the pair that cannot carry each other. Since this is the only thing
   a dialog says when a save is refused, it now takes the same tinted-fill +
   lifted-text shape the status pills use, and reads through the theme. */
.wgl-dlg-error {
  padding: 0.55rem 0.7rem;
  border-radius: var(--bs-border-radius-sm);
  background: rgba(var(--wgl-red-rgb), 0.12);
  border: 1px solid rgba(var(--wgl-red-rgb), 0.3);
  color: var(--s-danger-text);
  font-size: 0.85rem;
  font-weight: 600;
}

/* ── POS cart tabs, scan hint and match list — Slice 8 ────── */

.wgl-cart-tabs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-bottom: var(--pos-step, 0.75rem);
}

/* 5px/12px at 10.5px type — the legacy's `.qfbtn`, which these are. They were a
   touch taller, and the `+` beside them taller again (see below), so a row of
   chips took the vertical space of a row of buttons. */
.wgl-cart-tab {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 5px 12px;
  border: 1.5px solid var(--bs-border-color);
  border-radius: 14px;
  background: var(--bs-body-bg);
  color: var(--bs-secondary-color);
  font-weight: 700;
  font-size: 10.5px;
  letter-spacing: 0.04em;
  line-height: 1.5;
  cursor: pointer;
}

.wgl-cart-tab.is-active {
  background: var(--wgl-yellow);
  border-color: var(--wgl-black);
  color: var(--wgl-black);
}

.wgl-cart-tab-n {
  font-variant-numeric: tabular-nums;
  opacity: 0.75;
}

.wgl-cart-tab-x {
  margin-inline-start: 0.15rem;
  opacity: 0.6;
}

.wgl-cart-tab-x:hover { opacity: 1; }

/* Matched to its siblings on every axis that decides height. It used to be 14px
   type in 6px padding against their 11.5px in 5px, so the one chip that is not a
   cart stood a clear 5px taller than the row it belongs to and dragged the whole
   strip's height up with it. Width is where a + may differ, and does. */
.wgl-cart-tab-add {
  font-size: 10.5px;
  padding: 5px 14px;
  line-height: 1.5;
}

.wgl-scan-hint {
  margin-top: var(--pos-tight, 0.35rem);
  font-size: 10px;
  color: var(--bs-secondary-color);
  line-height: 1.5;
}

/* The shortlist a non-exact scan produces. Rows, not a dropdown: the cashier is
   comparing three dresses and needs to see all three at once. */
.wgl-matches {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 8px;
}

.wgl-match {
  display: grid;
  grid-template-columns: 2.75rem 9rem minmax(0, 1fr) 5rem;
  gap: 0.6rem;
  align-items: center;
  text-align: start;
  padding: 7px 10px;
  border: 1.5px solid var(--bs-border-color);
  border-radius: 10px;
  background: var(--bs-body-bg);
  color: var(--bs-body-color);
  cursor: pointer;
  font-size: 0.85rem;
}

.wgl-match:hover {
  border-color: var(--s-wgl-accent-fg);
  background: var(--s-wgl-tint-bg-2);
}

.wgl-match-ref {
  font-size: 0.75rem;
  color: var(--bs-secondary-color);
}

.wgl-match-desc {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wgl-match-price {
  text-align: end;
  font-weight: 700;
}

/* ── Camera scanning — Slice 8.5 ───────────────────────────── */

.wgl-scan-row {
  display: flex;
  align-items: flex-end;
  gap: 0.6rem;
}

.wgl-scan-row .wgl-field { flex: 1 1 auto; }

.wgl-scan-cam-btn { flex: 0 0 auto; white-space: nowrap; }

/* ── The camera scanner ─────────────────────────────────────────
   Its own overlay rather than a WglDialog, and for once that is not a second
   modal implementation for the sake of it: this one has to close ITSELF the
   instant a barcode resolves, which none of the four WglDialog kinds can do —
   they close on OK, on Cancel or on the ×. The previous version worked around
   that by grafting a <video> into a confirm()'s body on a 30ms timer and then
   synthesising a click on its close button. See CameraScan.open().

   Escape and a backdrop click both close it, exactly as every WglDialog does,
   so it is not a trap. */
.wgl-scanmodal {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.1rem;
  background: rgba(17, 17, 17, 0.9);
}

.wgl-scanmodal-box {
  width: 100%;
  max-width: 27rem;
  text-align: center;
  padding: 1.1rem;
  border-radius: var(--bs-border-radius);
  border: 1px solid var(--bs-border-color);
  background: var(--bs-body-bg);
  color: var(--bs-body-color);
}

.wgl-scanmodal-title {
  margin: 0 0 0.7rem;
  font-size: 1rem;
  font-weight: 700;
}

.wgl-scanmodal-actions {
  display: flex;
  gap: 0.5rem;
  justify-content: center;
  flex-wrap: wrap;
}

/* The live view. Bordered heavily and on black so the frame edge is obvious when
   somebody is lining a label up in it. */
.wgl-scan-video {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 12px;
  border: 2px solid var(--wgl-black);
  background: var(--wgl-black);
}

/* Two lines of room reserved. Every failure this component has lands here rather
   than closing the modal — no camera, permission refused, no decoder, an
   unreadable photo — and a status line that grows pushes the buttons out from
   under the finger that is reaching for them. */
.wgl-scan-status {
  min-height: 2.4rem;
  margin: 0.6rem 0 0.8rem;
  font-size: 0.8rem;
  line-height: 1.45;
  color: var(--bs-secondary-color);
  text-align: center;
}

/* ── Expense report: the category breakdown ─────────────────
   The bar is the SERVER's percentage. No ratio is worked out here.

   `wgl-exp-slice-*`, not `wgl-slice-*`. These used to share the dashboard's
   `.wgl-slice` names while being a different component with a different number of
   cells — five here, four there. Since this block sits LATER in the file it won,
   so every "Stock by category" row on the dashboard was laid out on this grid: its
   four cells took the first four of five tracks and left a dead 6rem column on the
   end, and it inherited a row border and padding it was never drawn with. Nothing
   reported it, because a class name collision is not an error. */

.wgl-exp-slice {
  display: grid;
  grid-template-columns: 10rem 1fr 6rem 3.5rem 6rem;
  align-items: center;
  gap: 0.6rem;
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--bs-border-color);
  font-size: 0.86rem;
}

.wgl-exp-slice:last-child { border-bottom: 0; }
.wgl-exp-slice-name { font-weight: 600; }

.wgl-exp-slice-bar {
  height: 0.55rem;
  border-radius: var(--bs-border-radius-pill);
  background: var(--bs-tertiary-bg);
  overflow: hidden;
}

.wgl-exp-slice-fill {
  display: block;
  height: 100%;
  background: var(--wgl-yellow);
}

.wgl-exp-slice-count,
.wgl-exp-slice-pct {
  color: var(--bs-secondary-color);
  font-variant-numeric: tabular-nums;
  text-align: end;
}

.wgl-exp-slice-amount { text-align: end; font-variant-numeric: tabular-nums; }

/* The category breakdown, now a section of the Expenses panel rather than a card of
   its own. It reports the FILTERED set, so it belongs under the filters and above
   the rows — the same order the legacy prints it in. The rule below it is what
   separates "what this came to" from "what made it up". */
.wgl-exp-breakdown {
  margin-bottom: 1rem;
  padding-bottom: 0.9rem;
  border-bottom: 1px solid var(--bs-border-color);
}

.wgl-expense-row {
  display: grid;
  grid-template-columns: 5.5rem 9rem 1fr auto 7rem 6rem;
  align-items: center;
  gap: 0.6rem;
  padding: 0.45rem 0.5rem;
  border-bottom: 1px solid var(--bs-border-color);
  font-size: 0.86rem;
}

.wgl-expense-row:last-child { border-bottom: 0; }

/* A bill whose period has come round with nothing entered against it. */
.wgl-expense-row.is-due { background: var(--s-wgl-tint-bg-2); }

.wgl-expense-date,
.wgl-expense-method { color: var(--bs-secondary-color); font-variant-numeric: tabular-nums; }
.wgl-expense-cat { font-weight: 600; }
.wgl-expense-note { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wgl-expense-amount { text-align: end; font-variant-numeric: tabular-nums; }

@media (max-width: 900px) {
  .wgl-exp-slice { grid-template-columns: 1fr auto; }
  .wgl-exp-slice-bar { grid-column: 1 / -1; }
  .wgl-expense-row { grid-template-columns: 1fr auto; row-gap: 0.15rem; }
}

/* ── Shop settings ──────────────────────────────────────────
   The warning at the top is load-bearing: it is the reason an editable
   settings page is safe at all. */

.wgl-settings-note p { margin: 0 0 0.5rem; line-height: 1.55; }
.wgl-settings-note p:last-child { margin-bottom: 0; }

/* The unit and the "Changed" pill are siblings of the label text inside
   `.wgl-field-label`, and JSX drops a whitespace-only child that spans a newline —
   so nothing separated them and the labels read "QUOTATION VALIDITYdays",
   "COLLECTION WINDOWdays", "FIRST MARKDOWN ATdays". The space belongs in CSS rather
   than as a hand-typed `{' '}` in the markup, because it is a property of how these
   two parts sit together, not of one screen's template. In em so it tracks the 9.5px
   label rather than being a pixel guess at one font size. */
.wgl-unit {
  margin-inline-start: 0.5em;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--bs-secondary-color);
}

.wgl-field-label .wgl-status-pill {
  margin-inline-start: 0.5em;
  font-size: 0.62rem;
  padding: 0.05rem 0.4rem;
}

/* ── The weekly report, as something to paste ───────────────── */

.wgl-share { margin-top: 1.1rem; }

.wgl-share-text {
  width: 100%;
  font-family: var(--bs-font-monospace, monospace);
  font-size: 0.82rem;
  line-height: 1.5;
  resize: vertical;
}

/* ── Remote approval ────────────────────────────────────────
   Two buttons, or the chip that says which was chosen. */

.wgl-remote-row,
.wgl-remote-chip {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0.35rem 0 0.9rem;
}

.wgl-remote-at {
  color: var(--bs-secondary-color);
  font-variant-numeric: tabular-nums;
  font-size: 0.85rem;
}

/* ── The Hamster POS shadow catalogue ───────────────────────
   A scanned code that IS something, but not ours. This has to read as a stop, not
   as a suggestion: the shortlist below it is suppressed precisely so the cashier
   does not resolve a definite answer by picking a near-miss. */

.wgl-pos-foreign {
  border: 2px solid var(--bs-danger);
  border-radius: 12px;
  background: rgba(var(--bs-danger-rgb), 0.06);
  padding: 0.75rem 0.9rem;
}

.wgl-pos-foreign-head {
  font-family: var(--s-wgl-display-font, inherit);
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--bs-danger);
}

.wgl-pos-foreign-name {
  margin-top: 0.4rem;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--bs-body-color);
}

.wgl-pos-foreign-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 0.25rem;
  font-size: 0.8rem;
  color: var(--bs-secondary-color);
}

.wgl-pos-foreign-note {
  margin-top: 0.45rem;
  font-size: 0.78rem;
  line-height: 1.45;
  color: var(--bs-secondary-color);
}

/* ── Shadow-catalogue banner (Products) ─────────────────────
   Two different findings, deliberately different weights. A duplicate barcode is
   information — the item it means is in the list below. A Hamster-only product is a
   stop, and there is nothing below it. */

.wgl-shadow-banner {
  border: 1.5px solid var(--s-wgl-accent-fg);
  border-radius: 12px;
  background: var(--s-wgl-tint-bg-2);
  padding: 0.7rem 0.9rem;
  margin-bottom: 0.75rem;
}

.wgl-shadow-banner.is-foreign {
  border: 2px solid var(--bs-danger);
  background: rgba(var(--bs-danger-rgb), 0.06);
}

.wgl-shadow-head {
  font-family: var(--s-wgl-display-font, inherit);
  font-weight: 700;
  font-size: 0.7rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--bs-body-color);
}

.wgl-shadow-banner.is-foreign .wgl-shadow-head {
  color: var(--bs-danger);
}

.wgl-shadow-body {
  margin-top: 0.3rem;
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--bs-body-color);
}

/* An active restriction that arrived from another screen, beside the item count on
   the Products list. It is not one of the selects, so it has to say so and carry its
   own Clear — an invisible filter just makes the catalogue look short. */
.wgl-studio-only {
  display: inline-block;
  padding: 0.1rem 0.45rem;
  margin-right: 0.4rem;
  border: 1.5px solid var(--bs-border-color);
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  vertical-align: middle;
}

/* The footnote under the KPI tiles, saying where the detail went. Deliberately the
   quietest thing in the card: plain muted text and two underlined links, no button
   chrome and no enumeration. It is a signpost, and a signpost that competes with the
   numbers above it is in the way. */
.wgl-dash-reports {
  margin-top: 0.9rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--bs-border-color);
  font-size: 0.78rem;
  line-height: 1.6;
  color: var(--bs-secondary-color);
}

.wgl-dash-reports a {
  color: inherit;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: var(--bs-border-color);
}

.wgl-dash-reports a:hover {
  color: var(--bs-body-color);
  text-decoration-color: currentColor;
}

/* ── Studio images (Shop dashboard) ─────────────────────────
   The third card, which is where the legacy had it: Action center, the numbers, then
   this. It is a work queue, not a warning, so it stays in the neutral panel language
   until something actually fails. */

/* The panel is a .wgl-panel like its two neighbours, so the inner box carries no
   border of its own — that would be a frame inside a frame. */
.wgl-studio-panel .wgl-studio-gap {
  border: 0;
  border-radius: 0;
  padding: 0;
  margin-bottom: 0;
  background: none;
}

.wgl-studio-panel .wgl-panel-head {
  justify-content: flex-start;
  gap: 0.5rem;
  flex-wrap: wrap;
}

/* The list under the panel — the legacy's #stuList. Compact rows: the full product
   card lives on the Products screen and a row here opens it. */
.wgl-studio-list:empty { display: none; }
.wgl-studio-list { margin-top: 0.75rem; }

.wgl-studio-rows {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin-top: 0.5rem;
  max-height: 28rem;
  overflow-y: auto;
}

/* ── The lookup row (legacy lkRow) ──────────────────────────
   The read-only form of the shared product card: a compact four-line row —
   chips, title, meta, supplier — with the price and the actions on the end.
   Denser than the editable card on purpose, because this is a list you read
   rather than a form you fill in. */

.wgl-lkrow {
  display: grid;
  grid-template-columns: 3.4rem minmax(0, 1fr) auto;
  gap: 0.75rem;
  align-items: center;
  padding: 0.6rem 0.8rem;
  background: var(--bs-body-bg);
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-card-border-radius);
  box-shadow: var(--s-shadow-xs);
}

/* The photo goes first on a narrow screen; the actions wrap under the body. */
@media (max-width: 48rem) {
  .wgl-lkrow { grid-template-columns: 3.4rem minmax(0, 1fr); }
  .wgl-lk-side { grid-column: 1 / -1; align-items: flex-start; }
}

.wgl-lkrow .wgl-product-photo {
  width: 3.4rem;
  height: 3.4rem;
  border-radius: 8px;
}

.wgl-lk-main { min-width: 0; display: flex; flex-direction: column; gap: 0.15rem; }

.wgl-lk-chips {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.35rem;
}

/* The quotation and item number, in the brand fill. Black text on yellow — the
   contrast rule for --wgl-yellow is that it is a fill and never a text colour. */
.wgl-lk-no {
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  background: var(--s-wgl-accent-fg);
  color: #000;
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.wgl-lk-status {
  padding: 0.05rem 0.45rem;
  border-radius: 999px;
  border: 1.5px solid currentColor;
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  white-space: nowrap;
}

.wgl-lk-status.is-approved { color: var(--bs-success); }
.wgl-lk-status.is-dead { color: var(--bs-danger); }
.wgl-lk-status.is-open { color: var(--bs-secondary-color); }

.wgl-lk-title {
  font-weight: 700;
  font-size: 0.92rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wgl-lk-meta,
.wgl-lk-who {
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--bs-secondary-color);
}

/* The supplier line reads as a reference, not as body text — the legacy tinted it. */
.wgl-lk-who { color: var(--bs-primary); }

/* The barcode, in a bordered pill so it is scannable by eye against the meta. */
.wgl-lk-code {
  display: inline-block;
  padding: 0.02rem 0.35rem;
  border: 1px solid var(--bs-border-color);
  border-radius: 5px;
  font-family: var(--bs-font-monospace, monospace);
  font-size: 0.72rem;
  letter-spacing: 0.02em;
}

.wgl-lk-side {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.15rem;
  white-space: nowrap;
}

.wgl-lk-price {
  font-size: 1.15rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.wgl-lk-payout {
  font-size: 0.68rem;
  color: var(--bs-secondary-color);
}

/* The row's own actions sit in the side column, so they need none of the
   space-between a form card's foot uses. Wrapped, because the catalogue row carries
   four (Edit, Label, Open, Mark sold) where the dashboard's lists carry one or two. */
.wgl-lk-side .wgl-item-foot {
  margin-top: 0.35rem;
  display: flex;
  gap: 0.35rem;
  justify-content: flex-end;
  flex-wrap: wrap;
  border: 0;
  padding: 0;
}

/* The selection checkbox leads the row on a screen with bulk actions — it is what
   the toolbar's greyed buttons are waiting for. A list with nothing to select for
   passes no set and gets no column. */
.wgl-lkrow.has-pick { grid-template-columns: auto 3.4rem minmax(0, 1fr) auto; }

.wgl-lk-pick {
  display: flex;
  align-items: center;
  margin: 0;
}

@media (max-width: 48rem) {
  .wgl-lkrow.has-pick { grid-template-columns: auto 3.4rem minmax(0, 1fr); }
}

/* The legacy's `lkgal`: the rest of the item's photographs, under its meta line. The
   main shot is the thumbnail at the head of the row and is filtered out in the
   renderer — drawing it here as well says the item has one photograph more than it
   does. */
.wgl-lk-gal {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin-top: 0.3rem;
}

.wgl-lk-gal img {
  display: block;
  width: 1.9rem;
  height: 1.9rem;
  object-fit: cover;
  border-radius: 5px;
  border: 1px solid var(--bs-border-color);
}


/* Red, and never the brand yellow: yellow reads as store credit in this app. */
.wgl-tag-danger {
  background: rgba(var(--bs-danger-rgb), 0.12);
  color: var(--bs-danger);
  border-color: transparent;
}

/* Why the NEEDS ATTENTION chip fired, beside it — the label says why, so nobody
   opens the item to find out. */
.wgl-attention-why {
  font-size: 0.66rem;
  color: var(--bs-danger);
  align-self: center;
}

/* The tick that stands the attention flags down. A quiet inline control, not a
   button: it is a fact about the item, and the row already has three buttons. */
.wgl-validated-tick {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.68rem;
  color: var(--bs-secondary-color);
  border: 1px solid var(--bs-border-color);
  border-radius: 9px;
  padding: 0 0.45rem;
  cursor: pointer;
  user-select: none;
}

.wgl-validated-tick input { margin: 0; width: auto; }

.wgl-validated-tick.is-on {
  background: var(--s-wgl-tint-bg-2);
  border-color: var(--s-wgl-accent-fg);
  color: var(--bs-body-color);
}

/* "✉ Informed 21/08" — the stamp is standing, and clicking clears it. */
.wgl-saved-actions-bar .is-informed {
  background: var(--s-wgl-tint-bg-2);
  border-color: var(--s-wgl-accent-fg);
}

.wgl-studio-row:hover { border-color: var(--s-wgl-accent-fg); }

.wgl-studio-th {
  width: 2.6rem;
  height: 2.6rem;
  flex: 0 0 auto;
  object-fit: cover;
  border-radius: 7px;
  border: 1px solid var(--bs-border-color);
}

.wgl-studio-th-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bs-tertiary-bg);
}

.wgl-studio-row-main { min-width: 0; flex: 1 1 auto; }

.wgl-studio-row-top {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  flex-wrap: wrap;
}

.wgl-studio-ref { font-weight: 700; font-size: 0.78rem; }

.wgl-studio-row-desc {
  font-size: 0.82rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wgl-studio-row-meta {
  font-size: 0.72rem;
  color: var(--bs-secondary-color);
}

/* Red, and never the brand yellow: yellow reads as store credit in this app. */
.wgl-studio-chip {
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  background: rgba(var(--bs-danger-rgb), 0.12);
  color: var(--bs-danger);
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  white-space: nowrap;
}

.wgl-studio-gap:empty { display: none; }

.wgl-studio-gap {
  border: 1.5px solid var(--bs-border-color);
  border-radius: 14px;
  background: var(--bs-body-bg);
  padding: 0.85rem 1rem;
  margin-bottom: 0.9rem;
}

.wgl-studio-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.wgl-studio-title {
  font-family: var(--s-wgl-display-font, inherit);
  font-weight: 700;
  font-size: 0.8rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.wgl-studio-sub,
.wgl-studio-status,
.wgl-studio-done {
  font-size: 0.8rem;
  line-height: 1.5;
  color: var(--bs-secondary-color);
}

.wgl-studio-status { margin-top: 0.5rem; }

.wgl-studio-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.6rem;
}

.wgl-studio-size { width: auto; min-width: 16rem; }

/* Progress. The fraction is set inline from the server's counts — the only inline
   style here, because it is a value rather than a rule.

   Scaled, not resized: the fill is a solid block with no text, border or children, so
   scaleX renders identically to a width change and animates on the compositor instead
   of forcing layout. */
.wgl-studio-bar {
  height: 6px;
  border-radius: 3px;
  background: var(--bs-tertiary-bg);
  overflow: hidden;
  margin-top: 0.5rem;
}

.wgl-studio-bar > span {
  display: block;
  width: 100%;
  height: 100%;
  background: var(--s-wgl-accent-fg);
  transform-origin: left center;
  transition: transform 0.4s ease;
}

/* Failures. This is the part that earns the table behind it: without a reason in
   words, a refused photograph is retried forever and nobody knows why. */
.wgl-studio-fails {
  margin-top: 0.8rem;
  border: 2px solid var(--bs-danger);
  border-radius: 12px;
  background: rgba(var(--bs-danger-rgb), 0.05);
  padding: 0.7rem 0.85rem;
}

.wgl-studio-fail-head {
  font-family: var(--s-wgl-display-font, inherit);
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--bs-danger);
}

.wgl-studio-fail-list {
  max-height: 14rem;
  overflow-y: auto;
  margin-top: 0.45rem;
}

.wgl-studio-fail {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.4rem 0.8rem;
  align-items: center;
  padding: 0.35rem 0;
  border-top: 1px solid rgba(var(--bs-danger-rgb), 0.25);
  font-size: 0.8rem;
}

.wgl-studio-fail-why {
  grid-column: 1 / -1;
  color: var(--bs-danger);
  font-size: 0.75rem;
}

.wgl-studio-fail-done {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--bs-secondary-color);
}

.wgl-studio-fail-note {
  margin-top: 0.5rem;
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--bs-secondary-color);
}

/* ── Pending money, on the expenses screen and its printed sheet ──────────────
   A bill that has ARRIVED and has not been PAID. It is deliberately never shown
   in the amount column beside the paid figure and never summed with it: the two
   answer different questions, and a reader who adds them gets a number that is
   true of nothing. Amber rather than red — this is not an error, it is a normal
   state a bill passes through — and set apart on its own line so the eye cannot
   read it as part of the total above. */
/* ONE strip under the row for everything secondary — the pending balance and both
   actions — rather than a full-width line each.

   Each of them used to span the grid on its own, so a loan with a pending balance
   and a bill to settle stood FOUR rows tall with two full-size yellow buttons in it,
   and eight such expenses filled the screen. The information has not changed and nor
   has its order; it is one line now, and the buttons are row-sized rather than
   form-sized. `flex-wrap` is what keeps that true on a narrow window instead of
   trading the height back for a horizontal scrollbar. */
.wgl-expense-actions {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.75rem;
  margin-top: 0.3rem;
}

.wgl-expense-pending {
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--wgl-pending-text);
}

/* The summary tile carrying the same figure. It sits on the BLACK totals bar, not
   on a card, so it takes the lifted twin rather than --wgl-pending-text: the dark
   amber that reads well on paper is barely 3:1 on black. Same idea, legible ground. */
.wgl-totals .wgl-total.is-pending .wgl-total-value {
  color: var(--wgl-amber-lt);
}

/* "Loans to repay" — a liability rather than spending, and a different one again from
   the amber tile beside it: pending is a bill the shop has not paid yet, this is money
   somebody else already paid ON ITS BEHALF. Red for the same reason `.wgl-tag-owed` is,
   and the LIFTED red for the same reason its neighbour takes the lifted amber: this
   tile sits on the black totals bar, where --wgl-red is barely 3:1. */
.wgl-totals .wgl-total.is-owed .wgl-total-value {
  color: var(--wgl-red-lt);
}

/* ── Reports ────────────────────────────────────────────────
   The panes the legacy carried that this port had thinned: the pipeline's two
   segmented bars and its aging table, the filter strips the four list panes
   wear, and the weekly report's message box. Tokens only — no colour literals. */

/* A month's caption: how many consignments arrived, and what sold. Without it
   the flow chart shows five heights and no way to tell a quiet month from a
   month with one large consignment in it. */
.wgl-flow-sub {
  text-align: center;
  font-size: 0.66rem;
  color: var(--bs-secondary-color);
  font-variant-numeric: tabular-nums;
}

/* ── Segmented bar ──
   One row, one hundred per cent, one segment per state. Zero-count segments are
   left out by the caller rather than drawn at 0% — a hairline segment that can
   be hovered but carries nothing is worse than an absent one. */
.wgl-segbar {
  display: flex;
  height: 0.85rem;
  margin-bottom: 0.5rem;
  border-radius: var(--bs-border-radius-pill);
  background: var(--bs-secondary-bg);
  overflow: hidden;
}

.wgl-seg {
  display: block;
  height: 100%;
  min-width: 2px;
}

.wgl-seg.is-st-draft { background: var(--bs-secondary-bg); }
.wgl-seg.is-st-submitted { background: var(--wgl-yellow); }
.wgl-seg.is-st-approved { background: var(--wgl-green); }
.wgl-seg.is-st-rejected { background: var(--wgl-red); }
.wgl-seg.is-st-cancelled { background: var(--wgl-gray); }

.wgl-seg.is-band-0 { background: var(--wgl-green); }
.wgl-seg.is-band-1 { background: var(--wgl-yellow); }
.wgl-seg.is-band-2 { background: var(--wgl-amber); }
.wgl-seg.is-band-3 { background: var(--wgl-red); }

/* A second heading inside a pane that already has one. */
.wgl-panel-head.is-second {
  margin-top: 1.4rem;
}

.wgl-panel-actions {
  margin-inline-start: auto;
  display: flex;
  gap: 0.4rem;
}

.wgl-panel-actions.is-block {
  margin-inline-start: 0;
  margin-top: 0.7rem;
}

/* ── Filter strip ──
   Wraps rather than scrolls: these are four or five short controls, and a filter
   somebody cannot see is a filter they cannot clear — which is how a list ends up
   looking mysteriously short. The Clear button sits with them for the same reason. */
.wgl-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: 0.6rem;
  margin-bottom: 0.9rem;
  padding-bottom: 0.8rem;
  border-bottom: 1px solid var(--bs-border-color);
}

.wgl-filters .wgl-field {
  margin-bottom: 0;
  flex: 1 1 11rem;
}

/* The strip's own caption, on a line of its own above the controls. It is the
   legacy's wording, and it earns its line because these controls sit in the same
   panel as a list they NARROW — next to an entry form that CREATES. Two rows of
   labelled boxes with nothing saying which is which is how somebody types an
   expense into a filter. */
.wgl-filters-label {
  flex: 1 0 100%;
}

/* The search box earns more room than a date or a status list. */
.wgl-filters .wgl-field:first-child {
  flex: 2 1 18rem;
}

/* ── Report table ──
   The aging list is genuinely tabular — six short columns compared down the page
   — so it is a table rather than the card rows the other panes use. It scrolls
   inside its own box; the page must never scroll sideways. */
.wgl-tbl-scroll {
  overflow-x: auto;
}

.wgl-rtbl {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.85rem;
}

.wgl-rtbl th {
  text-align: start;
  padding: 0.45rem 0.6rem;
  font-family: var(--header-font), 'Space Grotesk', sans-serif;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--bs-secondary-color);
  border-bottom: 2px solid var(--wgl-yellow);
  white-space: nowrap;
}

.wgl-rtbl td {
  padding: 0.5rem 0.6rem;
  border-bottom: 1px solid var(--bs-border-color);
  vertical-align: middle;
}

.wgl-rtbl tbody tr:hover {
  background: var(--bs-tertiary-bg);
}

.wgl-rtbl .is-num {
  text-align: end;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.wgl-rtbl .is-act {
  text-align: end;
  white-space: nowrap;
}

/* ── Weekly report ──
   Monospaced, because it is a message that will be pasted somewhere with no
   proportional font and its columns are meant to line up when it lands. */
.wgl-report-text {
  width: 100%;
  font-family: ui-monospace, Consolas, monospace;
  font-size: 0.78rem;
  line-height: 1.55;
}

/* ── A tab that leaves ──
   Expenses is a screen of its own. The marker is what stops the tab reading as
   broken when the pane it appears to select never arrives. */
.wgl-report-tabs .wgl-cart-tab.is-link {
  gap: 0.3rem;
}

.wgl-tab-out {
  font-size: 0.75em;
  opacity: 0.7;
}

/* The intake chart is a single series and sits under a chart four bars wide, so
   it gets a shorter plot: at the full 9rem one lonely bar per month reads as the
   more important of the two, which is backwards — it is the supporting figure. */
.wgl-flow.is-short .wgl-flow-bars {
  height: 5rem;
}

/* ── Report lists without a status pill ─────────────────────
   `.wgl-saved` lays out the quotation archive and the till's orders: a fixed
   7.5rem number, a fixed 6.5rem STATUS PILL, then the flexible track for the
   description. Payouts, store credit and cash-outs reuse the row but have no
   pill — so a supplier's NAME landed in the pill track and was clipped to
   "Diala bader f(", while "9 sold · 154 on the shelf" sat in the flexible one
   with room to spare.

   Same fault `.wgl-crm-row` was carved out of `.wgl-saved` for. Here the row
   shape is right and only the tracks are wrong, so these two rules move the
   slack to the name rather than duplicating the component. */
.wgl-rlist-6 .wgl-saved {
  grid-template-columns: 7.5rem minmax(0, 1fr) 13rem 7.5rem 6.5rem 6.5rem;
}

.wgl-rlist-5 .wgl-saved {
  grid-template-columns: 7.5rem minmax(0, 1fr) 11rem 9rem 6.5rem;
}

/* ── The payouts report's two levels ────────────────────────────
   The legacy's pane had a supplier group and that supplier's quotations indented
   beneath it, and a payout run reads the second level to see WHICH consignment
   produced the money. Restoring it means one list holds two kinds of row, so the
   two have to be told apart at a glance or the page reads as twice as many
   suppliers as the shop has.

   The group row leads with a CARET AND A COUNT rather than the contact number.
   Two document-looking codes in one column read as one flat list of documents —
   WGL-C-0005 sitting above WGL-Q-2433 is a contact number that looks like a
   consignment, and it was read as one. The supplier's number moved under their
   name, still searchable, no longer claiming to be a document. */
.wgl-rlist-6 .wgl-saved.wgl-saved-group {
  grid-template-columns:
    4.5rem minmax(0, 1fr) 12rem 7.5rem 6.5rem 8.5rem auto;
  font-weight: 600;
}

.wgl-saved-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-variant-numeric: tabular-nums;
  font-size: 0.85rem;
  color: var(--bs-secondary-color);
}

/* Holds its width so the supplier's name does not shift sideways by a pixel
   every time a group is opened or closed. */
.wgl-caret {
  display: inline-block;
  width: 0.85em;
  text-align: center;
  color: var(--bs-body-color);
}

/* An open group is the head of a block rather than a row on its own, so it drops
   its rounded foot and sits flush on what it opened. */
.wgl-saved.wgl-saved-group.is-open {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}

/* The row toggles; this leaves the report. Ghost weight because going to the
   account is the rarer of the two — the breakdown is what a payout run wants. */
.wgl-saved-open {
  justify-self: end;
  white-space: nowrap;
}

/* ── One consignment, under its supplier ────────────────────────
   Inset, quieter, and pulled up against the list's own gap: three signals, and
   all three are needed for it to read as subordinate while the eye is scanning a
   column of money.

   Its own four tracks. It deliberately does NOT borrow the group's, because the
   indent has already broken the alignment and a column that is nearly-but-not-
   quite under its heading is worse than one that plainly is not. */
.wgl-rlist-6 .wgl-saved.wgl-saved-sub {
  /* Five tracks: the fifth holds the consignment's own two actions. Declared
     here rather than beside those buttons further down, where a later rule of
     equal specificity would have undone the mobile collapse between them. */
  grid-template-columns: 7.5rem minmax(0, 1fr) 13rem 8.5rem auto;

  /* `width: auto`, and it is load-bearing. `.wgl-saved` sets `width: 100%`, and
     100% of the list PLUS a start margin is wider than the list — the sub-rows
     hung 1.75rem past the group row's right edge, which is the one place the two
     levels have to agree. The list is a flex column, so stretch already sizes the
     row and the margin now takes its width out of it rather than adding to it. */
  width: auto;
  margin-inline-start: 1.75rem;
  margin-top: -0.35rem;
  border-style: dashed;
  background: var(--bs-tertiary-bg);
  font-size: 0.92em;
  font-weight: 400;
}

/* The date takes the flexible track and reads from the LEFT, which is what puts
   the slack between it and the figures instead of in the middle of the row.

   `.wgl-saved-date` is end-aligned by default so a column of dates lines up under
   its header, and that is right on the archive grid where the track is 6rem wide.
   Here the flexible track is the wide one: an end-aligned date was pinned to the
   far side of it and the counts to the far side of the next, leaving a lake of
   empty row between the quotation number and anything that said something about
   it. */
.wgl-rlist-6 .wgl-saved.wgl-saved-sub .wgl-saved-date {
  text-align: start;
}

/* The next supplier needs the full gap back, or the indent is the only thing
   telling two groups apart and that is not enough while reading figures. */
.wgl-saved.wgl-saved-sub + .wgl-saved:not(.wgl-saved-sub) {
  margin-top: 0.5rem;
}

/* ── What can be done to the opened supplier ────────────────────
   The legacy's six buttons. They sit in the opened block rather than on every
   row, because six buttons on each of twenty-five rows is not a list anybody
   reads down — and the press that opens a supplier is the same press that says
   which one is being worked on.

   Inset to the sub-rows' line so the whole opened block reads as one thing
   hanging off the supplier, and it wraps rather than widening the row: on a
   narrow screen these become two lines of buttons, never a horizontal scroll
   across a panel of money. */
.wgl-saved-actions-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  align-items: center;
  margin-inline-start: 1.75rem;
  margin-top: -0.2rem;
  padding: 0.45rem 0.7rem;
  border: 1px dashed var(--bs-border-color);
  border-radius: var(--bs-border-radius-sm);
  background: var(--bs-tertiary-bg);
}

@media (max-width: 860px) {
  .wgl-saved-actions-bar { margin-inline-start: 0.9rem; }
}

/* ── The sold items behind a supplier's numbers ─────────────────
   The legacy unfolded these in place: press "Sold items" and the receipts open
   under the row, press again and they close. This port sent the operator to
   another screen for it, which answers the question and costs the report — the
   page they were on, the other suppliers they had opened, and their filters.

   A block rather than a row, so it does NOT take a place on the list's grid. The
   rows inside it carry their own tracks; borrowing the group's would put a
   description under a heading it does not belong to, and the indent has already
   broken that alignment anyway. */
.wgl-saved-items {
  width: auto;
  margin-inline-start: 1.75rem;
  margin-top: -0.2rem;
  padding: 0.25rem 0.6rem 0.4rem;
  border: 1px dashed var(--bs-border-color);
  border-radius: var(--bs-border-radius-sm);
  background: var(--bs-body-bg);
}

/* Five tracks: when it sold, what it was, which documents it is on, what it rang
   up, and the supplier's share of that. The last is the column somebody is
   actually reading down — it is what the row above claims and this list proves. */
.wgl-rlist-6 .wgl-saved.wgl-saved-item {
  grid-template-columns: 6rem minmax(0, 1fr) 13rem 7rem 8.5rem;
  width: auto;
  margin: 0;
  padding-block: 0.3rem;
  border: 0;
  border-bottom: 1px solid var(--bs-border-color);
  border-radius: 0;
  background: transparent;
  font-size: 0.9em;
  font-weight: 400;
}

.wgl-rlist-6 .wgl-saved.wgl-saved-item:hover { background: var(--bs-tertiary-bg); }

/* Reading from the left, like the sub-row's date and for the same reason: the
   slack belongs between the description and the figures, not inside the row. */
.wgl-rlist-6 .wgl-saved.wgl-saved-item .wgl-saved-date { text-align: start; }

/* Except in the money columns, where a column of end-aligned figures is the whole
   point of having them in their own tracks. */
.wgl-rlist-6 .wgl-saved.wgl-saved-item .wgl-saved-date.wgl-money { text-align: end; }

/* The footer sums what is DRAWN, so it must not read as one more item. No rule
   under it, and it carries the weight the rows deliberately gave up. */
.wgl-rlist-6 .wgl-saved.wgl-saved-item-sum {
  border-bottom: 0;
  padding-top: 0.45rem;
  font-weight: 600;
}

.wgl-saved-items .wgl-empty {
  padding: 0.5rem 0.2rem;
  font-size: 0.9em;
}

/* The next supplier needs the full gap back — same reason the sub-rows do, and
   an unfolded list is the widest thing that can sit between two groups. */
.wgl-saved-items + .wgl-saved:not(.wgl-saved-sub) { margin-top: 0.5rem; }

@media (max-width: 860px) {
  .wgl-saved-items { margin-inline-start: 0.9rem; }

  .wgl-rlist-6 .wgl-saved.wgl-saved-item {
    grid-template-columns: 1fr auto;
    row-gap: 0.15rem;
  }
}

/* The two actions that belong to ONE consignment — its own statement and its own
   sold items. They sit at the end of the sub-row rather than in the supplier's bar,
   because that is what they are scoped to; Record payout and → Credit are not down
   here for the same reason, since both settle the person.
 */

.wgl-saved-subacts {
  display: inline-flex;
  gap: 0.3rem;
  justify-self: end;
  white-space: nowrap;
}

/* Quieter than the supplier bar's: these are the third level down, and at full
   strength three rows of buttons is all the eye finds on the panel. */
.wgl-saved-subacts .wgl-btn {
  padding-block: 0.15rem;
  font-size: 0.85em;
}

/* Both collapse to the archive's two-column stack. The modifiers above are more
   specific than the base rule, so they have to say so themselves. */
@media (max-width: 860px) {
  .wgl-rlist-6 .wgl-saved.wgl-saved-group,
  .wgl-rlist-6 .wgl-saved.wgl-saved-sub {
    grid-template-columns: 1fr auto;
    row-gap: 0.2rem;
  }

  .wgl-rlist-6 .wgl-saved.wgl-saved-sub { margin-inline-start: 0.9rem; }
}
