/* ==========================================================================
   MARMOCHA — shared styles for index.html AND product.html
   (Base design unchanged; sidebar / cart / product-detail styles added.)
   ========================================================================== */

/* ===== Base ===== */
* { box-sizing: border-box; }
:root {
  --bg: #faf8f5;
  --card: #ffffff;
  --ink: #2c2622;
  /* Secondary text and rules, darkened in P035-C14: #7a716a measured about
     4.8:1 on white and was used at .68–.78rem, which is where readability was
     lost. #635b54 is about 6.5:1 and keeps the same warm hue. */
  --muted: #635b54;
  --line: #e0d7cc;
  --accent: #b5643c;
  --accent-dark: #98502e;
  --ok: #2f7d4f;
  --radius: 14px;
  --shadow: 0 6px 24px rgba(0,0,0,.08);

  /* Sidebar widths (JS may change --sidebar-width when you drag) */
  --sidebar-width: 270px;
  --sidebar-collapsed-width: 60px;
}
body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: var(--ink);
  background: var(--bg);
  line-height: 1.55;
}
.wrap { max-width: 1080px; margin: 0 auto; padding: 0 20px; }
a { color: var(--accent); }
h1, h2 { line-height: 1.2; }

/* ===== Header ===== */
.site-header {
  position: sticky; top: 0; z-index: 20;
  background: rgba(255,255,255,.9);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}
.header-inner { display: flex; align-items: center; gap: 16px; padding: 12px 20px; flex-wrap: wrap; }
.brand { font-weight: 700; font-size: 1.25rem; letter-spacing: .3px; text-decoration: none; color: var(--ink); white-space: nowrap; display: inline-flex; align-items: center; gap: 8px; }
.brand-mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 8px;
  background: var(--accent); color: #fff; font-weight: 800; font-size: 1rem;
}
.search {
  flex: 1; min-width: 0;
  padding: 10px 14px; border: 1px solid var(--line); border-radius: 999px;
  font-size: 1rem; background: #fff;
}
.search:focus { outline: 2px solid var(--accent); border-color: transparent; }

/* Header action buttons (cart indicator + sidebar toggle) */
.header-actions {
  display: flex; gap: 8px; align-items: center;
  /* THREE CONTROLS LIVE HERE NOW — cart, language and the way in or out.
     They wrap onto a second line rather than widening the page, and
     min-width:0 lets them actually give way instead of insisting on
     their content width. */
  flex-wrap: wrap; justify-content: flex-end; min-width: 0;
}
.icon-btn {
  border: 1px solid var(--line); background: #fff; color: var(--ink);
  border-radius: 999px; padding: 9px 14px; cursor: pointer;
  font-size: .95rem; white-space: nowrap;
}
.icon-btn:hover { border-color: var(--accent); }
#sb-toggle { display: inline-flex; align-items: center; justify-content: center; padding: 9px; }
#sb-toggle svg { width: 20px; height: 20px; display: block; }

/* ON DESKTOP THERE IS ONLY ONE HAMBURGER.
   The sidebar has its own toggle (#sb-toggle-in) pinned at the far-left edge,
   and it stays visible even when the sidebar is collapsed to 64px, so the
   copy in the page header is a duplicate. Hidden rather than deleted from the
   HTML because MOBILE still needs it: below 768px the sidebar slides fully
   off-screen, taking #sb-toggle-in with it, and this button is then the only
   way to open the drawer. */
@media (min-width: 769px) {
  #sb-toggle { display: none; }
}

/* ==========================================================================
   OWNER BAR — the strip shown on the SHOP only while the owner is signed in
   --------------------------------------------------------------------------
   Deliberately dark: it must read instantly as "this is not part of the shop"
   so the owner always knows which hat they are wearing. It sits inside
   .site-header, above .header-inner, so the shop header itself is unchanged.
   ========================================================================== */
.owner-bar { background: var(--ink); color: #fff; font-size: .8rem; }
.owner-bar-inner {
  display: flex; align-items: center; gap: 12px;
  padding: 7px 20px; flex-wrap: wrap;
}
.owner-bar-tag {
  background: var(--accent); color: #fff; border-radius: 999px;
  padding: 1px 9px; font-size: .66rem; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase;
}
.owner-bar-who { color: rgba(255,255,255,.72); }
.owner-bar-who strong { color: #fff; }
.owner-bar-links { display: flex; align-items: center; gap: 6px; margin-inline-start: auto; flex-wrap: wrap; }
.owner-bar-links a,
.owner-bar-links button {
  color: #fff; text-decoration: none; font: inherit; cursor: pointer;
  background: rgba(255,255,255,.12); border: 1px solid rgba(255,255,255,.18);
  border-radius: 999px; padding: 3px 12px; white-space: nowrap;
}
.owner-bar-links a:hover,
.owner-bar-links button:hover:not(:disabled) { background: rgba(255,255,255,.24); }
.owner-bar-links button:disabled { opacity: .6; cursor: default; }

/* Phones: the name drops to its own line and the buttons spread out, rather
   than squeezing the shop header. */
@media (max-width: 560px) {
  .owner-bar-inner { gap: 8px; padding: 7px 14px; }
  .owner-bar-who { flex-basis: 100%; order: 2; }
  .owner-bar-links { margin-left: 0; order: 3; flex-basis: 100%; }
  .owner-bar-links a, .owner-bar-links button { flex: 1; text-align: center; }
}

@media print { .owner-bar { display: none !important; } }

/* ===== Hero ===== */
.hero { padding: 48px 0 30px; text-align: center; }
.hero h1 {
  margin: 0 0 10px; font-size: clamp(2.4rem, 6vw, 3.6rem);
  letter-spacing: 1px; color: var(--accent-dark); font-weight: 800;
}
.hero .tagline { margin: 0; color: var(--muted); font-size: 1.1rem; }

/* ===== Categories ===== */
.categories { display: flex; flex-wrap: wrap; gap: 8px; padding-top: 6px; padding-bottom: 22px; }
.chip {
  padding: 8px 16px; border: 1px solid var(--line); border-radius: 999px;
  background: #fff; cursor: pointer; font-size: .95rem; color: var(--ink);
}
.chip:hover { border-color: var(--accent); }
.chip.active { background: var(--accent); color: #fff; border-color: var(--accent); }

/* ===== Grid ===== */
.grid {
  display: grid; gap: 22px;
  grid-template-columns: repeat(4, minmax(0, 1fr)); /* max 4 products per row */
  align-items: stretch;                              /* equal card heights per row */
  padding-bottom: 30px;
}
@media (max-width: 900px) { .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 680px) { .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 420px) { .grid { grid-template-columns: 1fr; } }

/* ===== Product cards ===== */
.card {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; transition: transform .15s, box-shadow .15s;
  display: flex; flex-direction: column;
}
.card:hover { transform: translateY(-3px); box-shadow: var(--shadow); }
.card-media { position: relative; aspect-ratio: 4/3; background: #f0eae2; }
.card-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.media-link { display: block; width: 100%; height: 100%; }         /* clickable image */
.badge {
  position: absolute; top: 10px; left: 10px;
  background: #fff; color: var(--muted); font-size: .75rem;
  padding: 3px 9px; border-radius: 999px; border: 1px solid var(--line);
}
.badge.sold { background: #efe0da; color: var(--accent-dark); }
.card-body { padding: 14px; display: flex; flex-direction: column; gap: 4px; flex: 1; }
.card-name-link { text-decoration: none; color: inherit; display: block; }
.card-name { font-weight: 600; }
.card-name-link:hover .card-name { color: var(--accent-dark); }
.card-maker { font-size: .82rem; color: var(--muted); }
.card-price { margin-top: 6px; font-weight: 700; color: var(--accent-dark); font-size: 1.05rem; }

.empty { text-align: center; color: var(--muted); padding: 40px 0 60px; }

/* Wishlist heart (used on cards + product detail) */
.heart {
  position: absolute; top: 10px; right: 10px; z-index: 3;
  width: 34px; height: 34px; border-radius: 999px;
  border: 1px solid var(--line); background: rgba(255,255,255,.92);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; color: var(--muted); padding: 0;
}
.heart:hover { border-color: var(--accent); }
.heart svg { width: 18px; height: 18px; display: block; }
.heart.active { color: var(--accent); }
.heart.inline { position: static; top: auto; right: auto; }   /* inline on detail page */

/* THE PHOTO CONTROLS, AND WHO GETS A BOX (P035-C9B).

   These were gated on `body.edit-mode` — a browser boolean anybody could
   flip. The markup was written into every product card on the PUBLIC
   storefront and merely hidden, so the one reader who must never see an
   administrative control was one CSS rule away from it.

   `body.can-edit-media` is set by app.js from the capability the SERVER
   computed for the resolved session, and by nothing else. A customer, and
   any signed-in person without it, never gets the class — so the control
   never gets a box. The upload endpoints behind it were, and remain,
   guarded on the server; this rule decides only what is drawn. */
.photo-placeholder { display: flex; align-items: center; justify-content: center; height: 100%; color: var(--muted); font-size: .9rem; }
.card-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.photo-btn {
  position: absolute; bottom: 10px; right: 10px; display: none;
  background: rgba(255,255,255,.92); border: 1px solid var(--line);
  color: var(--ink); font-size: .75rem; padding: 5px 10px; border-radius: 999px; cursor: pointer;
}
.photo-btn:hover { border-color: var(--accent); }
body.can-edit-media .photo-btn { display: inline-block; }

/* Editing affordances that appear only for a session the server granted the
   capability to (the product detail "Add image", for one). Default is none:
   absence is the state an unauthorized reader gets. */
.edit-only { display: none; }
body.can-edit-media .edit-only { display: inline-flex; }

/* ===== Add to Cart + quantity controls (shared home + detail) ===== */
.cart-controls { margin-top: 10px; }
.add-cart {
  width: 100%; background: var(--accent); color: #fff; border: none;
  border-radius: 999px; padding: 10px; font-weight: 700; cursor: pointer; font-size: .95rem;
}
.add-cart:hover:not(:disabled) { background: var(--accent-dark); }
.add-cart:disabled { background: #cfc6bd; cursor: not-allowed; }
.qtybar { display: flex; align-items: center; justify-content: center; gap: 10px; }
.qtybar-num { min-width: 24px; text-align: center; font-weight: 700; }
.qty-btn {
  width: 30px; height: 30px; border: 1px solid var(--line);
  background: #fff; border-radius: 8px; cursor: pointer; font-size: 1.1rem; line-height: 1;
}
.qty-btn:hover:not(:disabled) { border-color: var(--accent); }
.qty-btn:disabled { opacity: .4; cursor: not-allowed; }
.qty-trash {
  width: 30px; height: 30px; border: 1px solid var(--line); background: #fff;
  border-radius: 8px; cursor: pointer; color: var(--muted);
  display: inline-flex; align-items: center; justify-content: center;
}
.qty-trash:hover { border-color: var(--accent); color: var(--accent-dark); }
.qty-trash svg { width: 16px; height: 16px; }
.stock-hint { text-align: center; color: var(--muted); font-size: .75rem; margin-top: 6px; }
/* A line the customer cannot buy: dimmed, but still readable and removable. */
.stock-hint.unavailable { color: #a13228; font-weight: 600; }
.cart-unavailable { color: #a13228; font-weight: 600; }
.cart-row.unavailable .cart-name, .summary-item.unavailable .summary-name { opacity: .65; }
.summary-item.unavailable { background: #fff7f5; border-radius: 8px; }

/* ===== About ===== */
.about { background: #fff; border-top: 1px solid var(--line); padding: 40px 0; }
.about-grid { display: grid; gap: 28px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.about h2 { font-size: 1.15rem; margin: 0 0 8px; }
.about p { margin: 0; color: var(--muted); }

/* ===== Footer ===== */
.site-footer { padding: 24px 0; text-align: center; color: var(--muted); font-size: .9rem; }

/* ===== Buy button (used for Proceed to Checkout) ===== */
.buy {
  display: inline-block; margin-top: 8px; width: 100%; text-align: center;
  background: var(--accent); color: #fff; text-decoration: none;
  padding: 14px; border-radius: 999px; font-weight: 700; font-size: 1.05rem;
  border: none; cursor: pointer;
}
.buy:hover { background: var(--accent-dark); }

/* ==========================================================================
   LEFT SIDEBAR (built by app.js, shared on both pages)
   ========================================================================== */
#sidebar {
  position: fixed; top: 0; inset-inline-start: 0; height: 100vh;
  width: var(--sidebar-width);
  background: #fff; border-inline-end: 1px solid var(--line);
  display: flex; flex-direction: column;
  z-index: 70; transition: width .25s ease, transform .25s ease;
}
/* Content sits to the right of the fixed sidebar.
   Shop pages wrap everything in #page. Owner pages have no such wrapper — a
   sticky .owner-header plus .owner-main — so both are offset the same way.
   Listing them here (rather than restructuring the owner HTML) is what lets
   the SAME sidebar serve both kinds of page. */
#page,
.owner-body .owner-header,
.owner-body .owner-main { margin-inline-start: var(--sidebar-width); transition: margin-inline-start .25s ease; }
body.no-transition #sidebar, body.no-transition #page { transition: none; }

.sb-top { display: flex; align-items: center; gap: 10px; padding: 12px; border-bottom: 1px solid var(--line); }
.sb-brand-mini { font-weight: 700; color: var(--ink); }
.sb-iconbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border: 1px solid var(--line);
  background: #fff; border-radius: 8px; cursor: pointer; color: var(--ink);
}
.sb-iconbtn:hover { border-color: var(--accent); }
.sb-iconbtn svg { width: 20px; height: 20px; }
.sb-mobile-only { display: none; margin-inline-start: auto; }

/* THE QUIET CONTROLS. Small text buttons, not a toolbar: they act on the
   navigation and must not compete with it. */
.sb-tools {
  display: flex; align-items: center; gap: 4px;
  padding: 8px 10px; border-bottom: 1px solid var(--line);
}
/* Distinct enough to be FOUND (P035-C14) — they looked like stray text — and
   still quieter than any destination: a bordered chip each, and Reset set apart
   at the far end in the accent colour with a dashed edge, because it undoes
   the sidebar's remembered shape and should never be pressed by accident. */
.sb-toolbtn {
  border: 1px solid #d6cbbf; background: var(--bg); color: var(--ink);
  border-radius: 999px; padding: 5px 11px; font-size: .8rem; font-weight: 600; cursor: pointer;
  min-height: 30px;
}
.sb-toolbtn:hover { border-color: var(--accent); background: #fff; }
.sb-toolbtn-quiet { border-color: #d6cbbf; color: var(--ink); background: #fff; }
.sb-toolbtn-quiet:hover { color: var(--ink); border-color: var(--accent); }
#sb-reset { margin-inline-start: auto; color: var(--accent-dark); border-style: dashed; }

.sb-scroll { flex: 1; overflow-y: auto; overscroll-behavior: contain; padding: 8px; position: relative; }

/* ---- groups ----
   Indentation carries the hierarchy, and the left rule makes a nested group
   readable without turning the sidebar into a file tree. */
.sb-group { margin-bottom: 2px; }
.sb-group[data-depth="2"] { margin-inline-start: 10px; padding-inline-start: 8px; border-inline-start: 1px solid var(--line); }

.sb-group-head {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 9px 10px; border: none; background: none; border-radius: 8px;
  cursor: pointer; color: var(--ink); text-align: left; font: inherit;
}
.sb-group-head:hover { background: var(--bg); }
/* THE PARENT IS THE STRONGEST THING IN ITS GROUP  (P035-C14).
   A top-level heading used to be .74rem muted uppercase — smaller and paler
   than the .95rem ink links underneath it, so the tree read upside down. A
   heading is now larger and bolder than anything it contains, in the ink
   colour, with a quiet tint behind it; the difference is carried by size AND
   weight AND background, never by colour alone. */
.sb-group-head[data-depth="1"] {
  font-size: 1rem; font-weight: 700; letter-spacing: 0;
  text-transform: none; color: var(--ink);
  background: #f5f0e9; margin-top: 4px;
}
.sb-group-head[data-depth="1"]:hover { background: #efe7dd; }
.sb-group-head[data-depth="2"] { font-size: .97rem; font-weight: 700; }
/* An open group says so twice: the chevron turns, and the heading keeps a tint. */
.sb-group-head[data-depth="2"][aria-expanded="true"] { background: #faf6f1; }

/* A parent of the current page gets a WHISPER of context, never the full
   active treatment — one thing on screen is where you are. */
.sb-group-head.has-active { color: var(--ink); }
.sb-group-head[data-depth="2"].has-active { background: #fbf7f2; }

.sb-chev { display: inline-flex; transition: transform .15s ease; color: var(--muted); }
.sb-chev svg { width: 14px; height: 14px; display: block; }
.sb-chev.open { transform: rotate(90deg); }

.sb-group-body { display: block; }
/* Children hang from their heading on a visible rule, so nesting is read at a
   glance rather than inferred from indentation alone. */
.sb-group[data-depth="1"] > .sb-group-body {
  margin: 4px 0 10px; margin-inline-start: 14px;
  padding-inline-start: 6px; border-inline-start: 2px solid #e2d8cc;
}

/* ==========================================================================
   THE HIDDEN ATTRIBUTE HAS TO ACTUALLY HIDE
   --------------------------------------------------------------------------
   The sidebar closes a group by setting `hidden` on its body, and shows or
   hides the tools bar the same way. That relies on the BROWSER'S OWN rule,
   [hidden] { display: none }, which lives in the user-agent stylesheet.

   Author declarations beat user-agent declarations in the cascade whatever
   their specificity. So `.sb-group-body { display: block }` above — an
   ordinary author rule — silently cancelled it: every group reported
   aria-expanded="false", carried the hidden attribute, and stayed fully
   visible on screen. Collapse All appeared to do nothing at all, and there
   was no error anywhere to suggest why.

   One rule, scoped to the sidebar, restores the attribute's meaning for every
   element in here — the two that use it today and any added later. Its
   specificity (id + attribute) clears the class rules above without needing
   !important. The same trap was hit before in this file and solved the same
   way for `.co-modal[hidden]`.
   ========================================================================== */
#sidebar [hidden] { display: none; }

/* ---- destinations ---- */
.sb-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 8px 10px; border-radius: 8px; cursor: pointer;
  color: var(--ink); font-size: .95rem; text-decoration: none;
  border-left: 3px solid transparent;
}
.sb-item[data-depth="2"] { padding-left: 14px; }
.sb-item[data-depth="3"] { padding-left: 20px; }
.sb-item:hover { background: var(--bg); }

/* THE ACTIVE PAGE. Three signals, not one: a filled background, a weight
   change and a solid bar down the left edge. Somebody who cannot separate
   this beige from that beige still sees the bar and the bolder text. */
.sb-item.is-active {
  background: #f4e9dd; font-weight: 700;
  border-left-color: var(--accent); color: var(--ink);
}
.sb-item.is-active:hover { background: #f0e2d2; }
.sb-item:focus-visible, .sb-group-head:focus-visible,
.sb-toolbtn:focus-visible, .sb-rail-btn:focus-visible, .sb-fly-item:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
}

/* ONE ICON BOX FOR EVERY NAVIGATION ROW  (P035 Batch 3 — B3-05)
   --------------------------------------------------------------------------
   The slot used to be only as wide as whatever was inside it, so a row whose
   icon had not drawn yet — or has none — put its label 19px further along
   than its neighbours. Reserving the box makes a row the same shape whether
   or not its glyph has arrived, which is the difference between the menu
   filling in and the menu moving.

   The three sizes in this file are three ROLES, not an inconsistency: 20px
   header buttons, 19px navigation icons, 14px group chevrons. Measured across
   Orders, Products, Delivery, Payment Methods and Prices, in both languages,
   they are identical on every page. */
.sb-ico {
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 19px; width: 19px; height: 19px;
}
.sb-ico svg { width: 19px; height: 19px; display: block; }
.sb-label { flex: 1; min-width: 0; }
/* The market's physical location: context, in smaller quieter type, on its
   own line. It is not a link and never behaves like one. */
.sb-sub { display: block; font-size: .74rem; font-weight: 400; color: var(--muted); text-transform: none; letter-spacing: 0; }
.sb-flag { font-size: .68rem; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.sb-count { background: var(--accent); color: #fff; font-size: .75rem; font-weight: 700; border-radius: 999px; padding: 1px 8px; min-width: 22px; text-align: center; }

/* ---- the icon rail (collapsed desktop only) ---- */
.sb-rail { display: none; flex-direction: column; gap: 4px; padding: 8px 0; overflow-y: auto; }
.sb-rail-btn {
  display: flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; margin: 0 auto;
  border: none; background: none; border-radius: 9px; cursor: pointer; color: var(--ink);
}
.sb-rail-btn:hover { background: var(--bg); }
.sb-rail-btn.has-active { background: #f4e9dd; box-shadow: inset 2px 0 0 var(--accent); }

.sb-flyout {
  position: fixed; inset-inline-start: calc(var(--sidebar-collapsed-width) + 6px);
  min-width: 210px; max-width: 280px; max-height: 80vh; overflow-y: auto;
  background: #fff; border: 1px solid var(--line); border-radius: 12px;
  box-shadow: var(--shadow); padding: 8px; z-index: 95;
}
.sb-fly-title { margin: 2px 8px 8px; font-size: .7rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.sb-fly-section { margin-bottom: 6px; }
.sb-fly-heading { margin: 6px 8px 3px; font-size: .82rem; font-weight: 700; color: var(--ink); }
.sb-fly-item {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 9px; border-radius: 7px; color: var(--ink);
  text-decoration: none; font-size: .92rem;
}
.sb-fly-item:hover { background: var(--bg); }
.sb-fly-item.is-active { background: #f4e9dd; font-weight: 700; box-shadow: inset 2px 0 0 var(--accent); }

/* The edge facing the content, so Arabic gets the left one and English the
   right one without a second rule. app.js inverts the arithmetic to match. */
.sb-resize { position: absolute; top: 0; inset-inline-end: 0; width: 6px; height: 100%; cursor: ew-resize; z-index: 5; }
.sb-resize:hover { background: var(--line); }

.sb-back { background: none; border: none; color: var(--accent); cursor: pointer; padding: 4px 4px 8px; font-size: .9rem; }
.sb-view-title { margin: 4px 8px 10px; font-size: 1.05rem; }

.cart-empty, .wl-empty { color: var(--muted); padding: 20px 8px; text-align: center; }
.cart-row { display: flex; align-items: center; gap: 10px; padding: 12px 4px; border-bottom: 1px solid var(--line); }
.cart-info { flex: 1; }
.cart-name { font-weight: 600; font-size: .95rem; }
.cart-line { color: var(--muted); font-size: .82rem; }
.qty { display: flex; align-items: center; gap: 8px; }
.cart-remove { border: none; background: none; color: var(--muted); cursor: pointer; font-size: .95rem; }
.cart-remove:hover { color: var(--accent-dark); }
.sb-foot { padding: 14px 4px; border-top: 1px solid var(--line); margin-top: 8px; }
.cart-subtotal { font-weight: 700; margin-bottom: 12px; }

.wl-row { display: flex; align-items: center; gap: 10px; padding: 12px 4px; border-bottom: 1px solid var(--line); }
.wl-thumb { width: 46px; height: 46px; border-radius: 8px; object-fit: cover; background: #f0eae2; flex-shrink: 0; }
.wl-info { flex: 1; min-width: 0; }
.wl-name { font-weight: 600; font-size: .9rem; }
.wl-line { color: var(--muted); font-size: .82rem; }
.wl-actions { display: flex; flex-direction: column; gap: 6px; }
.wl-add { background: var(--accent); color: #fff; border: none; border-radius: 999px; padding: 5px 10px; font-size: .78rem; cursor: pointer; }
.wl-add:hover:not(:disabled) { background: var(--accent-dark); }
.wl-add:disabled { background: #cfc6bd; cursor: not-allowed; }
.wl-remove { border: none; background: none; color: var(--muted); cursor: pointer; font-size: .78rem; }
.wl-remove:hover { color: var(--accent-dark); }

/* Desktop-only: the collapsed sidebar becomes an ICON RAIL.
   The tree is hidden and the rail takes its place — a genuinely different
   control, because an icon that opens a flyout and a row that navigates are
   different things. Restyling one into the other is what makes most collapsed
   sidebars useless. */
@media (min-width: 769px) {
  body.sidebar-collapsed #sidebar { width: var(--sidebar-collapsed-width); }
  body.sidebar-collapsed #page,
  body.sidebar-collapsed.owner-body .owner-header,
  body.sidebar-collapsed.owner-body .owner-main { margin-inline-start: var(--sidebar-collapsed-width); }
  body.sidebar-collapsed .sb-scroll,
  body.sidebar-collapsed .sb-tools,
  body.sidebar-collapsed .sb-brand-mini,
  body.sidebar-collapsed .sb-resize { display: none; }
  body.sidebar-collapsed .sb-rail { display: flex; flex: 1; }
  body.sidebar-collapsed .sb-top { justify-content: center; padding: 12px 4px; }
}
/* The rail exists only when collapsed; the tree only when expanded. */
.sb-rail { display: none; }

/* Mobile: sidebar becomes a left overlay drawer */
#sb-backdrop { display: none; }
@media (max-width: 768px) {
  #sidebar { transform: translateX(-100%); width: min(300px, 82vw); box-shadow: var(--shadow); z-index: 90; }
  body.sidebar-open #sidebar { transform: translateX(0); }
  /* On a phone the sidebar is an overlay, so nothing is pushed aside. */
  #page,
  .owner-body .owner-header,
  .owner-body .owner-main { margin-inline-start: 0 !important; }
  .sb-resize { display: none; }
  .sb-mobile-only { display: inline-flex; }
  /* A phone drawer is already narrow and already an overlay; an icon rail
     inside one would be a menu you cannot read. The full accordion is shown
     whatever the desktop collapsed preference happens to say. */
  body.sidebar-collapsed #sidebar { width: min(300px, 82vw); }
  body.sidebar-collapsed .sb-scroll,
  body.sidebar-collapsed .sb-tools { display: block; }
  body.sidebar-collapsed .sb-tools { display: flex; }
  body.sidebar-collapsed .sb-brand-mini { display: inline; }
  .sb-rail, body.sidebar-collapsed .sb-rail { display: none !important; }
  .sb-flyout { display: none !important; }
  #sb-backdrop { display: block; position: fixed; inset: 0; background: rgba(0,0,0,.45); opacity: 0; visibility: hidden; transition: opacity .2s; z-index: 80; }
  body.sidebar-open #sb-backdrop { opacity: 1; visibility: visible; }
}

/* ==========================================================================
   PRODUCT DETAIL PAGE (product.html)
   ========================================================================== */
.back-shop { display: inline-block; margin: 18px 0 6px; color: var(--accent); text-decoration: none; font-size: .95rem; }
.back-shop:hover { text-decoration: underline; }

.pd-wrap { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; align-items: start; padding-bottom: 10px; }
@media (max-width: 820px) { .pd-wrap { grid-template-columns: 1fr; gap: 20px; } }

/* THE MAIN PRODUCT IMAGE SHOWS THE WHOLE PRODUCT  (P035 Batch 3, B3-08)
   --------------------------------------------------------------------------
   It was object-fit: cover, which fills the square by cutting off whatever
   does not fit. On a photograph of a landscape that is a crop; on a piece of
   jewellery photographed as a set, or a label with writing near the edge, it
   is the part the customer needed to see. A shop cannot decide which edge of
   somebody's product matters.

   contain fits the whole image inside the frame and letterboxes the rest
   against the neutral background this container already had. Nothing is
   stretched: the aspect ratio is the file's own, and the source media is
   never touched.

   THIS IS THE MAIN IMAGE ONLY. .pd-main appears in product.html and nowhere
   else; the thumbnail strip below it, the catalogue cards and the related
   products keep cover deliberately, because a grid of uniform tiles is what
   makes them scannable and each of those is a pointer to the product rather
   than the look at it. */
.pd-main { aspect-ratio: 1/1; background: #f0eae2; border-radius: var(--radius); overflow: hidden; border: 1px solid var(--line); }
.pd-main img { width: 100%; height: 100%; object-fit: contain; display: block; }
.pd-main .photo-placeholder { height: 100%; }
.pd-thumbs { display: flex; gap: 10px; margin-top: 12px; flex-wrap: wrap; align-items: center; }
.pd-thumb { width: 70px; height: 70px; border-radius: 10px; overflow: hidden; border: 2px solid transparent; cursor: pointer; background: #f0eae2; padding: 0; position: relative; }
.pd-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pd-thumb.active { border-color: var(--accent); }
.pd-addimg { width: 70px; height: 70px; border: 2px dashed var(--line); border-radius: 10px; background: #fff; cursor: pointer; color: var(--muted); font-size: .8rem; }
.pd-addimg:hover:not(:disabled) { border-color: var(--accent); color: var(--accent-dark); }
.pd-addimg:disabled { opacity: .4; cursor: not-allowed; }

.pd-badge-handmade { display: inline-block; background: var(--bg); border: 1px solid var(--line); border-radius: 999px; padding: 4px 12px; font-size: .8rem; margin-bottom: 10px; color: var(--muted); }
.pd-cat { color: var(--muted); font-size: .85rem; }
.pd-titlerow { display: flex; align-items: flex-start; gap: 12px; }
.pd-name { font-size: 1.8rem; margin: 4px 0; flex: 1; }
.pd-seller { color: var(--muted); }
/* THE FRAGRANCE HOUSE, LABELLED AS WHAT IT IS. Same quiet treatment as the
   handmade badge it replaces for these products — it is context, not a claim
   about who made the bottle. The Arabic label sits beside the English one so
   a Jordan customer reads it in either language. */
.pd-badge-reference {
  display: inline-block; background: var(--bg); border: 1px solid var(--line);
  border-radius: 999px; padding: 4px 12px; font-size: .8rem;
  margin-bottom: 10px; color: var(--muted);
}
.pd-reference-house { color: var(--muted); display: flex; flex-wrap: wrap; gap: 6px; align-items: baseline; }
.pd-reference-house-label { font-size: .82rem; text-transform: uppercase; letter-spacing: .04em; }
.pd-reference-house-name { color: var(--ink); font-weight: 600; unicode-bidi: isolate; }
.pd-reference-house-ar { font-size: .82rem; unicode-bidi: isolate; }
.pd-price { font-size: 1.5rem; font-weight: 700; color: var(--accent-dark); margin: 12px 0; }
.pd-stock { font-size: .9rem; margin: 8px 0; color: var(--muted); }
.pd-stock.low { color: var(--accent-dark); font-weight: 600; }
.pd-stock.out { color: var(--accent-dark); font-weight: 700; }
.pd-short { margin: 12px 0; }
.pd-controls { margin-top: 16px; max-width: 280px; }
.pd-ship { color: var(--muted); font-size: .85rem; margin-top: 12px; }
.pd-share { margin-top: 14px; background: none; border: 1px solid var(--line); border-radius: 999px; padding: 8px 16px; cursor: pointer; color: var(--ink); font-size: .9rem; }
.pd-share:hover { border-color: var(--accent); }

.pd-details { margin-top: 40px; border-top: 1px solid var(--line); padding-top: 24px; }
.pd-details h2 { font-size: 1.2rem; margin: 0 0 12px; }
.pd-detail-row { display: flex; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--line); }
.pd-detail-row .k { width: 160px; color: var(--muted); font-size: .9rem; }
.pd-detail-row .v { flex: 1; }
.pd-longdesc { margin: 0 0 18px; }

.related { margin-top: 44px; }
.related h2 { font-size: 1.2rem; margin-bottom: 16px; }

.pd-notfound { text-align: center; padding: 60px 0; color: var(--muted); }

/* ==========================================================================
   CHECKOUT PAGE (checkout.html)
   ========================================================================== */
.co-links { display: flex; gap: 16px; flex-wrap: wrap; margin: 16px 0 4px; }
.co-links a, .co-links button { text-decoration: none; }

/* Step indicator: Cart → Checkout → Payment */
.co-steps { display: flex; gap: 8px; align-items: center; color: var(--muted); font-size: .9rem; margin: 8px 0 18px; flex-wrap: wrap; }
.co-steps .step { padding: 4px 12px; border-radius: 999px; border: 1px solid var(--line); background: #fff; }
.co-steps .step.active { background: var(--accent); color: #fff; border-color: var(--accent); font-weight: 700; }
.co-steps .step.upcoming { opacity: .6; }
.co-steps .sep { color: var(--line); }

/* Two-column layout: form (wide) + order summary (narrow) */
.co-grid { display: grid; grid-template-columns: 1.5fr 1fr; gap: 24px; align-items: start; padding-bottom: 30px; }
@media (max-width: 860px) { .co-grid { grid-template-columns: 1fr; } }

.co-section { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: 18px 18px 6px; margin-bottom: 18px; }
.co-section h2 { font-size: 1.1rem; margin: 0 0 14px; }

/* Form fields */
.co-field { margin-bottom: 14px; }
.co-field > label { display: block; font-size: .9rem; margin-bottom: 6px; font-weight: 600; }
.co-field input, .co-field select, .co-field textarea {
  width: 100%; padding: 11px 12px; border: 1px solid var(--line);
  border-radius: 10px; font-size: 1rem; background: #fff; font-family: inherit; color: var(--ink);
}
.co-field input:focus, .co-field select:focus, .co-field textarea:focus { outline: 2px solid var(--accent); border-color: transparent; }
.co-field textarea { resize: vertical; min-height: 80px; }
.co-readonly { padding: 11px 12px; background: var(--bg); border: 1px solid var(--line); border-radius: 10px; color: var(--muted); }
.co-two { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 520px) { .co-two { grid-template-columns: 1fr; } }
.co-hint { color: var(--muted); font-size: .8rem; margin-top: 4px; }

/* Inline validation */
.co-err { color: #b23b3b; font-size: .82rem; margin-top: 5px; display: none; }
.co-field.invalid .co-err { display: block; }
.co-field.invalid input, .co-field.invalid select, .co-field.invalid textarea { border-color: #b23b3b; }

/* Checkboxes (gift + agreement) */
.co-check { display: flex; gap: 10px; align-items: flex-start; }
.co-check input { width: auto; margin-top: 3px; }
.co-check label { font-weight: 400; margin: 0; }
.char-count { text-align: right; color: var(--muted); font-size: .78rem; margin-top: 4px; }
.link-btn { background: none; border: none; color: var(--accent); cursor: pointer; text-decoration: underline; padding: 0; font: inherit; }

/* Info + banner boxes */
.co-info { background: var(--bg); border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; font-size: .85rem; color: var(--muted); margin-bottom: 14px; }
.co-banner { background: #fbf1e9; border: 1px solid #e9d6c6; border-radius: 10px; padding: 12px 14px; margin-bottom: 16px; color: var(--accent-dark); font-size: .9rem; }
.co-success { background: #eef6ef; border: 1px solid #cfe6d4; border-radius: 12px; padding: 18px; color: #2f5d3f; margin-top: 16px; }

/* Order summary */
.co-summary { position: sticky; top: 80px; }
@media (max-width: 860px) { .co-summary { position: static; } }
.summary-item { display: flex; gap: 10px; padding: 12px 0; border-bottom: 1px solid var(--line); align-items: flex-start; }
.summary-thumb { width: 52px; height: 52px; border-radius: 8px; object-fit: cover; background: #f0eae2; flex-shrink: 0; }
.summary-info { flex: 1; min-width: 0; }
.summary-name { font-weight: 600; font-size: .9rem; }
.summary-meta { color: var(--muted); font-size: .8rem; margin-bottom: 4px; }
.summary-controls .cart-controls { margin-top: 6px; }
.summary-controls .qtybar { justify-content: flex-start; }
.summary-line { font-weight: 700; color: var(--accent-dark); white-space: nowrap; font-size: .9rem; }

.totals { margin-top: 14px; }
.totals-row { display: flex; justify-content: space-between; padding: 6px 0; }
.totals-row .lbl { color: var(--muted); }
.totals-row.total { border-top: 1px solid var(--line); margin-top: 8px; padding-top: 12px; font-weight: 800; font-size: 1.15rem; }
.totals-row.total .lbl { color: var(--ink); }

/* Empty cart state */
.co-empty { text-align: center; padding: 60px 20px; }
.co-empty h2 { margin: 0 0 10px; }
.co-empty p { color: var(--muted); margin: 0 0 18px; }

/* Simple modal for the Shipping & Returns policy */
.co-modal { position: fixed; inset: 0; z-index: 100; display: flex; align-items: center; justify-content: center; padding: 20px; }
.co-modal[hidden] { display: none; }
.co-modal-back { position: absolute; inset: 0; background: rgba(0,0,0,.5); }
.co-modal-card { position: relative; background: #fff; border-radius: var(--radius); max-width: 520px; width: 100%; padding: 24px; box-shadow: var(--shadow); max-height: 85vh; overflow: auto; }
.co-modal-card h3 { margin-top: 0; }
.co-modal-close { position: absolute; top: 12px; right: 12px; width: 34px; height: 34px; border-radius: 999px; border: none; background: var(--bg); cursor: pointer; font-size: 1rem; }

/* ==========================================================================
   PAYMENT / CONFIRMATION / RESULT PAGES
   ========================================================================== */

/* Developer notice (payment.html only) */
.pay-notice { background: #fff7f5; border: 1px solid #f0cfc9; color: #a13228; border-radius: 10px; padding: 10px 14px; font-size: .85rem; margin: 4px 0 18px; }

/* Development-only test controls — deliberately NOT styled like real buttons */
.dev-box { border: 1px dashed #b23b3b; border-radius: 10px; padding: 14px; margin-top: 18px; background: #fff7f5; }
.dev-box h3 { margin: 0 0 4px; font-size: .8rem; color: #b23b3b; letter-spacing: .05em; text-transform: uppercase; }
.dev-box p { margin: 0 0 12px; font-size: .82rem; color: var(--muted); }
.dev-controls { display: flex; gap: 10px; flex-wrap: wrap; }
.dev-btn { border: 1px solid var(--line); background: #fff; border-radius: 8px; padding: 9px 14px; cursor: pointer; font-size: .88rem; color: var(--ink); }
.dev-btn:hover { border-color: #b23b3b; }

/* Status badges.
   The class names come from statusBadgeHTML() in payment.js — every value it
   can produce needs a rule here, otherwise the badge renders with no colour. */
.pay-badge { display: inline-flex; align-items: center; gap: 8px; padding: 6px 14px; border-radius: 999px; font-weight: 700; font-size: .95rem; }
.pay-badge.paid { background: #eef6ef; color: #2f5d3f; border: 1px solid #cfe6d4; }
.pay-badge.cancelled { background: #fbf1e9; color: var(--accent-dark); border: 1px solid #e9d6c6; }
.pay-badge.failed { background: #fdecea; color: #a13228; border: 1px solid #f0cfc9; }
.pay-badge.pending { background: var(--bg); color: var(--muted); border: 1px solid var(--line); }
/* "progress" = preparing / ready to ship / shipped — work is under way. */
.pay-badge.progress { background: #eef3fa; color: #2f4f7d; border: 1px solid #cfdcee; }

/* A small grey note under a heading or a form. Used on almost every page. */
.muted-note { color: var(--muted); font-size: .82rem; margin: 8px 0 14px; }
.muted-note a { color: var(--accent); }

/* Wrapper around the part of the confirmation page that should print. */
.print-area { display: block; }

/* Order item rows (confirmation / payment summary) */
.ord-item { display: flex; justify-content: space-between; gap: 10px; padding: 10px 0; border-bottom: 1px solid var(--line); }
.ord-item .oi-name { font-weight: 600; font-size: .92rem; }
.ord-item .oi-meta { color: var(--muted); font-size: .82rem; }
.ord-item .oi-line { font-weight: 700; color: var(--accent-dark); white-space: nowrap; }

/* Key/value rows */
.kv { display: flex; gap: 10px; padding: 6px 0; }
.kv .k { width: 150px; color: var(--muted); font-size: .9rem; flex-shrink: 0; }

/* Confirmation hero */
.conf-hero { text-align: center; padding: 12px 0 4px; }
.conf-hero h1 { margin: 8px 0 4px; }
.conf-ref { font-size: 1.1rem; font-weight: 800; color: var(--accent-dark); letter-spacing: .5px; margin: 6px 0 0; }

/* Action button rows (stack on mobile) */
.result-actions, .conf-actions { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 20px; }
.btn-outline { display: inline-block; border: 1px solid var(--line); background: #fff; color: var(--ink); border-radius: 999px; padding: 11px 18px; cursor: pointer; text-decoration: none; font-weight: 600; font-size: .95rem; }
.btn-outline:hover { border-color: var(--accent); }
.btn-solid { display: inline-block; border: none; background: var(--accent); color: #fff; border-radius: 999px; padding: 11px 18px; cursor: pointer; text-decoration: none; font-weight: 700; font-size: .95rem; }
.btn-solid:hover { background: var(--accent-dark); }
@media (max-width: 520px) {
  .result-actions, .conf-actions { flex-direction: column; }
  .result-actions a, .conf-actions a, .conf-actions button { text-align: center; }
}

/* ===== PayPal / Sandbox ===== */
#paypal-button-container { margin-top: 12px; min-height: 46px; }
.pay-processing { display: none; margin-top: 12px; color: var(--muted); font-size: .9rem; }
.pay-processing.show { display: block; }
.sandbox-tag {
  display: inline-block; background: #fff7dd; border: 1px solid #e8d9a8; color: #7a5b00;
  border-radius: 999px; padding: 2px 10px; font-size: .72rem; font-weight: 700;
  letter-spacing: .04em; vertical-align: middle;
}

/* ==========================================================================
   ORDER TIMELINE
   --------------------------------------------------------------------------
   Built from the order_status_history rows in the database, by
   renderTimelineHTML() in BOTH payment.js (customer) and owner.js (owner).
   One list of dots down a vertical line, oldest at the top.
   ========================================================================== */
.timeline { list-style: none; margin: 0; padding: 0; }
.tl-item { position: relative; padding: 0 0 18px 24px; }
/* The connecting line. The last item has no line below its dot. */
.tl-item::before {
  content: ""; position: absolute; left: 5px; top: 14px; bottom: 0;
  width: 2px; background: var(--line);
}
.tl-item:last-child { padding-bottom: 2px; }
.tl-item:last-child::before { display: none; }
.tl-dot {
  position: absolute; left: 0; top: 5px; width: 12px; height: 12px;
  border-radius: 999px; background: var(--accent); border: 2px solid #fff;
  box-shadow: 0 0 0 1px var(--line);
}
/* The newest entry is the current state, so it gets the strongest dot. */
.tl-item:last-child .tl-dot { background: var(--accent-dark); }
.tl-body { min-width: 0; }
.tl-label { font-weight: 600; font-size: .92rem; }
.tl-when { color: var(--muted); font-size: .8rem; margin-top: 2px; }
.tl-note { color: var(--muted); font-size: .84rem; margin-top: 4px; word-break: break-word; }
/* Who made the change: system, paypal or owner. Owner pages only. */
.tl-source {
  display: inline-block; margin-left: 6px; padding: 1px 8px; border-radius: 999px;
  background: var(--bg); border: 1px solid var(--line); color: var(--muted);
  font-size: .68rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
}

/* ==========================================================================
   TRACK MY ORDER (track-order.html)
   ========================================================================== */
.track-grid { display: grid; grid-template-columns: 1fr 1.4fr; gap: 24px; align-items: start; padding-bottom: 30px; }
@media (max-width: 860px) { .track-grid { grid-template-columns: 1fr; } }
.track-badges { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }

/* ==========================================================================
   OWNER AREA — shared shell
   --------------------------------------------------------------------------
   The owner pages are an internal tool, not a shop page: no sidebar, no cart,
   a full-width header and a slightly cooler background so it is immediately
   obvious you are not looking at the customer-facing site.

   NOTE ON SECURITY: none of this CSS protects anything. The protection is
   requireOwner() on every /api/owner/* endpoint in the server.
   ========================================================================== */
.owner-body { background: #f4f1ec; }
/* The owner pages never load app.js, so #page/sidebar offsets do not apply. */

/* THE PAGE KEEPS ITS GUTTER  (P035 Batch 3 — B3-05)
   --------------------------------------------------------------------------
   Measured, not guessed: navigating between owner pages in Arabic moved the
   sidebar 15px sideways — 1096 to 1081 — as the document grew tall enough for
   a scrollbar and the viewport narrowed under it. Every fixed thing on the
   page shifted with it, which is precisely the "light flicker during
   navigation" that was reported.

   Reserving the gutter always means the viewport is the same width before and
   after the content arrives, so nothing moves. It is one line at the document
   and it reserves a SCROLLBAR, never a menu row. */
html { scrollbar-gutter: stable; }

.owner-header { background: #fff; border-bottom: 1px solid var(--line); position: sticky; top: 0; z-index: 20; }
.owner-header-inner {
  max-width: 1240px; margin: 0 auto; padding: 12px 20px;
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
}
.owner-brand { display: inline-flex; align-items: center; gap: 10px; font-weight: 700; color: var(--ink); text-decoration: none; }
.owner-brand-sub { color: var(--muted); font-weight: 600; font-size: .85rem; }
.owner-header-right { margin-inline-start: auto; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.owner-user { color: var(--muted); font-size: .85rem; }
.owner-btn-sm { padding: 7px 14px; font-size: .85rem; }
/* The role-aware header links. Rendered by owner.js, so this only has to lay
   them out — which links appear is a permissions question, not a CSS one. */
.owner-nav { display: contents; }
/* A LIVE PayPal tag must be impossible to miss — this phase should stay amber. */
.sandbox-tag.live-tag { background: #fdecea; border-color: #f0cfc9; color: #a13228; }

.owner-main { max-width: 1240px; margin: 0 auto; padding: 20px; }

/* WHAT AN UNAUTHORIZED PAGE LOOKS LIKE.
   It replaces the whole main area rather than sitting on top of a working
   form — the page never loaded the data and never drew the controls, and it
   should look that way. Calm, not alarming: most people who see this simply
   followed a link or a bookmark meant for somebody else. */
.access-denied {
  max-width: 640px; margin: 48px auto; padding: 28px;
  background: var(--card, #fff); border: 1px solid #e9d6c6; border-radius: 14px; text-align: center;
}
.access-denied h1 { font-size: 1.35rem; margin: 0 0 12px; }
.access-denied p { color: var(--muted); margin: 0 0 10px; }
.access-denied-actions { margin-top: 20px; display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }

/* Product Management holds a wide table, so it opts into more of the screen.
   Scoped to that page via <body class="owner-wide"> so no other owner page's
   layout changes. */
.owner-wide .owner-main { max-width: 1720px; }
.owner-wide .owner-header-inner { max-width: 1720px; }

@media (max-width: 640px) {
  .owner-header-inner { gap: 10px; }
  .owner-header-right { width: 100%; margin-left: 0; }
  .owner-user { flex: 1; }
}

/* ==========================================================================
   OWNER SIGN IN (owner-login.html)
   ========================================================================== */
.owner-login-wrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px; }
.owner-login-card {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 28px; width: 100%; max-width: 420px;
}
.owner-login-brand { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.owner-login-title { font-weight: 700; font-size: 1.2rem; }
.owner-login-sub { color: var(--muted); font-size: .88rem; }
.owner-login-intro { color: var(--muted); font-size: .88rem; margin: 0 0 20px; }
.owner-login-foot { color: var(--muted); font-size: .8rem; margin: 14px 0 0; }
.owner-login-foot a { color: var(--accent); }
.owner-login-card code {
  background: var(--bg); border: 1px solid var(--line); border-radius: 6px;
  padding: 1px 6px; font-size: .82em;
}
.owner-login-card .buy { margin-top: 4px; }

/* ==========================================================================
   OWNER DASHBOARD (owner-orders.html)
   ========================================================================== */

/* ---- Summary tiles. Each one is a button that filters the list below. ---- */
.owner-summary {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 12px; margin-bottom: 18px;
}
.owner-tile {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  padding: 14px; cursor: pointer; text-align: left; font: inherit; color: var(--ink);
  display: flex; flex-direction: column; gap: 2px;
}
.owner-tile:hover { border-color: var(--accent); }
.owner-tile-value { font-size: 1.6rem; font-weight: 800; color: var(--accent-dark); line-height: 1.1; }
.owner-tile-label { color: var(--muted); font-size: .82rem; }
/* Orders carrying a reconciliation_note — a payment mismatch or a stock
   shortfall. These need a human, so they are red rather than brand-coloured. */
.owner-tile.attention { border-color: #f0cfc9; background: #fff7f5; }
.owner-tile.attention .owner-tile-value { color: #a13228; }

/* ---- Filter chips + search ---- */
.owner-toolbar { display: flex; gap: 14px; align-items: flex-start; flex-wrap: wrap; margin-bottom: 16px; }
.owner-filters { display: flex; flex-wrap: wrap; gap: 8px; flex: 1; min-width: 260px; }
.owner-filters .chip { padding: 6px 14px; font-size: .86rem; }
.owner-search { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.owner-search input {
  padding: 8px 12px; border: 1px solid var(--line); border-radius: 999px;
  background: #fff; font-size: .9rem; font-family: inherit; color: var(--ink); min-width: 240px;
}
.owner-search input:focus { outline: 2px solid var(--accent); border-color: transparent; }

/* ---- The order list. One CSS grid so the header row and the order rows
   always line up in the same five columns. ---- */
.order-list { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.order-row {
  display: grid; grid-template-columns: 1.5fr 1.3fr .8fr 1.4fr 28px;
  gap: 12px; align-items: center; padding: 14px 16px;
  border-bottom: 1px solid var(--line); text-decoration: none; color: var(--ink);
}
.order-row:last-child { border-bottom: none; }
a.order-row:hover { background: var(--bg); }
.order-head {
  background: var(--bg); font-size: .74rem; font-weight: 700; color: var(--muted);
  letter-spacing: .06em; text-transform: uppercase;
}
/* Same red treatment as the tile, so a problem order stands out in the list. */
.order-row.attention { background: #fff7f5; }
a.order-row.attention:hover { background: #ffeeea; }

.or-ref { min-width: 0; }
.or-ref strong { font-size: .95rem; }
.or-date { color: var(--muted); font-size: .78rem; margin-top: 3px; }
.or-customer { min-width: 0; font-size: .92rem; overflow-wrap: anywhere; }
.or-city { color: var(--muted); font-size: .8rem; margin-top: 3px; }
.or-total { font-weight: 700; color: var(--accent-dark); white-space: nowrap; }
.or-status { display: flex; flex-wrap: wrap; gap: 6px; }
.or-track { flex-basis: 100%; color: var(--muted); font-size: .76rem; overflow-wrap: anywhere; }
.or-go { color: var(--muted); text-align: right; }

/* On a phone the five columns become a stacked card. */
@media (max-width: 780px) {
  .order-row { grid-template-columns: 1fr auto; gap: 8px; }
  .order-head { display: none; }
  .or-customer, .or-status { grid-column: 1 / -1; }
  .or-go { display: none; }
}

/* ---- Status pills (owner.js statusPill). Smaller and quieter than the
   customer-facing .pay-badge, because a list shows dozens at once. ---- */
.pill {
  display: inline-block; padding: 3px 10px; border-radius: 999px;
  font-size: .74rem; font-weight: 700; white-space: nowrap;
  background: var(--bg); border: 1px solid var(--line); color: var(--muted);
}
.pill.paid { background: #eef6ef; border-color: #cfe6d4; color: #2f5d3f; }
.pill.delivered { background: #e8f3ec; border-color: #bfdcc8; color: #24543a; }
.pill.shipped { background: #eef3fa; border-color: #cfdcee; color: #2f4f7d; }
.pill.progress { background: #fdf4e8; border-color: #ecd9bd; color: #8a5b1d; }
.pill.cancelled { background: #f2efec; border-color: #ded6cd; color: #6b625b; }
.pill.failed { background: #fdecea; border-color: #f0cfc9; color: #a13228; }
.pill.gift { background: #f7eef7; border-color: #e3cfe3; color: #74407a; }

/* ==========================================================================
   OWNER ORDER DETAIL (owner-order.html)
   ========================================================================== */
.owner-detail-head {
  display: flex; align-items: flex-start; gap: 14px; flex-wrap: wrap;
  margin: 4px 0 18px;
}
.owner-detail-head h1 { margin: 0; font-size: 1.5rem; letter-spacing: .5px; }
.owner-detail-sub { color: var(--muted); font-size: .85rem; margin-top: 4px; }
.owner-detail-badges { margin-inline-start: auto; display: flex; gap: 8px; flex-wrap: wrap; }
@media (max-width: 640px) { .owner-detail-badges { margin-left: 0; } }

/* Items + timeline on the left, the action panel and customer data on the right. */
.owner-detail-grid { display: grid; grid-template-columns: 1.5fr 1fr; gap: 22px; align-items: start; padding-bottom: 30px; }
@media (max-width: 940px) { .owner-detail-grid { grid-template-columns: 1fr; } }

/* The reconciliation_note banner — a payment mismatch or a stock shortfall.
   Deliberately louder than the ordinary .co-banner. */
.co-banner.attention-banner { background: #fdecea; border-color: #f0cfc9; color: #a13228; }

.address-block { line-height: 1.7; margin: 0; }
/* Customer-written text (gift message, order notes). Quoted so it is obvious
   these are the customer's words, not Marmocha's. preserve-line-breaks. */
.gift-message {
  background: var(--bg); border-left: 3px solid var(--accent);
  border-radius: 0 10px 10px 0; padding: 12px 14px; margin: 0 0 10px;
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.gift-section h2 { color: var(--accent-dark); }

/* PayPal order / capture ids: long, and must be copied exactly. */
.mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .82em; background: var(--bg); border: 1px solid var(--line);
  border-radius: 6px; padding: 1px 6px; overflow-wrap: anywhere;
}

/* On the owner pages the key/value label column can be narrower. */
.owner-body .kv .k { width: 130px; }

/* ==========================================================================
   CART PAGE (cart.html) and WISHLIST PAGE (wishlist.html)
   --------------------------------------------------------------------------
   These used to be panels inside the sidebar. As full pages they reuse the
   shop's existing card, section and totals styling; only the row layout is
   new.
   ========================================================================== */
.cart-line {
  display: grid; grid-template-columns: 72px 1fr auto auto;
  gap: 14px; align-items: center;
  padding: 14px 0; border-bottom: 1px solid var(--line);
}
.cart-line:last-child { border-bottom: none; }
.cart-page-thumb { width: 72px; height: 72px; border-radius: 10px; }
.cart-line-info { min-width: 0; }
.cart-line-name { font-weight: 600; overflow-wrap: anywhere; }
.cart-line-meta { color: var(--muted); font-size: .8rem; margin-top: 2px; }
.cart-line-unit { color: var(--muted); font-size: .85rem; margin-top: 4px; }
.cart-line-qty { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.cart-line-remove { font-size: .78rem; }
.cart-line-total { font-weight: 700; color: var(--accent-dark); white-space: nowrap; min-width: 90px; text-align: right; }
/* An item that can no longer be bought: dimmed, never hidden. */
.cart-line.unavailable { background: #fff7f5; border-radius: 10px; padding-left: 10px; padding-right: 10px; }
.cart-line.unavailable .cart-line-name { opacity: .7; }

@media (max-width: 640px) {
  .cart-line { grid-template-columns: 60px 1fr; row-gap: 10px; }
  .cart-page-thumb { width: 60px; height: 60px; }
  .cart-line-qty { flex-direction: row; grid-column: 1 / -1; justify-content: flex-start; gap: 14px; }
  .cart-line-total { grid-column: 2; text-align: left; min-width: 0; }
}

/* ---- Wishlist cards reuse .card / .grid from the shop ---- */
.wish-card .card-body { gap: 6px; }
.wish-stock { font-size: .8rem; color: var(--muted); }
.wish-stock.low { color: var(--accent-dark); font-weight: 600; }
.wish-actions { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
.wish-actions .btn-outline,
.wish-actions .add-cart { width: 100%; text-align: center; font-size: .88rem; padding: 9px 14px; }
.wish-card.unavailable .card-name { opacity: .7; }
.wish-remove { color: var(--muted); }
.wish-remove:hover { border-color: #f0cfc9; color: #a13228; }

/* ==========================================================================
   CURRENCY SELECTOR (shop header)
   --------------------------------------------------------------------------
   Deliberately quiet. Prices are the thing that matters on a shop page; the
   currency is a setting, so it looks like one and sits beside the cart button
   rather than competing with the brand.
   ========================================================================== */
.currency-select-wrap { display: inline-flex; align-items: center; }
.currency-select {
  appearance: none;
  border: 1px solid var(--line); background: #fff; color: var(--ink);
  border-radius: 999px; padding: 7px 26px 7px 12px;
  font: inherit; font-size: .85rem; font-weight: 600; cursor: pointer;
  /* The little chevron, drawn rather than loaded, so there is no extra file. */
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237a716a' stroke-width='2.2' stroke-linecap='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 8px center; background-size: 12px;
}
.currency-select:hover { border-color: var(--accent); }
.currency-select:focus { outline: 2px solid var(--accent); border-color: transparent; }

/* Visible to screen readers, invisible on screen. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ==========================================================================
   OWNER — CURRENCY MANAGEMENT (owner-currencies.html)
   ========================================================================== */
.cur-intro p { margin: 0 0 10px; }
.cur-intro code {
  background: var(--bg); border: 1px solid var(--line); border-radius: 6px;
  padding: 1px 6px; font-size: .85em;
}

.cur-list { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.cur-row {
  display: grid; grid-template-columns: 1.6fr .6fr 1fr .9fr 1fr auto;
  gap: 12px; align-items: center; padding: 14px 16px; border-bottom: 1px solid var(--line);
}
.cur-row:last-child { border-bottom: none; }
.cur-head {
  background: var(--bg); font-size: .74rem; font-weight: 700; color: var(--muted);
  letter-spacing: .06em; text-transform: uppercase;
}
/* USD. Tinted so "this one is different" reads before the padlock does. */
.cur-row.locked { background: var(--bg); }

.cur-name { font-weight: 600; font-size: .95rem; min-width: 0; }
.cur-sub { color: var(--muted); font-size: .78rem; font-weight: 400; margin-top: 3px; }
.cur-code code { font-size: .82rem; }

.cur-rate {
  width: 100%; max-width: 140px; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: 8px;
  font: inherit; font-size: .9rem; font-variant-numeric: tabular-nums; color: var(--ink);
}
.cur-rate:focus { outline: 2px solid var(--accent); border-color: transparent; }
.cur-rate-locked {
  font-variant-numeric: tabular-nums; font-weight: 700; color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .9rem;
}

.cur-toggle { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-size: .85rem; }
.cur-toggle input { width: auto; cursor: pointer; }
.cur-updated { color: var(--muted); font-size: .8rem; }
.cur-action { text-align: right; }

@media (max-width: 900px) {
  .cur-row { grid-template-columns: 1fr 1fr; }
  .cur-head { display: none; }
  .cur-name { grid-column: 1 / -1; }
  .cur-action { text-align: left; }
}

/* ==========================================================================
   OWNER — PRODUCT MANAGEMENT (owner-products.html / owner-product.html)
   ========================================================================== */
/* ==========================================================================
   THE PRODUCT LIST MEASURES ITSELF, NOT THE WINDOW.
   --------------------------------------------------------------------------
   THE DEFECT THIS FIXES. The row layout switched to cards at a VIEWPORT
   width of 1180px, while the space it actually had was the viewport MINUS a
   270px sidebar. On a 1366px laptop with the sidebar open the content area
   is about 1041px and the table needs 1061px — so between roughly 1200px
   and 1366px the full nine-column table was drawn into a box too small to
   hold it, and overflow:hidden cut the right-hand edge off in silence.
   Measured: the Actions column was unreachable and the document reported no
   overflow at all, so nothing on screen suggested anything was missing.

   A VIEWPORT BREAKPOINT CAN NEVER BE RIGHT HERE. The same window is 270px
   narrower with the sidebar open, 60px narrower collapsed, and any width in
   between once it has been dragged. So the rules below key on the
   CONTAINER's own inline size, and are correct in all of those states
   without knowing about any of them.

   AND IT NEVER CLIPS AGAIN. overflow-x is auto, so in any band where the
   table genuinely needs more room than it has, the scrolling happens INSIDE
   this box: the page and the sidebar stay still, and the last column stays
   reachable. */
.prod-list {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  container-type: inline-size;
  container-name: prodlist;
  overflow-x: auto;
  overflow-y: hidden;
}
/* An edge worth grabbing, on the platforms that paint one. */
.prod-list::-webkit-scrollbar { height: 10px; }
.prod-list::-webkit-scrollbar-thumb { background: #cfc6ba; border-radius: 6px; }
.prod-list::-webkit-scrollbar-track { background: #f4f0ea; border-radius: 6px; }
/* "USD 45.00" is nowrap, so the price column needs a floor or it overflows
   into the stock column and the numbers stop lining up with their headings. */
/* Thumbnail, name and SKU share ONE cell now, which buys the width the store
   columns need and keeps rows to a single compact line. */
/* P2-R1 added a ninth column — global product policy — and the stock column
   grew from one number to a stepper and three figures. Both are given room
   rather than squeezed, because this table is now edited rather than read. */
.prod-row {
  display: grid;
  /* MEASURED FLOORS, not estimated ones. The stock cell holds a stepper and
     three figures and needs about 208px; the policy cell holds three toggles
     and needs about 158px. The old 146px and 150px were where the crowding
     came from. */
  /* TEN TRACKS SINCE P035 BATCH 3 (B3-10): unit cost joined the row, and the
     selling price stopped being a span and became a box. A price you can type
     into needs about 132px where a printed figure needed 84 — adding the
     column without widening that track is what squeezed stock and policy to
     19px, which the responsive suite caught immediately. */
  /* NINE TRACKS. Batch 3 put a box where the printed price was and stacked
     the unit cost beneath it in the same cell, so the money column needs about
     132px where a figure needed 84 — but the row keeps its column count. A
     tenth track starved every cell beside it at 1366px. */
  grid-template-columns:
    minmax(200px, 2.1fr) minmax(140px, 1fr) minmax(136px, .8fr)
    minmax(208px, 1.2fr) minmax(78px, .5fr) minmax(158px, .9fr)
    minmax(78px, .5fr) minmax(84px, .55fr) auto;
  gap: 10px; align-items: center; padding: 10px 14px; border-bottom: 1px solid var(--line);
}
.prod-cell { display: flex; align-items: center; gap: 10px; min-width: 0; }
.prod-cat, .prod-stock { font-size: .88rem; }
.prod-stock-n { font-weight: 700; }
.prod-row:last-child { border-bottom: none; }
.prod-head {
  background: var(--bg); font-size: .72rem; font-weight: 700; color: var(--muted);
  letter-spacing: .06em; text-transform: uppercase;
}
.prod-thumb { width: 48px; height: 48px; border-radius: 8px; object-fit: cover; background: #f0eae2; display: block; }
.empty-thumb {
  display: flex; align-items: center; justify-content: center; text-align: center;
  color: var(--muted); font-size: .6rem; line-height: 1.2; border: 1px dashed var(--line);
}
.prod-name { min-width: 0; overflow-wrap: anywhere; }
.prod-sku { margin-top: 3px; }
/* THE SELLING PRICE, AND THE REFERENCE FIGURE UNDER IT.
   The store's own price is the number an operator reads, so it keeps the
   weight and the colour. The global base figure is deliberately quiet and
   small: it is context for somebody setting a price, not a price. */
.prod-price { font-weight: 700; color: var(--accent-dark); white-space: nowrap; }
.prod-store-price { display: block; font-variant-numeric: tabular-nums; }
.prod-base-price {
  display: block; margin-top: 2px;
  font-weight: 400; font-size: .75rem; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
/* Not priced is a state to act on, so it reads as a link rather than as a
   value. It is the one cell on this page that sends somebody somewhere. */
.prod-unpriced {
  display: inline-block; font-weight: 600; font-size: .82rem;
  color: #a13228; text-decoration: underline; text-underline-offset: 2px;
  white-space: normal;
}
.prod-base-unset { color: var(--muted); font-weight: 400; }
/* Active but nothing left to sell — worth noticing at a glance. */
.prod-stock-zero { color: #a13228; font-weight: 700; }
.prod-updated { color: var(--muted); font-size: .8rem; }
.prod-actions { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }

/* ==========================================================================
   THE LADDER. Three shapes, chosen by how much room the LIST actually has.

   >= 1140px    the full table, exactly as a wide screen has always shown it.
   920-1139px   MEDIUM: the two pieces of secondary information — category
                and the updated date — move under the product name instead
                of each holding a wide column of its own. NOTHING IS
                REMOVED; it is reorganised, and the row drops to about
                920px so a laptop with the sidebar open shows every column
                with no scrolling at all.
   < 920px      CARD: one product per block, each field labelled. Identity,
                price, stock, policy, status and the actions all stay
                reachable.
   ========================================================================== */
/* THE SECONDARY LINE under the product name: category and the updated date,
   shown only in the shapes where they have no column of their own.

   IT IS DECLARED HERE, BEFORE THE LADDER, AND THAT POSITION IS LOAD
   BEARING. Both this rule and the .prod-sub inside the container query
   below are a single class, so the cascade separates them by ORDER alone.
   While this one came last it won unconditionally, the line never
   appeared, and the category and the updated date were not reorganised
   out of the table - they were deleted from the page, silently, with no
   error anywhere. Exactly the shape of the [hidden] defect in CLAUDE.md
   section 13. Do not move it back below. */
.prod-sub { display: none; flex-wrap: wrap; gap: 8px; font-size: .74rem;
            color: var(--muted); margin-top: 3px; }
.prod-sub > span { white-space: nowrap; }

@container prodlist (max-width: 1139px) {
  .prod-row {
    /* SEVEN TRACKS FOR SEVEN VISIBLE CELLS. Hiding category and the updated
       date leaves product, price, stock, sold-here, policy, status and the
       actions — and a six-track template silently pushed the policy toggles
       into the narrow status column, which is where the crowding at 1280-1440
       was coming from. */
    grid-template-columns:
      /* The sold-here cell is wider in Arabic than in English — "مُفعَّل" beside
         the switch does not fit the width an English "On" needs. The floor is
         the ARABIC one, because a column sized for the shorter language is a
         column that overflows in the other. */
      /* 186, not 148 (P035-C14): the bulk selection checkbox sits in this
         cell and takes 38px of it. The name keeps the room it had before. */
      /* The money column is wider since Batch 3 — it holds a box and the cost
         beneath it — but the track count is unchanged. */
      minmax(186px, 1.8fr) minmax(120px, 1fr) minmax(208px, 1.2fr)
      minmax(104px, .6fr) minmax(156px, .9fr) minmax(72px, .5fr) auto;
  }
  /* Not lost — printed under the name instead. See .prod-sub. */
  .prod-cat, .prod-updated { display: none; }
  .prod-sub { display: flex; }
}

@container prodlist (max-width: 959px) {
  .prod-row { grid-template-columns: 1fr auto; row-gap: 10px; }
  .prod-head { display: none; }
  .prod-cell { grid-column: 1 / -1; }
  .prod-price, .prod-stock, .prod-policy, .prod-status,
  .cat-stores, .prod-base { grid-column: 1 / -1; }
  .prod-actions { grid-column: 1 / -1; justify-content: flex-start; }
  .more-menu { right: auto; left: 0; }
  /* A card has no column headings above it, so each field says what it is. */
  .prod-row > [data-label]::before {
    content: attr(data-label);
    display: block; font-size: .68rem; font-weight: 700; letter-spacing: .05em;
    text-transform: uppercase; color: var(--muted); margin-bottom: 2px;
  }
}


/* ==========================================================================
   STORE CONTEXT BADGE  (owner header)
   --------------------------------------------------------------------------
   The store is chosen in the SIDEBAR now. This badge exists because the
   sidebar can be collapsed, and editing the wrong market's stock is an easy
   and expensive mistake — so which market and which physical location a page
   is acting on is always on screen.
   ========================================================================== */
.store-context {
  display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap;
  background: var(--bg); border: 1px solid var(--line);
  border-radius: 999px; padding: 5px 14px; font-size: .8rem;
}
.store-context-label { color: var(--muted); font-size: .68rem; text-transform: uppercase; letter-spacing: .05em; }
.store-context-store { color: var(--accent-dark); font-size: .92rem; }
.store-context-loc { font-weight: 600; }

/* Which location a stock column is showing. */
.store-scope {
  display: block; text-transform: none; letter-spacing: 0;
  font-weight: 400; font-size: .68rem; color: var(--muted);
}

/* ---- The store list in the sidebar ---- */
.sb-store.active-store { background: var(--bg); font-weight: 700; }
.sb-store.active-store .sb-label { color: var(--accent-dark); }
.sb-store-dot { background: transparent; color: var(--accent); font-size: .7rem; min-width: 0; padding: 0 4px; }

/* A product the selected store does not sell — dimmed, still editable. */
.prod-row.not-in-store { background: var(--bg); }
.prod-row.not-in-store .prod-name strong,
.prod-row.not-in-store .prod-price { opacity: .55; }

/* ==========================================================================
   SOLD-IN-STORE SWITCH
   --------------------------------------------------------------------------
   A real switch rather than a bare checkbox: this changes whether a market
   sells a product, and it deserves to look like a decision.
   ========================================================================== */
.switch {
  display: inline-flex; align-items: center; gap: 8px;
  background: none; border: none; padding: 0; cursor: pointer; font: inherit;
}
.switch-track {
  width: 38px; height: 21px; border-radius: 999px; background: #cfc6bd;
  position: relative; transition: background .15s ease; flex-shrink: 0;
}
.switch-knob {
  position: absolute; top: 2px; left: 2px; width: 17px; height: 17px;
  border-radius: 999px; background: #fff; transition: transform .15s ease;
  box-shadow: 0 1px 3px rgba(0,0,0,.25);
}
.switch.on .switch-track { background: var(--ok); }
.switch.on .switch-knob { transform: translateX(17px); }
.switch-text { font-size: .78rem; color: var(--muted); font-weight: 600; }
.switch.on .switch-text { color: var(--ok); }
.switch:disabled { opacity: .5; cursor: default; }

/* ---- Compact row actions: Edit + a "more" menu, never a vertical stack ---- */
.more-wrap { position: relative; display: inline-block; }
.more-btn { padding: 5px 10px; line-height: 1; }
.more-menu {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: 30;
  background: #fff; border: 1px solid var(--line); border-radius: 10px;
  box-shadow: var(--shadow); min-width: 210px; overflow: hidden;
}
.more-menu button {
  display: block; width: 100%; text-align: left; border: none; background: none;
  padding: 9px 14px; font: inherit; font-size: .85rem; cursor: pointer; color: var(--ink);
}
.more-menu button:hover { background: var(--bg); }
.more-menu button[data-remove] { color: #a13228; }
/* WHILE OPEN the menu lives on <body>, positioned by menu.js against the
   viewport, above sticky headers and the sidebar. Items are touch-sized and
   show the keyboard focus the arrow keys move. */
.more-menu.is-floating { z-index: 1000; min-width: 220px; }
.more-menu.is-floating button { min-height: 42px; text-align: start; }
.more-menu button:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; background: var(--bg); }

/* ==========================================================================
   SYSTEM OVERVIEW  (P035-C14, owner-system.html)
   --------------------------------------------------------------------------
   One word for the whole shop, said with a symbol, a word and a colour so it
   never depends on colour alone; then one card per domain. Nothing here is a
   control.
   ========================================================================== */
.sys-overall { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: 16px 18px; margin: 0 0 16px;
  border-inline-start: 6px solid #cfc6bd; }
.sys-overall.is-healthy { border-inline-start-color: var(--ok); }
.sys-overall.is-warning { border-inline-start-color: #c98a17; }
.sys-overall.is-degraded { border-inline-start-color: #c0561b; }
.sys-overall.is-critical { border-inline-start-color: #a13228; background: #fff7f6; }
.sys-overall-head { display: flex; gap: 12px; align-items: center; }
.sys-overall-icon { width: 40px; height: 40px; border-radius: 999px; display: inline-flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 1.1rem; background: #f2efec; flex-shrink: 0; }
.is-healthy .sys-overall-icon { background: #e8f3ec; color: #1f5e39; }
.is-warning .sys-overall-icon { background: #fbf1dc; color: #7a5208; }
.is-degraded .sys-overall-icon { background: #fde9dc; color: #8a3a0e; }
.is-critical .sys-overall-icon { background: #fdecea; color: #8f2a22; }
.sys-overall-label { font-size: .78rem; color: var(--muted); }
.sys-overall-word { font-size: 1.4rem; font-weight: 800; letter-spacing: .02em; }
.sys-overall-body { margin: 10px 0 0; }
.sys-overall h3 { font-size: .95rem; margin: 14px 0 6px; }
.sys-list { margin: 0; padding-inline-start: 20px; display: flex; flex-direction: column; gap: 4px; }
.sys-list.is-muted { color: var(--muted); }
.sys-domains { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 12px; }
.sys-domain { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: 14px 16px; border-top: 4px solid #cfc6bd; }
.sys-domain.is-ok { border-top-color: var(--ok); }
.sys-domain.is-warning { border-top-color: #c98a17; }
.sys-domain.is-fail { border-top-color: #a13228; }
.sys-domain.is-unknown { border-top-color: #8a95a3; }
.sys-domain-head { display: flex; justify-content: space-between; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 8px; }
.sys-domain-head h3 { margin: 0; font-size: 1rem; }
.sys-state { font-size: .8rem; font-weight: 700; padding: 2px 10px; border-radius: 999px; background: #f2efec; white-space: nowrap; }
.is-ok .sys-state { background: #e8f3ec; color: #1f5e39; }
.is-warning .sys-state { background: #fbf1dc; color: #7a5208; }
.is-fail .sys-state { background: #fdecea; color: #8f2a22; }
.is-unknown .sys-state { background: #eef1f5; color: #3d4b5c; }
.sys-domain .kv { font-size: .9rem; }
.sys-domain-note { margin: 8px 0 0; font-size: .85rem; color: var(--muted); }
@media (max-width: 520px) { .sys-domains { grid-template-columns: 1fr; } .sys-overall-word { font-size: 1.2rem; } }

/* ==========================================================================
   STORE OVERVIEW  (P035-C14, owner-stores.html)
   --------------------------------------------------------------------------
   One card per market. The status is said three ways — a symbol, a word and a
   colour — so it never depends on colour alone.
   ========================================================================== */
.so-heading { margin: 22px 0 10px; font-size: 1.15rem; }
.so-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 14px; }
.so-card { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: 16px; display: flex; flex-direction: column; gap: 12px;
  border-top: 4px solid #cfc6bd; }
.so-card.so-ready { border-top-color: var(--ok); }
.so-card.so-attention { border-top-color: #c98a17; }
.so-card.so-not_ready { border-top-color: #a13228; }
.so-head { display: flex; justify-content: space-between; gap: 10px; align-items: flex-start; flex-wrap: wrap; }
.so-ident h3 { margin: 0; font-size: 1.1rem; }
.so-meta { margin: 4px 0 0; font-size: .85rem; color: var(--muted); }
.so-status { font-weight: 700; padding: 4px 12px; border-radius: 999px; white-space: nowrap; background: #f2efec; color: var(--ink); }
.so-ready .so-status { background: #e8f3ec; color: #1f5e39; }
.so-attention .so-status { background: #fbf1dc; color: #7a5208; }
.so-not_ready .so-status { background: #fdecea; color: #8f2a22; }
.so-figures { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; margin: 0; }
.so-figures > div { background: var(--bg); border: 1px solid var(--line); border-radius: 10px; padding: 8px; }
.so-figures dt { font-size: .74rem; color: var(--muted); }
.so-figures dd { margin: 2px 0 0; font-weight: 700; font-size: 1.05rem; }
.so-checks { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.so-check { display: flex; gap: 8px; align-items: flex-start; font-size: .9rem; }
.so-icon { flex-shrink: 0; width: 22px; height: 22px; border-radius: 999px; display: inline-flex; align-items: center; justify-content: center;
  font-size: .75rem; font-weight: 700; background: #f2efec; color: var(--ink); }
.so-check.is-ok .so-icon { background: #e8f3ec; color: #1f5e39; }
.so-check.is-warning .so-icon { background: #fbf1dc; color: #7a5208; }
.so-check.is-fail .so-icon { background: #fdecea; color: #8f2a22; }
.so-check.is-info .so-icon { background: #eef1f5; color: #3d4b5c; }
.so-links { display: flex; flex-wrap: wrap; gap: 6px; }
@media (max-width: 520px) { .so-list { grid-template-columns: 1fr; } .so-figures { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ==========================================================================
   CATEGORY MANAGER  (P035-C14, owner-categories.html)
   --------------------------------------------------------------------------
   A two-level tree, not a form: a top-level category is a strong row, the
   categories inside it hang from it on a visible connector, and each row says
   what a change would reach before anybody makes one. On a phone every row
   becomes a card and nothing needs sideways scrolling.
   ========================================================================== */
.cm-toolbar { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin: 14px 0 6px; }
.cm-search input { min-width: 240px; padding: 9px 12px; border: 1px solid #d6cbbf; border-radius: 10px; font: inherit; }
.cm-add { display: flex; flex-wrap: wrap; gap: 6px; margin-inline-start: auto; }
.cm-add input, .cm-add select { padding: 8px 10px; border: 1px solid #d6cbbf; border-radius: 8px; font: inherit; font-size: .9rem; min-height: 38px; }
.cm-rule { margin: 4px 0 12px; }
.cm-bulk { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 0 0 10px; padding: 10px 12px;
  background: #fbf1e9; border: 1px solid #e9d6c6; border-radius: 12px; }
.cm-tree { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.cm-row { display: grid; grid-template-columns: auto minmax(180px, 2fr) minmax(170px, 1.3fr) auto auto;
  gap: 10px; align-items: center; padding: 10px 14px; border-bottom: 1px solid var(--line); }
.cm-row:last-child { border-bottom: none; }
.cm-top { background: #faf6f1; }
.cm-top .cm-name { font-size: 1.02rem; }
.cm-child { position: relative; padding-inline-start: 44px; }
.cm-child::before { content: ""; position: absolute; inset-inline-start: 26px; top: 0; bottom: 0; border-inline-start: 2px solid #e2d8cc; }
.cm-child.cm-last::before { bottom: 50%; }
.cm-child::after { content: ""; position: absolute; inset-inline-start: 26px; top: 50%; width: 12px; border-top: 2px solid #e2d8cc; }
.cm-context { opacity: .75; }
.cm-row.is-selected { box-shadow: inset 3px 0 0 var(--accent); }
[dir="rtl"] .cm-row.is-selected { box-shadow: inset -3px 0 0 var(--accent); }
.cm-ident { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cm-name { overflow-wrap: anywhere; }
.cm-level { font-size: .78rem; color: var(--muted); }
.cm-reach { display: flex; flex-wrap: wrap; gap: 10px; font-size: .85rem; color: var(--muted); }
.cm-fig b { color: var(--ink); }
.cm-actions { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; }
.cm-step { min-width: 38px; }
.cm-edit { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end;
  padding: 10px; background: var(--bg); border: 1px solid var(--line); border-radius: 10px; }
.cm-edit label { display: flex; flex-direction: column; gap: 4px; font-size: .8rem; color: var(--muted); }
.cm-edit input, .cm-edit select { padding: 8px 10px; border: 1px solid #d6cbbf; border-radius: 8px; font: inherit; min-height: 38px; }
.cm-edit-actions { display: flex; gap: 6px; margin-inline-start: auto; }
@media (max-width: 760px) {
  .cm-row { grid-template-columns: auto 1fr; row-gap: 8px; }
  .cm-reach, .cm-state, .cm-actions { grid-column: 2 / -1; }
  .cm-actions { justify-content: flex-start; }
  .cm-child { padding-inline-start: 34px; }
  .cm-child::before, .cm-child::after { inset-inline-start: 16px; }
  .cm-search input, .cm-add, .cm-add input, .cm-add select, .cm-add button { width: 100%; min-width: 0; margin-inline-start: 0; }
}

/* ==========================================================================
   SELECTING MANY ROWS  (P035-C14, bulk-select.js)
   --------------------------------------------------------------------------
   The action bar FLOATS at the bottom of the screen while anything is
   selected: it stays reachable on a phone at any scroll position, it never
   depends on the height of the sticky header above it, and the page gains the
   bottom padding it needs so the bar never covers the last row.
   ========================================================================== */
.bulk-check {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 36px; min-height: 36px; margin-inline-end: 2px; cursor: pointer; flex-shrink: 0;
}
.bulk-check input { width: 18px; height: 18px; cursor: pointer; accent-color: var(--accent); margin: 0; }
.prod-head-first { display: flex; align-items: center; }
.prod-row.is-selected { background: #fbf1e9; box-shadow: inset 3px 0 0 var(--accent); }
[dir="rtl"] .prod-row.is-selected { box-shadow: inset -3px 0 0 var(--accent); }
body.has-bulk-selection .owner-main { padding-bottom: 150px; }

.bulk-bar {
  position: fixed; bottom: 16px; inset-inline: 16px; z-index: 60;
  margin-inline: auto; max-width: 1040px;
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  padding: 10px 14px; background: #fff; color: var(--ink);
  border: 1px solid #d6cbbf; border-radius: 14px; box-shadow: 0 10px 30px rgba(0,0,0,.18);
}
@media (min-width: 901px) {
  .bulk-bar { inset-inline-start: calc(var(--sidebar-width) + 16px); }
}
.bulk-count { white-space: nowrap; font-size: .95rem; }
.bulk-divider { width: 1px; align-self: stretch; background: var(--line); }
.bulk-field, .bulk-value { display: inline-flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.bulk-field select, .bulk-value select, .bulk-value input {
  padding: 7px 10px; border: 1px solid #d6cbbf; border-radius: 8px;
  font: inherit; font-size: .9rem; min-height: 38px; max-width: 100%; background: #fff; color: var(--ink);
}
@media (max-width: 700px) {
  .bulk-bar { inset-inline: 8px; bottom: 8px; padding: 10px; }
  .bulk-divider { display: none; }
  .bulk-field, .bulk-value, .bulk-field select, .bulk-value select, .bulk-value input { width: 100%; }
  .bulk-bar [data-bulk-apply] { width: 100%; min-height: 42px; }
}

/* THE BAR SAYS WHAT IS SELECTED BEFORE IT OFFERS WHAT TO DO (P035-C15).
   Two groups: the scope (how many, from where, and how to change that) and the
   action. Bulk edit is the one primary button; the single-action tools are
   secondary, and on a phone they fold behind "More actions". */
.bulk-bar-scope, .bulk-bar-act { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; min-width: 0; }
.bulk-bar-scope { flex: 1 1 340px; }
.bulk-bar-act { flex: 0 1 auto; }
.bulk-scope-actions, .bulk-other { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; min-width: 0; }
.bulk-bar .bulk-count { white-space: normal; line-height: 1.35; }
.bulk-count[data-bulk-mode="matching"] { color: #8f2a22; }
.bulk-edit-btn { min-height: 42px; padding-inline: 20px; font-weight: 700; }
.bulk-more-toggle { display: none; }
@media (max-width: 700px) {
  body.has-bulk-selection .owner-main { padding-bottom: 240px; }
  .bulk-bar { max-height: calc(100vh - 16px); overflow-y: auto; }
  .bulk-bar-scope, .bulk-bar-act { flex: 1 1 100%; }
  .bulk-scope-actions { width: 100%; }
  .bulk-scope-actions > button { flex: 1 1 auto; min-height: 42px; }
  .bulk-bar.has-edit .bulk-edit-btn { flex: 1 1 60%; min-height: 46px; }
  .bulk-bar.has-edit .bulk-more-toggle { display: inline-flex; align-items: center; justify-content: center; min-height: 46px; flex: 1 1 30%; }
  .bulk-bar.has-edit:not(.is-open) .bulk-other { display: none; }
  .bulk-bar.has-edit .bulk-other { flex: 1 1 100%; }
}

.bulk-modal { background: rgba(0,0,0,.45); z-index: 1100; }

/* CATEGORY DELETE (P035-C15): a destructive action that looks like one. */
.cm-actions .cm-delete { color: #a13228; border-color: #e6c2bd; }

/* BULK PERMANENT DELETE (P035-C15B). The dialog reuses the bulk edit sheet;
   these rules make the irreversible parts look irreversible. */
.bd-card .be-head { border-bottom-color: #efc9c5; }
.bd-card .be-head h2 { color: #8f2a22; }
.bd-warn { background: #fdf3f3; border: 1px solid #efc9c5; color: #8f2a22; border-radius: 10px; padding: 10px 12px; margin: 0 0 12px; font-size: .92rem; }
.bd-list { list-style: none; margin: 0 0 12px; padding: 0; display: grid; gap: 6px; }
.bd-list li { border: 1px solid var(--line); border-radius: 10px; padding: 8px 12px; display: flex; flex-wrap: wrap; gap: 4px 8px; align-items: baseline; }
.bd-name { font-weight: 600; overflow-wrap: anywhere; }
.bd-reason { flex: 1 1 100%; font-size: .84rem; color: #8f2a22; }
.bd-blocked li { background: #fffaf9; }
@media (max-width: 700px) {
  .bulk-bar [data-bulk-delete] { width: 100%; min-height: 44px; }
}
.cm-actions .cm-delete:hover { background: #fdf3f3; }
.cm-del-modal { background: rgba(0,0,0,.45); z-index: 1100; }
.cm-del-modal .co-modal-card h2 { margin: 0 0 8px; font-size: 1.2rem; }
.cm-del-target { margin: 0 0 12px; }
.cm-del-name { display: inline-block; font-weight: 700; font-size: 1.05rem; padding: 4px 10px; border-radius: 8px; background: var(--bg); border: 1px solid var(--line); overflow-wrap: anywhere; }
.cm-del-blockers { margin: 0 0 12px; padding-inline-start: 20px; color: #8f2a22; font-weight: 600; }
.cm-del-modal .co-modal-actions button { min-height: 44px; }

/* ==========================================================================
   MASTER CATALOG BULK EDIT PANEL  (P035-C15, bulk-edit-panel.js)
   --------------------------------------------------------------------------
   A drawer on a wide screen, a full-screen sheet on a phone. The body scrolls;
   the header and the action buttons never do, so Review and Confirm can never
   end up below a region somebody cannot reach.
   ========================================================================== */
body.be-open { overflow: hidden; }
.be-overlay { position: fixed; inset: 0; z-index: 1150; background: rgba(0,0,0,.45); display: flex; justify-content: flex-end; }
.be-card {
  background: #fff; color: var(--ink); width: min(600px, 100%); height: 100%;
  display: flex; flex-direction: column; box-shadow: 0 0 40px rgba(0,0,0,.25);
}
.be-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; padding: 16px 18px 10px; border-bottom: 1px solid var(--line); }
.be-head h2 { margin: 0; font-size: 1.25rem; }
.be-head h2:focus { outline: none; }
.be-scope, .be-scope-line { margin: 4px 0 0; font-weight: 600; color: #8f2a22; font-size: .92rem; }
.be-scope-line { margin: 0 0 12px; }
.be-x { border: 1px solid var(--line); background: #fff; border-radius: 10px; min-width: 44px; min-height: 44px; font-size: 1.4rem; line-height: 1; cursor: pointer; color: var(--ink); }
.be-steps { list-style: none; display: flex; gap: 6px; margin: 0; padding: 10px 18px; border-bottom: 1px solid var(--line); counter-reset: bestep; flex-wrap: wrap; }
.be-steps li { counter-increment: bestep; font-size: .8rem; color: var(--muted); padding: 4px 10px; border-radius: 999px; background: var(--bg); }
.be-steps li::before { content: counter(bestep) " · "; }
.be-steps li.is-current { background: var(--accent); color: #fff; font-weight: 700; }
.be-steps li.is-done { color: var(--ink); }
.be-body { flex: 1 1 auto; overflow-y: auto; padding: 14px 18px 18px; -webkit-overflow-scrolling: touch; }
.be-foot {
  display: flex; gap: 10px; justify-content: flex-end; flex-wrap: wrap;
  padding: 12px 18px calc(12px + env(safe-area-inset-bottom, 0px)); border-top: 1px solid var(--line); background: #fff;
}
.be-foot > button { min-height: 46px; padding-inline: 20px; }
.be-lead { margin: 0 0 14px; color: var(--muted); font-size: .92rem; }
.be-section { border: 1px solid var(--line); border-radius: 14px; padding: 12px 14px 4px; margin: 0 0 14px; }
.be-section > h3 { margin: 0 0 10px; font-size: .78rem; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.be-field { border: 0; padding: 0; margin: 0 0 14px; min-width: 0; }
.be-field > legend { font-weight: 700; font-size: .98rem; padding: 0; margin: 0 0 2px; }
.be-now { margin: 0 0 8px; font-size: .86rem; color: var(--muted); }
.be-now.is-mixed { color: #7a4a00; }
.be-mixed-tag { display: inline-block; font-weight: 700; font-size: .74rem; padding: 1px 8px; border-radius: 999px; background: #fff3d6; border: 1px solid #efd9a3; color: #7a4a00; }
.be-seg { display: flex; flex-wrap: wrap; gap: 6px; }
.be-opt { position: relative; flex: 1 1 auto; min-width: 0; }
.be-opt input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.be-opt span {
  display: flex; align-items: center; justify-content: center; text-align: center;
  min-height: 46px; padding: 8px 14px; border: 1px solid #d6cbbf; border-radius: 10px;
  background: #fff; cursor: pointer; font-weight: 600; font-size: .92rem; overflow-wrap: anywhere;
}
.be-opt.is-keep span { color: var(--muted); font-weight: 500; }
.be-opt input:checked + span { background: var(--accent); border-color: var(--accent); color: #fff; }
.be-opt.is-keep input:checked + span { background: var(--bg); border-color: #b9ab9c; color: var(--ink); font-weight: 700; }
.be-opt input:focus-visible + span { outline: 3px solid var(--accent); outline-offset: 2px; }
.be-select select { width: 100%; min-height: 46px; padding: 8px 10px; border: 1px solid #d6cbbf; border-radius: 10px; font: inherit; background: #fff; color: var(--ink); }
.be-price { display: flex; align-items: stretch; margin-top: 8px; border: 1px solid #d6cbbf; border-radius: 10px; overflow: hidden; }
.be-price-cur { display: flex; align-items: center; padding: 0 12px; background: var(--bg); font-weight: 700; }
.be-price input { flex: 1; min-width: 0; min-height: 46px; border: 0; padding: 8px 12px; font: inherit; font-size: 1.05rem; }
.be-hint { margin: 6px 0 0; font-size: .82rem; color: var(--muted); }
.be-info { margin: 0 0 12px; }
.be-subhead { font-size: .95rem; margin: 14px 0 6px; }
.be-plan { list-style: none; margin: 0 0 12px; padding: 0; display: grid; gap: 6px; }
.be-plan li { border: 1px solid var(--line); border-radius: 10px; padding: 8px 12px; display: flex; flex-wrap: wrap; gap: 4px 8px; align-items: baseline; }
.be-plan-figs { flex: 1 1 100%; font-size: .82rem; color: var(--muted); }
.be-figures { grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); }
.be-warn { background: #fff8e6; border: 1px solid #efd9a3; color: #6b4600; border-radius: 10px; padding: 10px 12px; font-size: .9rem; }
.be-op { font-size: .88rem; color: var(--muted); }
@media (max-width: 640px) {
  .be-card { width: 100%; }
  .be-head { padding: 12px 14px 8px; }
  .be-steps { padding: 8px 14px; }
  .be-body { padding: 12px 14px 16px; }
  .be-foot { padding-inline: 14px; }
  .be-foot > button { flex: 1 1 40%; }
  .be-opt { flex: 1 1 calc(33% - 6px); }
}
.bulk-modal .co-modal-card h2 { margin: 0 0 10px; font-size: 1.2rem; }
.bulk-scope {
  margin: 0 0 12px; padding: 8px 12px; border-radius: 10px; font-weight: 600;
  background: #fbf1e9; border: 1px solid #e9d6c6; color: var(--accent-dark);
}
.bulk-scope.is-global { background: #fdf3f3; border-color: #efc9c5; color: #8f2a22; }
.bulk-figures { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; margin: 0 0 12px; }
.bulk-figures > div { background: var(--bg); border: 1px solid var(--line); border-radius: 10px; padding: 8px 10px; }
.bulk-figures dt { font-size: .76rem; color: var(--muted); }
.bulk-figures dd { margin: 2px 0 0; font-size: 1.3rem; font-weight: 700; }
.bulk-figures .is-bad dd { color: #a13228; }
@media (max-width: 520px) { .bulk-figures { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.bulk-reasons { margin: 0 0 12px; padding-inline-start: 18px; font-size: .88rem; color: var(--muted); max-height: 160px; overflow: auto; }
.co-modal-actions { display: flex; justify-content: flex-end; gap: 8px; flex-wrap: wrap; margin-top: 14px; }

/* ==========================================================================
   PAGINATION
   ========================================================================== */
.pager {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; flex-wrap: wrap; margin: 14px 0 4px;
}
.pager-left { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.pager-left label { color: var(--muted); font-size: .82rem; }
.pager-left select {
  padding: 6px 10px; border: 1px solid var(--line); border-radius: 8px;
  font: inherit; font-size: .85rem; background: #fff; color: var(--ink);
}
.pager-count { margin: 0; }
.pager-right { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.page-num {
  border: 1px solid var(--line); background: #fff; color: var(--ink);
  border-radius: 8px; padding: 6px 11px; font: inherit; font-size: .85rem; cursor: pointer;
}
.page-num:hover:not(:disabled) { border-color: var(--accent); }
.page-num.active { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 700; }
.page-num:disabled { opacity: .45; cursor: default; }

/* ==========================================================================
   GLOBAL vs STORE SCOPE HEADINGS  (owner-product.html)
   --------------------------------------------------------------------------
   Colour-coded on purpose: a future Store Manager will be allowed to change
   the store block and not the global one, so the boundary is made obvious now
   rather than after somebody edits the wrong thing.
   ========================================================================== */
.scope-heading {
  display: flex; flex-direction: column; gap: 2px;
  margin: 0 0 10px; padding: 8px 12px; border-radius: 10px;
  font-size: .78rem; letter-spacing: .04em; text-transform: uppercase; font-weight: 700;
}
.scope-heading strong { text-transform: none; letter-spacing: 0; }
.scope-heading .scope-note {
  text-transform: none; letter-spacing: 0; font-weight: 400; font-size: .78rem; opacity: .85;
}
.scope-heading.global { background: var(--bg); border: 1px solid var(--line); color: var(--muted); }
/* Read-only for this role: the fields are visible but not editable. */
.scope-heading.global.locked { border-style: dashed; }
.co-field input:disabled, .co-field select:disabled, .co-field textarea:disabled {
  background: var(--bg); color: var(--muted); cursor: not-allowed;
}
.scope-heading.store {
  background: #fbf1e9; border: 1px solid #e9d6c6; color: var(--accent-dark); margin-top: 18px;
}
.co-section.store-section { border-color: #e9d6c6; }

/* ==========================================================================
   USER MANAGEMENT, AUDIT LOG AND MASTER CATALOG  (Multi-Owner V1)
   ========================================================================== */
.owner-role-tag {
  display: inline-block; margin-left: 6px; padding: 1px 8px;
  background: var(--accent); color: #fff; border-radius: 999px;
  font-size: .64rem; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
}

.user-list, .audit-list {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
}
.user-row {
  display: grid; grid-template-columns: 1.4fr 1fr .9fr 1.3fr .8fr 1fr auto;
  gap: 12px; align-items: center; padding: 12px 16px; border-bottom: 1px solid var(--line);
}
.user-row:last-child { border-bottom: none; }
.user-head, .audit-head {
  background: var(--bg); font-size: .72rem; font-weight: 700; color: var(--muted);
  letter-spacing: .06em; text-transform: uppercase;
}
/* A disabled account stays listed — the audit trail refers to it. */
.user-row.disabled-user { background: var(--bg); }
.user-row.disabled-user .user-name strong { opacity: .6; }
.user-stores, .user-last { font-size: .84rem; color: var(--muted); }
.user-actions { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.store-checks { display: flex; flex-direction: column; gap: 6px; }

/* USER MANAGEMENT TOOLS (P035-C14): search and filters drawn once, so typing
   never loses the caret; a summary that says who is in what state. */
.user-tools { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 14px 0 8px; }
.user-tools input[type="search"] { flex: 1 1 240px; min-width: 0; padding: 9px 12px; border: 1px solid #d6cbbf; border-radius: 10px; font: inherit; }
.user-tools select { padding: 8px 10px; border: 1px solid #d6cbbf; border-radius: 8px; font: inherit; font-size: .9rem; min-height: 40px; max-width: 100%; background: #fff; }
.user-summary { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 10px; }
.user-stat { background: #fff; border: 1px solid var(--line); border-radius: 999px; padding: 4px 12px; font-size: .86rem; }
.user-stat b { color: var(--ink); }
.user-stat.is-warn { background: #fbf1dc; border-color: #ecd6a6; color: #6b4a08; }
.user-you { display: inline-block; margin-inline-start: 6px; padding: 1px 8px; border-radius: 999px; background: #eef1f5; color: #3d4b5c; font-size: .74rem; font-weight: 700; vertical-align: middle; }
.user-actions .more-menu button[disabled] { color: var(--muted); cursor: not-allowed; }
.pw-actions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; margin-top: 12px; }
@media (max-width: 520px) { .user-tools select, .user-tools input[type="search"] { flex: 1 1 100%; } }

.audit-row {
  display: grid; grid-template-columns: 1.1fr .9fr .8fr 1.1fr 2.4fr;
  gap: 12px; align-items: start; padding: 11px 16px; border-bottom: 1px solid var(--line);
  font-size: .86rem;
}
.audit-row:last-child { border-bottom: none; }
.audit-when, .audit-entity { color: var(--muted); font-size: .78rem; }
.audit-summary { overflow-wrap: anywhere; }
.audit-detail { margin-top: 4px; font-size: .78rem; color: var(--muted); }
.audit-before { text-decoration: line-through; opacity: .75; }
.audit-after { color: var(--accent-dark); font-weight: 600; }

/* AUDIT LOG READING  (P035-C14) */
.audit-toolbar #f-q { flex: 1 1 240px; min-width: 0; }
.audit-toolbar .owner-search { flex-wrap: wrap; }
.audit-opbar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 0 0 10px; padding: 10px 12px;
  background: #eef1f5; border: 1px solid #d5dbe3; border-radius: 12px; }
.audit-opbar code { overflow-wrap: anywhere; }
.audit-tail { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 6px; }
.audit-op-chip { border: 1px solid #d5dbe3; background: #eef1f5; color: #3d4b5c; border-radius: 999px; padding: 2px 10px; font: inherit; font-size: .76rem; cursor: pointer; }
.audit-op-chip:hover, .audit-op-chip:focus-visible { background: #dfe5ec; }
.audit-class { font-size: .74rem; color: var(--muted); }
.audit-export-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; justify-content: space-between; margin: 0 0 10px; }
.audit-drawer .co-modal-card { max-width: 660px; }
.audit-facts { display: grid; grid-template-columns: max-content 1fr; gap: 6px 14px; margin: 0 0 14px; }
.audit-facts dt { color: var(--muted); font-size: .84rem; }
.audit-facts dd { margin: 0; overflow-wrap: anywhere; }
.audit-note { background: var(--bg); border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px; overflow-wrap: anywhere; }
.audit-changes-wrap { overflow-x: auto; margin: 8px 0 0; }
.audit-changes { width: 100%; border-collapse: collapse; font-size: .88rem; }
.audit-changes th, .audit-changes td { text-align: start; padding: 6px 8px; border-bottom: 1px solid var(--line); vertical-align: top; overflow-wrap: anywhere; }
.audit-changes th { font-size: .74rem; color: var(--muted); font-weight: 700; }
.audit-changes td.is-before { color: var(--muted); }
.audit-changes td.is-after { color: var(--accent-dark); font-weight: 600; }
@media (max-width: 520px) { .audit-facts { grid-template-columns: 1fr; } .audit-facts dt { margin-top: 4px; } }

/* Master Catalog rows: no store stock column, a "sold in" column instead. */
.prod-row.cat-row, .prod-row.cat-row-head {
  grid-template-columns:
    minmax(220px, 2.4fr) minmax(90px, .9fr) minmax(96px, .7fr)
    minmax(150px, 1.2fr) minmax(96px, .7fr) minmax(84px, .6fr) auto;
}

/* THE CATALOGUE'S RUNGS ON THE SAME LADDER. Seven cells rather than nine,
   so it needs its own column counts — but the same container, the same
   breakpoints and the same card shape. Scoped with two classes so it
   outranks the rule above, and so it can never reach the category editor
   rows that share the .cat-row name. */
@container prodlist (max-width: 1139px) {
  .prod-row.cat-row, .prod-row.cat-row-head {
    grid-template-columns:
      minmax(180px, 2.4fr) minmax(110px, .9fr) minmax(140px, 1.2fr)
      minmax(84px, .6fr) auto;
  }
}
@container prodlist (max-width: 959px) {
  .prod-row.cat-row, .prod-row.cat-row-head { grid-template-columns: 1fr auto; }
}
.cat-stores { display: flex; gap: 4px; flex-wrap: wrap; }
.more-menu button.danger { color: #a13228; border-top: 1px solid var(--line); }

@media (max-width: 1100px) {
  .user-row { grid-template-columns: 1fr 1fr; }
  .user-head, .audit-head { display: none; }
  .user-name, .user-actions { grid-column: 1 / -1; }
  .user-actions { justify-content: flex-start; }
  .audit-row { grid-template-columns: 1fr; row-gap: 4px; }
  .audit-summary { grid-column: 1 / -1; }
}

/* ---- Collapsible categories block ---- */
.cat-toggle {
  display: flex; align-items: center; gap: 10px; width: 100%;
  background: none; border: none; padding: 0 0 4px; cursor: pointer;
  font: inherit; font-size: 1.1rem; font-weight: 700; color: var(--ink);
}
.cat-toggle-caret { color: var(--muted); font-size: .85rem; }
.cat-toggle-hint { margin: 0; font-weight: 400; }

.store-row .store-loc { font-size: .88rem; }
.cur-row.store-row { grid-template-columns: 1.8fr .8fr 1fr .9fr 1fr auto; }
.store-name {
  width: 100%; padding: 8px 10px; border: 1px solid var(--line);
  border-radius: 8px; font: inherit; font-size: .95rem; font-weight: 600; color: var(--ink);
}
@media (max-width: 900px) { .cur-row.store-row { grid-template-columns: 1fr 1fr; } }

/* ---- Categories block ---- */
.cat-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }
.cat-row {
  display: grid; grid-template-columns: 2fr 90px 130px 1fr auto;
  gap: 10px; align-items: center;
}
.cat-row input[type="text"], .cat-row input[type="number"] {
  padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px;
  font: inherit; font-size: .9rem; width: 100%; color: var(--ink);
}
.cat-count { color: var(--muted); font-size: .82rem; }
.cat-add { display: flex; gap: 8px; flex-wrap: wrap; }
.cat-add input {
  flex: 1; min-width: 200px; padding: 8px 12px;
  border: 1px solid var(--line); border-radius: 999px; font: inherit; font-size: .9rem;
}
@media (max-width: 760px) { .cat-row { grid-template-columns: 1fr 1fr; } }

/* ---- Image manager ---- */
/* THE SAVE STAYS IN REACH (P035-C15). On a phone the form is one long
   column, and the button that commits it was at the bottom of a section the
   reader had scrolled past. It sticks to the bottom of the viewport while its
   section is on screen, and is full width so it is a real touch target. */
@media (max-width: 940px) {
  .co-section .pe-save { position: sticky; bottom: 8px; width: 100%; min-height: 46px; z-index: 5; }
}
/* A photo control is a touch target, not a decoration. */
.img-btn { min-width: 32px; min-height: 32px; }

/* The sign-in card on a small phone: room for fingers, not for margins. */
@media (max-width: 430px) {
  .owner-login-wrap { padding: 16px 12px; }
  .owner-login-card { padding: 20px 16px; }
  .owner-login-card .buy { min-height: 46px; }
}

.img-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 10px; margin-bottom: 14px; }
.img-cell {
  position: relative; aspect-ratio: 1/1; border-radius: 10px; overflow: hidden;
  border: 2px solid var(--line); background: #f0eae2;
}
/* The primary image is the one shoppers see on the product card. */
.img-cell.primary { border-color: var(--accent); }
.img-cell img { width: 100%; height: 100%; object-fit: cover; display: block; }
.img-badge {
  position: absolute; top: 4px; left: 4px; background: var(--accent); color: #fff;
  font-size: .62rem; font-weight: 700; padding: 2px 7px; border-radius: 999px;
}
.img-tools {
  position: absolute; left: 0; right: 0; bottom: 0; display: flex; gap: 2px;
  padding: 4px; background: linear-gradient(transparent, rgba(0,0,0,.6));
}
.img-btn {
  flex: 1; border: none; background: rgba(255,255,255,.9); color: var(--ink);
  border-radius: 5px; font-size: .66rem; padding: 3px 0; cursor: pointer; font-weight: 600;
}
.img-btn:hover { background: #fff; }
.img-btn.danger { background: rgba(253,236,234,.95); color: #a13228; }
#img-file { font-size: .85rem; }

/* The read-only currency audit block on an owner order detail. */
.cur-audit { margin-top: 18px; padding-top: 14px; border-top: 1px dashed var(--line); }
.cur-audit h3 { margin: 0 0 8px; font-size: .78rem; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.cur-audit .muted-note { margin-bottom: 0; }

/* ===== Print: show only the order, hide navigation and controls ===== */
@media print {
  #sidebar, #sb-backdrop, .site-header, .site-footer,
  .dev-box, .no-print, .result-actions, .conf-actions,
  .currency-select-wrap { display: none !important; }
  #page { margin-left: 0 !important; }
  body { background: #fff; }
  .co-section { border: none; box-shadow: none; padding: 6px 0; }

  /* Owner pages print as a packing slip: no header, no status controls. */
  .owner-header, .owner-toolbar, .owner-summary, #status-form, #status-msg { display: none !important; }
  .owner-body { background: #fff; }
  .owner-main { padding: 0; max-width: none; }
  .owner-detail-grid { display: block; }
  /* A packing slip wants every section OPEN: the hidden attribute is a screen
     affordance, and paper has no way to expand anything. */
  .od-acc .acc-body[hidden] { display: block !important; }
  .od-acc .acc-mark, .od-acc-controls { display: none !important; }
}

/* ==========================================================================
   FULFILMENT  (Fulfillment Management V1)
   --------------------------------------------------------------------------
   Four screens share these: the store's configuration, the product's policy,
   the checkout chooser, and the owner's operations panel. Grouped here rather
   than scattered so the vocabulary stays consistent between them.
   ========================================================================== */

/* ---- Product: sales & fulfilment policy --------------------------------- */
/* THREE SEPARATE PROMISES TO A CUSTOMER, so three separate boxes rather
   than three lines of small print. Each is a card with a real edge, a
   checkbox big enough for a thumb and its own sentence underneath — the
   person setting these has to be able to tell cancelling, returning and
   refunding apart at a glance, on a phone. */
.policy-flags { display: grid; gap: 10px; margin: 4px 0 16px; }
.policy-toggle {
  display: flex; gap: 12px; align-items: flex-start; cursor: pointer;
  border: 1px solid var(--line); border-radius: 10px;
  padding: 12px; min-height: 56px; background: #fff;
}
.policy-toggle:hover { border-color: var(--accent); }
.policy-toggle:focus-within { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(0,0,0,.05); }
.policy-toggle input { flex: none; width: 22px; height: 22px; margin-top: 1px; accent-color: var(--ok); }
.policy-toggle input:checked ~ .policy-toggle-text strong { color: var(--ok); }
.policy-toggle-text { display: flex; flex-direction: column; gap: 3px; }
.policy-hint { color: var(--muted); font-size: .82rem; line-height: 1.45; }
.policy-toggle input:disabled + .policy-toggle-text { opacity: .65; }

/* THE DRAFT LINE. Quiet on purpose: it reports that the TYPING is kept, and
   must never be mistaken for the product having been created. */
.pe-draft {
  margin: 8px 0 0; font-size: .8rem; color: var(--muted);
  display: flex; align-items: center; gap: 6px;
}
.pe-draft::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--ok); flex: none; }
.pe-draft-discard {
  margin-top: 6px; background: none; border: none; padding: 8px 0;
  min-height: 44px; color: var(--accent-dark); text-decoration: underline;
  font: inherit; font-size: .82rem; cursor: pointer;
}
.pe-draft-discard:hover { color: var(--ink); }

/* ---- Store configuration ------------------------------------------------ */
.fulfil-store + .fulfil-store { margin-top: 18px; }
.fulfil-list { display: grid; gap: 8px; margin-bottom: 18px; }
.fulfil-row {
  display: grid; grid-template-columns: 1fr auto 140px auto; gap: 12px; align-items: center;
  padding: 10px 12px; border: 1px solid #eadfd4; border-radius: 10px; background: #fffdfb;
}
.fulfil-fee { display: flex; align-items: center; gap: 6px; }
.fulfil-cur { color: var(--muted); font-size: .8rem; }
.fulfil-fee-input { width: 90px; text-align: right; }
.fulfil-sub { font-size: 1rem; margin: 18px 0 8px; }
.fulfil-areas { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.fulfil-area {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 6px 10px; border: 1px solid #eadfd4; border-radius: 999px; background: #fffdfb;
}
.fulfil-area.off { opacity: .55; }
.fulfil-add { display: flex; gap: 8px; flex-wrap: wrap; }
.fulfil-add input { flex: 1 1 160px; min-width: 0; }

/* ---- Checkout: choosing how it arrives ---------------------------------- */
.fulfil-choices { display: grid; gap: 10px; }
.fulfil-choice {
  display: flex; gap: 12px; align-items: flex-start; cursor: pointer;
  padding: 12px 14px; border: 1px solid #eadfd4; border-radius: 12px; background: #fffdfb;
}
.fulfil-choice.chosen { border-color: var(--accent, #b07d4f); background: #fdf6ef; }
.fulfil-choice.unavailable { opacity: .55; cursor: not-allowed; }
.fulfil-choice.static { cursor: default; }
.fulfil-choice input { margin-top: 3px; flex: none; }
.fulfil-choice-body { display: flex; flex-direction: column; gap: 2px; }
.fulfil-choice-sub { color: var(--muted); font-size: .85rem; }

/* ---- Owner: the operations panel ---------------------------------------- */
.fulfil-component {
  border: 1px solid #eadfd4; border-radius: 12px; padding: 14px; background: #fffdfb;
}
.fulfil-component + .fulfil-component { margin-top: 14px; }
.fulfil-head { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-bottom: 10px; }
.fulfil-steps { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-bottom: 12px; }
.fulfil-step { font-size: .8rem; color: var(--muted); padding: 3px 8px; border-radius: 999px; background: #f4ece4; }
.fulfil-step.done { color: var(--ink); background: #e8f1e6; }
.fulfil-step.now { background: var(--accent, #b07d4f); color: #fff; font-weight: 600; }
.fulfil-arrow { color: var(--muted); font-size: .75rem; }
.fulfil-detail { display: flex; gap: 8px; font-size: .88rem; margin-bottom: 4px; }
.fulfil-detail span { color: var(--muted); min-width: 90px; }
.fulfil-changed { font-size: .85rem; margin: 8px 0; padding: 8px 10px; background: #fdf6ef; border-radius: 8px; }
.fulfil-items { margin: 10px 0; padding-left: 18px; font-size: .9rem; }
.fulfil-items li { margin-bottom: 4px; }
.fulfil-action { display: grid; gap: 8px; margin-top: 12px; }
.fulfil-inputs { display: flex; gap: 8px; flex-wrap: wrap; }
.fulfil-inputs input, .fulfil-inputs select { flex: 1 1 150px; min-width: 0; }
.fulfil-exception { margin-top: 12px; font-size: .9rem; }
.fulfil-exception summary { cursor: pointer; color: var(--muted); }

/* ---- Customer: where is my order ---------------------------------------- */
.track-fulfilment { border: 1px solid #eadfd4; border-radius: 12px; padding: 14px; background: #fffdfb; }
.track-fulfilment + .track-fulfilment { margin-top: 12px; }
.track-fulfilment-head { display: flex; gap: 10px; align-items: center; margin-bottom: 12px; }
.track-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.track-step { display: flex; gap: 10px; align-items: center; color: var(--muted); }
.track-step.done { color: var(--ink); }
.track-dot { width: 10px; height: 10px; border-radius: 50%; background: #e0d3c6; flex: none; }
.track-step.done .track-dot { background: var(--accent, #b07d4f); }
.track-step.now { font-weight: 600; }
.track-step.now .track-dot { box-shadow: 0 0 0 4px #f4e6d8; }
.track-extra { font-size: .88rem; color: var(--muted); margin: 10px 0 0; }

@media (max-width: 720px) {
  .fulfil-row { grid-template-columns: 1fr; gap: 8px; }
  .fulfil-fee-input { width: 100%; }
  .fulfil-detail { flex-direction: column; gap: 2px; }
  .fulfil-detail span { min-width: 0; }
}

/* Area price overrides — the same visual family as the delivery-area list, but
   a row here is about PRICE, not about whether we will go there. */
.fulfil-area-fees { display: grid; gap: 8px; margin-bottom: 12px; }
.fulfil-area-fee {
  display: grid; grid-template-columns: 1fr auto 90px auto auto; gap: 10px; align-items: center;
  padding: 8px 12px; border: 1px solid #eadfd4; border-radius: 10px; background: #fffdfb;
}
.fulfil-area-fee.off { opacity: .55; }
.fulfil-area-fee-what { font-size: .9rem; }
.area-fee-input { width: 100%; text-align: right; }
@media (max-width: 720px) {
  .fulfil-area-fee { grid-template-columns: 1fr; }
  .area-fee-input { width: 100%; }
}

/* The collection point at checkout. Deliberately prominent: somebody choosing
   to collect needs to know where they are going BEFORE they pay, not on the
   confirmation page afterwards. */
.pickup-point {
  margin-top: 12px; padding: 14px 16px;
  border: 1px solid #eadfd4; border-left: 3px solid var(--accent, #b07d4f);
  border-radius: 10px; background: #fdf6ef;
}
.pickup-point-label { font-size: .78rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.pickup-point-name { font-size: 1.05rem; font-weight: 700; margin-top: 2px; }
.pickup-point-store { color: var(--muted); font-size: .9rem; }
.pickup-point .co-hint { margin-top: 8px; }


/* ==========================================================================
   PUBLIC INFORMATION PAGES  (Public Content Management V1)
   --------------------------------------------------------------------------
   Reading width rather than full width: a returns policy set across a wide
   monitor is a policy nobody finishes.
   ========================================================================== */
.content-page { max-width: 720px; margin: 26px auto 40px; }
.content-title { font-size: 1.9rem; margin: 0 0 16px; }

/* ---- WHOSE POLICY IS THIS -------------------------------------------------
   A quiet strip under the heading of a page that belongs to one market,
   naming it. It is system-generated from Store Master Data, so it says the
   same thing in both languages and reads correctly in both directions — the
   layout is logical (margin-inline-start, not margin-left), so RTL needs no
   second rule and cannot drift from this one.

   It is deliberately small. A reader wants to know whose shipping policy they
   are reading; they do not want a second page header telling them. */
.content-store-context {
  display: inline-flex; align-items: center; gap: 8px;
  margin: -6px 0 18px; padding: 5px 12px;
  border: 1px solid var(--line); border-radius: 999px;
  background: #fff;
  font-size: .85rem; font-weight: 700; color: var(--accent-dark);
  max-width: 100%;
}
.content-store-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent); flex: 0 0 auto;
}
/* The name is Master Data and may be long. It wraps rather than pushing the
   page sideways — a horizontal scrollbar on a phone is the failure this
   guards against. */
.content-store-name { min-width: 0; overflow-wrap: anywhere; }

@media (max-width: 560px) {
  .content-store-context { font-size: .8rem; padding: 4px 10px; }
}

/* ==========================================================================
   AN AUTHORED PAGE THAT IS NOT IN THE READER'S LANGUAGE  (P035-C10C)
   --------------------------------------------------------------------------
   The notice is system UI and follows the interface; the article beneath it
   carries its own lang and dir, so English prose inside an Arabic shop is laid
   out left to right where it belongs. Nothing here mirrors the article — a
   policy forced into RTL is unreadable in the name of consistency.
   ========================================================================== */
.content-fallback-note {
  margin: 0 0 18px; padding: 10px 14px;
  border: 1px solid var(--line); border-inline-start: 3px solid var(--accent);
  border-radius: var(--radius); background: var(--card);
  color: var(--ink); font-size: .9rem; line-height: 1.55;
}
/* The article isolates itself so its direction cannot leak into the page
   around it, nor the page's into it. */
.content-authored { unicode-bidi: isolate; }

/* The language control in the editor: one page, one editor, a choice. */
.content-lang-switch {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  margin: 0 0 16px;
}
.content-lang-label {
  color: var(--muted); font-size: .75rem;
  text-transform: uppercase; letter-spacing: .05em;
}
.content-lang-btn {
  min-height: 44px; padding: 0 14px;
  border: 1px solid var(--line); border-radius: 999px;
  background: #fff; color: var(--ink); font-size: .95rem; cursor: pointer;
}
.content-lang-btn:hover { border-color: var(--accent); }
.content-lang-btn.on { background: var(--accent); color: #fff; border-color: var(--accent); }
.content-lang-none { opacity: .75; font-size: .8rem; }
.content-lang-btn.on .content-lang-none { opacity: .9; }

/* A language nobody has written yet — stated, with the one action that fits. */
.content-absent p { margin: 0 0 12px; }

.content-body { color: var(--ink); font-size: 1rem; line-height: 1.7; }
.content-body p { margin: 0 0 14px; }
.content-body h2 { font-size: 1.25rem; margin: 26px 0 10px; }
.content-body h3 { font-size: 1.05rem; margin: 20px 0 8px; }
.content-body ul, .content-body ol { margin: 0 0 14px; padding-left: 22px; }
.content-body li { margin-bottom: 6px; }
.content-body a { color: var(--accent-dark); }

/* Contact details are a description list, so a screen reader reads
   "Email, shop@…" rather than two unrelated pieces of text. */
.contact-details { margin: 26px 0 0; padding: 18px 20px; background: #fdf6ef; border: 1px solid #eadfd4; border-radius: 12px; }
.contact-row { display: flex; gap: 14px; padding: 7px 0; align-items: baseline; }
.contact-row + .contact-row { border-top: 1px solid #f0e6da; }
.contact-details dt { flex: 0 0 120px; color: var(--muted); font-size: .86rem; }
.contact-details dd { margin: 0; flex: 1; min-width: 0; word-break: break-word; }
.contact-details a { color: var(--accent-dark); }

/* The home page's Information strip: three links where three duplicated
   paragraphs used to be. */
.info-links { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }
.info-link {
  border: 1px solid var(--line); background: #fff; border-radius: 999px;
  padding: 8px 18px; color: var(--ink); text-decoration: none; font-size: .95rem;
}
.info-link:hover { border-color: var(--accent); color: var(--accent-dark); }

/* ==========================================================================
   PAGE CONTENT EDITOR  (Public Content Management V1)
   ========================================================================== */
.content-status { display: flex; align-items: center; }
.content-meta {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 10px 18px; margin: 14px 0 18px; padding: 14px 16px;
  background: #fdf6ef; border: 1px solid #eadfd4; border-radius: 12px;
}
.content-meta > div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cm-label { font-size: .72rem; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); }

/* The formatting bar. Text buttons rather than icons: eight unlabelled
   glyphs is a puzzle, and this is used by one person a few times a month. */
.rt-toolbar { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; }
.rt-btn {
  border: 1px solid var(--line); background: #fff; color: var(--ink);
  border-radius: 7px; padding: 5px 11px; font-size: .84rem; cursor: pointer;
}
.rt-btn:hover { border-color: var(--accent); }
.rt-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.rt-editor {
  min-height: 260px; max-height: 60vh; overflow-y: auto;
  border: 1px solid var(--line); border-radius: 10px; padding: 14px 16px;
  background: #fff; line-height: 1.65; font-size: .98rem;
}
.rt-editor:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.rt-editor p { margin: 0 0 12px; }
.rt-editor h2 { font-size: 1.2rem; margin: 18px 0 8px; }
.rt-editor h3 { font-size: 1.02rem; margin: 14px 0 6px; }
.rt-editor ul, .rt-editor ol { margin: 0 0 12px; padding-left: 22px; }
.rt-editor a { color: var(--accent-dark); }

.content-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 18px 0 40px; }
.content-note { color: var(--muted); font-size: .88rem; }
.content-note.is-error { color: #a4342a; }
.btn-outline.danger { border-color: #e0c3bd; color: #a4342a; }
.btn-outline.danger:hover { border-color: #a4342a; }

/* ==========================================================================
   STORE FULFILMENT QUEUE
   ========================================================================== */
.fq-summary { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 20px; }
.fq-chip {
  border: 1px solid var(--line); background: #fff; border-radius: 999px;
  padding: 6px 14px; font-size: .86rem; color: var(--ink);
}
.fq-chip strong { color: var(--accent-dark); }
.fq-chip.quiet { color: var(--muted); background: var(--bg); }

.fq-group { margin-bottom: 26px; }
.fq-heading { font-size: 1.02rem; margin: 0 0 10px; display: flex; align-items: center; gap: 8px; }
.fq-count { background: var(--bg); border-radius: 999px; padding: 1px 9px; font-size: .78rem; color: var(--muted); font-weight: 600; }
.fq-rows { display: flex; flex-direction: column; gap: 6px; }

.fq-row {
  display: grid; grid-template-columns: 1.2fr 1fr 1.3fr .8fr auto;
  gap: 12px; align-items: center;
  padding: 12px 14px; border: 1px solid var(--line); border-radius: 10px;
  background: #fff; text-decoration: none; color: var(--ink);
}
.fq-row:hover { border-color: var(--accent); background: #fdfaf6; }
.fq-row:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.fq-ref { font-weight: 700; font-size: .92rem; }
.fq-method, .fq-who, .fq-when { color: var(--muted); font-size: .9rem; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fq-next { justify-self: end; }

@media (max-width: 720px) {
  .fq-row { grid-template-columns: 1fr auto; row-gap: 4px; }
  .fq-when { display: none; }
  .fq-next { grid-column: 2; grid-row: 1 / span 2; }
}

/* ==========================================================================
   PAYMENT METHODS BY STORE — configuration screen
   ========================================================================== */
.pay-method { border: 1px solid var(--line); border-radius: 10px; padding: 14px 16px; margin-bottom: 12px; background: #fff; }
.pay-method-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.pay-method-name { font-size: 1.02rem; }
.pay-method-desc { color: var(--muted); font-size: .88rem; margin-top: 2px; }
.pay-channels { display: flex; flex-wrap: wrap; gap: 18px; margin-top: 12px; }
/* A control that can never be switched on reads as unavailable, not broken. */
.pay-impossible { opacity: .45; }
.pay-restriction { color: var(--accent-dark); }
.pay-policy { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 0 18px; }
.pay-elig { display: flex; flex-direction: column; gap: 6px; }
.pay-elig-row { display: flex; align-items: center; gap: 14px; padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px; background: #fff; }
.pay-elig-label { flex: 0 0 210px; color: var(--muted); font-size: .9rem; }
.pay-elig-value { flex: 1; display: flex; flex-wrap: wrap; gap: 6px; }
@media (max-width: 620px) { .pay-elig-row { flex-direction: column; align-items: flex-start; gap: 6px; } .pay-elig-label { flex: none; } }

/* ==========================================================================
   P1B-ii — STORE PRICING
   --------------------------------------------------------------------------
   The unpriced state is styled to look like a problem, because it is one: a
   product with no price in a market cannot be sold there, and a row that
   looked ordinary would let an owner scroll past forty of them.
   ========================================================================== */
.pr-summary { display:flex; flex-wrap:wrap; gap:.6rem; align-items:center; margin:.4rem 0 .9rem; }
.pr-chip { font-size:.82rem; padding:.2rem .6rem; border-radius:999px;
           background:var(--surface-2,#f2efe9); border:1px solid rgba(0,0,0,.08); }
.pr-chip-ok { background:#e8f4ea; border-color:#bcdcc2; }
.pr-chip-warn { background:#fdf0e2; border-color:#eccfa6; font-weight:600; }
/* LOGICAL, NOT PHYSICAL. `margin-left`, `border-left` and `text-align:left`
   stay on the left in Arabic, so the filter drifted to the wrong end of the
   row, the explanation's accent bar sat on the wrong side of its text and
   every column heading pulled away from the column it names. The logical
   equivalents flip with the document. */
.pr-filter { margin-inline-start:auto; }
.pr-explain { font-size:.88rem; line-height:1.5; margin:0 0 .9rem;
              padding:.6rem .8rem; border-inline-start:3px solid #eccfa6; background:#fdf8f1; }

/* Search sits above the table and wraps to its own line on a phone. */
.pr-search { display:flex; flex-wrap:wrap; align-items:center; gap:.5rem; margin:0 0 .9rem; }
.pr-search-label { font-size:.85rem; opacity:.8; }
.pr-search-input { flex:1 1 12rem; min-width:0; padding:.45rem .6rem; font-size:.9rem;
                   border:1px solid rgba(0,0,0,.2); border-radius:6px; }

.pr-table-wrap { overflow-x:auto; }
.pr-table { width:100%; border-collapse:collapse; font-size:.9rem; }
.pr-table th { text-align:start; font-weight:600; padding:.5rem .6rem;
               border-bottom:2px solid rgba(0,0,0,.1); white-space:nowrap; }
.pr-th-sub { display:block; font-weight:400; font-size:.75rem; opacity:.7; }
.pr-table td { padding:.55rem .6rem; border-bottom:1px solid rgba(0,0,0,.07); vertical-align:middle; }
.pr-row.pr-blocked { background:#fdf8f1; }
.pr-name strong { display:block; }
.pr-sku { font-size:.75rem; opacity:.65; font-family:ui-monospace,Menlo,Consolas,monospace; }

/* The master figure is reference, not an offer — it is deliberately quieter
   than the box that decides what a customer is charged. */
.pr-master { white-space:nowrap; opacity:.75; }
.pr-master-val { font-variant-numeric:tabular-nums; }
.pr-master-tag { display:block; font-size:.7rem; text-transform:uppercase;
                 letter-spacing:.04em; opacity:.7; }

.pr-input-wrap { display:inline-flex; align-items:center; gap:.35rem; }
.pr-cur { font-size:.8rem; opacity:.8; min-width:2.4rem; }
.pr-input { width:8rem; padding:.35rem .5rem; font-variant-numeric:tabular-nums;
            border:1px solid rgba(0,0,0,.2); border-radius:6px; background:#fff; }
.pr-input[readonly] { background:var(--surface-2,#f4f2ee); cursor:default; }
.pr-ok { color:#2f6b3d; font-weight:600; }
.pr-warn { color:#a3591b; font-weight:600; }
.pr-ro { font-size:.8rem; opacity:.7; }
.pr-actions { white-space:nowrap; }

/* ==========================================================================
   P1B-ii — COLLECTION POINTS
   ========================================================================== */
.pk-intro { margin-bottom:1rem; }
.pk-h1 { margin:0 0 .3rem; font-size:1.25rem; }
.pk-code { font-family:ui-monospace,Menlo,Consolas,monospace; font-size:.8rem;
           background:var(--surface-2,#f2efe9); padding:.05rem .35rem; border-radius:4px; }

.pk-status { padding:.6rem .8rem; border-radius:8px; margin:.2rem 0 .9rem; font-size:.9rem; }
.pk-status p { margin:.3rem 0 0; font-weight:400; }
.pk-ready { background:#e8f4ea; border:1px solid #bcdcc2; }
.pk-notready { background:#fdf0e2; border:1px solid #eccfa6; }

.pk-active { display:inline-flex; margin-bottom:1rem; }
.pk-fields { display:grid; gap:.9rem; grid-template-columns:repeat(auto-fit,minmax(16rem,1fr)); }
.pk-field { display:flex; flex-direction:column; gap:.25rem; }
.pk-field-missing .pk-input { border-color:#d99a4e; background:#fffaf3; }
.pk-label { font-size:.82rem; font-weight:600; }
.pk-req { font-weight:400; font-size:.72rem; text-transform:uppercase;
          letter-spacing:.04em; color:#a3591b; }
.pk-locked { font-weight:400; font-size:.72rem; text-transform:uppercase;
             letter-spacing:.04em; opacity:.65; }
.pk-input { width:100%; padding:.4rem .5rem; border:1px solid rgba(0,0,0,.2);
            border-radius:6px; background:#fff; font:inherit; }
.pk-input[readonly] { background:var(--surface-2,#f4f2ee); cursor:default; }
.pk-hint { margin:0; font-size:.76rem; opacity:.7; line-height:1.4; }
.pk-missing-note { margin:0; font-size:.76rem; color:#a3591b; }
.pk-actions { margin-top:1rem; }

/* ==========================================================================
   P2 — THE PUBLIC STORE SELECTOR
   --------------------------------------------------------------------------
   Which market somebody is buying from is the first thing that should be
   obvious about a two-market shop, so it sits in the header beside the
   currency selector rather than inside a settings panel. It borrows the
   currency selector's shape deliberately — this is not a new visual idea,
   it is the same control answering a more important question — and carries a
   little more weight because the answer changes what things cost.
   ========================================================================== */
.store-select-wrap { display: inline-flex; align-items: center; margin-right: 6px; }
.store-select {
  appearance: none;
  border: 1px solid var(--accent); background: #fff; color: var(--ink);
  border-radius: 999px; padding: 7px 26px 7px 12px;
  font: inherit; font-size: .85rem; font-weight: 700; cursor: pointer;
  max-width: 11rem; text-overflow: ellipsis;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237a716a' stroke-width='2.2' stroke-linecap='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 8px center; background-size: 12px;
}
.store-select:hover { border-color: var(--accent); }
.store-select:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* On a phone the header is already crowded. The control keeps its full hit
   target and loses only width, because a selector too small to tap is worse
   than one that wraps. */
@media (max-width: 560px) {
  .store-select { max-width: 7.5rem; font-size: .8rem; padding: 7px 24px 7px 10px; }
}

/* A price that does not exist is never a number. This is the line that says
   so, and it must not look like a price. */
.card-price:not(:empty) { min-height: 1.2em; }

/* ==========================================================================
   P2-R1 — INLINE STOCK
   --------------------------------------------------------------------------
   The number in this cell is now the thing an owner comes to this page to
   change, so it is given a real target to press rather than a link to a form.
   The minus greys out at the reserved floor — the server refuses it anyway,
   but a control that looks pressable and then refuses is a worse experience
   than one that shows the limit.
   ========================================================================== */
.inv-cell { display: flex; flex-direction: column; gap: 2px; align-items: flex-start; }
.inv-stepper { display: inline-flex; align-items: stretch; border: 1px solid var(--line);
               border-radius: 8px; overflow: hidden; background: #fff; }
.inv-step {
  min-width: 26px; min-height: 26px; border: 0; background: var(--surface-2, #f5f2ed);
  color: var(--ink); font: inherit; font-size: 1rem; font-weight: 700; line-height: 1;
  cursor: pointer; padding: 0 8px;
}
.inv-step:hover:not(:disabled) { background: var(--accent); color: #fff; }
.inv-step:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.inv-step:disabled { opacity: .38; cursor: not-allowed; }
.inv-onhand {
  width: 3.2rem; min-height: 26px; border: 0; border-left: 1px solid var(--line);
  border-right: 1px solid var(--line); text-align: center; font: inherit;
  font-weight: 700; font-variant-numeric: tabular-nums; background: #fff; color: var(--ink);
}
.inv-onhand:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* One line, not three. Wrapping these turned a table row into a paragraph. */
.inv-detail { display: flex; flex-wrap: nowrap; gap: 0 7px; font-size: .66rem;
              color: var(--muted); line-height: 1.25; white-space: nowrap; }
.inv-fig { white-space: nowrap; }
.inv-k { text-transform: uppercase; letter-spacing: .03em; }
.inv-fig b { font-variant-numeric: tabular-nums; color: var(--ink); }
.inv-busy { opacity: .55; pointer-events: none; }
.inv-digital-note { font-size: .78rem; color: var(--muted); font-style: italic; }

/* ==========================================================================
   P2-R1 — GLOBAL PRODUCT POLICY
   --------------------------------------------------------------------------
   The word GLOBAL is the most important thing in this cell. Somebody looking
   at the Jordan Store is about to change something for Saudi as well, and the
   only defence against that surprise is saying so where they are looking.
   ========================================================================== */
.policy-scope-head, .policy-scope {
  display: inline-block; font-size: .56rem; font-weight: 800; letter-spacing: .07em;
  background: #ede4d6; color: #6b5836; border-radius: 999px; padding: 0 5px;
  text-transform: uppercase; line-height: 1.5;
}
.policy-scope-head { margin-left: 6px; }
.prod-policy { display: flex; flex-direction: column; gap: 2px; align-items: flex-start; }
.pol-type {
  font: inherit; font-size: .74rem; padding: 1px 5px; border-radius: 6px;
  border: 1px solid var(--line); background: #fff; color: var(--ink); cursor: pointer;
}
.pol-type:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.pol-type-ro { font-size: .78rem; font-weight: 600; }
.pol-flags { display: flex; flex-wrap: nowrap; gap: 0 7px; white-space: nowrap; }
.pol-flag { display: inline-flex; align-items: center; gap: 2px; font-size: .68rem; cursor: pointer; }
.pol-flag.is-ro { cursor: default; opacity: .75; }
.pol-flag input { width: 13px; height: 13px; margin: 0; accent-color: var(--accent); }
.pol-flag input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* On a phone the nine-column grid stops being a table and becomes a stack.
   A tiny desktop table is not a responsive design, it is an unusable one. */
@media (max-width: 900px) {
  .prod-head { display: none; }
  .prod-row {
    grid-template-columns: 1fr 1fr;
    gap: 8px 12px; padding: 12px 14px;
  }
  .prod-cell { grid-column: 1 / -1; }
  .prod-policy, .prod-stock { grid-column: 1 / -1; }
  .inv-stepper { width: 100%; max-width: 12rem; }
  .inv-step { min-width: 44px; min-height: 40px; }      /* a real thumb target */
  .inv-onhand { flex: 1; min-height: 40px; font-size: 1rem; }
  .prod-actions { grid-column: 1 / -1; }
}

/* ==========================================================================
   P3 — JORDAN ONLINE PICKUP + CASH AT STORE
   --------------------------------------------------------------------------
   Reuses the existing tokens rather than introducing a second palette. The
   only genuinely new idea here is the WARNING state on a collection that is
   running out of time, which has to be noticeable at a glance from across a
   counter without shouting on every other row.
   ========================================================================== */

.pay-methods { margin-top: 1rem; }
.pay-note {
  margin-top: .6rem; padding: .7rem .9rem;
  background: var(--surface-2, #faf7f2);
  border: 1px solid var(--line, #e7ded2); border-radius: 10px;
  font-size: .92rem; line-height: 1.5;
}
.pay-note p { margin: 0 0 .4rem; }
.pay-note p:last-child { margin-bottom: 0; }

.pickup-person { margin-top: .8rem; }
.pickup-person label[for="pickupPersonName"] { display: block; margin-top: .6rem; }

/* The customer's own view of a collection. */
.pickup-block .kv { align-items: flex-start; }
.pickup-soon { color: var(--danger, #b23b3b); font-weight: 600; }

/* The counter's view. */
.pickup-desk .pk-actions {
  display: flex; flex-wrap: wrap; gap: .5rem; margin-top: 1rem;
}
.pk-cancel-form { margin-top: .8rem; display: grid; gap: .4rem; }
.pk-cancel-form select,
.pk-cancel-form textarea {
  width: 100%; padding: .5rem .6rem;
  border: 1px solid var(--line, #e7ded2); border-radius: 8px;
  font: inherit; background: #fff;
}

/* A row in the orders list that is a collection. */
.or-pickup { margin-top: .35rem; display: flex; flex-wrap: wrap; gap: .3rem; justify-content: flex-end; }
.or-pickup .or-city { width: 100%; text-align: right; }

.pill.warn { background: #fdf0e3; color: #8a5a1a; border-color: #f0d9bb; }
.pill.ok   { background: #e8f4ec; color: #256b40; border-color: #c6e3d1; }

/* Kept visually distinct from the primary action: cancelling frees stock and
   ends a confirmed order, and it should never be the button somebody presses
   by muscle memory. */
.btn-danger {
  background: #fff; color: var(--danger, #b23b3b);
  border: 1px solid var(--danger, #b23b3b);
  border-radius: 999px; padding: .55rem 1.1rem;
  font: inherit; font-weight: 600; cursor: pointer;
}
.btn-danger:hover { background: #fdf3f3; }
.btn-secondary {
  background: #fff; color: var(--ink, #2f2a25);
  border: 1px solid var(--line, #d9cebd);
  border-radius: 999px; padding: .55rem 1.1rem;
  font: inherit; font-weight: 600; cursor: pointer;
}
.btn-secondary:hover { background: var(--surface-2, #faf7f2); }
.btn-danger[disabled], .btn-secondary[disabled] { opacity: .55; cursor: not-allowed; }

.form-msg { margin-top: .6rem; font-size: .92rem; color: var(--muted, #7a6f62); }
.field-hint { margin: .3rem 0 0; font-size: .88rem; color: var(--muted, #7a6f62); }

/* The collection chips read as a group of their own, because they answer a
   different question from the status chips beside them. */
.chip.pickup-chip { border-style: dashed; }
.chip.pickup-chip.active { border-style: solid; }

/* THE EXCEPTION QUEUE  (P035 D7 — R5). It reads as the warning it is rather
   than as one more state: the same warning colours the Needs-attention tile
   and the flagged row already use, so the three say the same thing in the same
   language. Selected, it fills like every other chip, so which view is active
   is never in doubt. */
.chip.attention { border-color: #f0cfc9; background: #fff7f5; color: #a13228; }
.chip.attention:hover { border-color: #a13228; }
.chip.attention.active { background: #a13228; border-color: #a13228; color: #fff; }

@media (max-width: 640px) {
  .pickup-desk .pk-actions { flex-direction: column; align-items: stretch; }
  .pickup-desk .pk-actions button { width: 100%; }
  .or-pickup { justify-content: flex-start; }
  .or-pickup .or-city { text-align: left; }
}

/* ==========================================================================
   P4 — CASH SALES AT THE COUNTER
   --------------------------------------------------------------------------
   MOBILE FIRST, and meant literally: this screen is used one-handed, standing
   up, with a customer waiting. So the phone layout is the default and the
   desktop one is the media query, rather than the other way round.

   Touch targets are 44px or larger throughout — the size a thumb actually
   hits rather than the size a mouse can manage. Nothing horizontal ever
   scrolls: long product names wrap, and the grid reflows.
   ========================================================================== */
.pos-main { max-width: 1440px; }
.pos-shell { display: flex; flex-direction: column; gap: 14px; }
/* The choosing half of the till. It is one element so that the two-column
   rule further down has exactly two things to place — see the note there. */
.pos-pick { display: flex; flex-direction: column; gap: 14px; min-width: 0; }

.pos-top {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
}
.pos-top h1 { margin: 0; font-size: 1.35rem; }
.pos-store-line { margin: 2px 0 0; color: var(--muted); font-size: .9rem; }

.pos-notice {
  margin: 0; padding: 10px 12px; border-radius: var(--radius);
  border: 1px solid var(--line); background: var(--card); font-size: .95rem;
}
.pos-notice.warn { border-color: #e0b070; background: #fdf6ec; }
.pos-notice.bad  { border-color: #dd9999; background: #fdf0f0; }

.pos-review {
  border: 1px solid #e0b070; background: #fdf6ec;
  border-radius: var(--radius); padding: 12px 14px;
}
.pos-review h3 { margin: 0 0 6px; font-size: 1rem; }
.pos-review p  { margin: 0 0 6px; font-size: .92rem; }
.pos-review ul { margin: 0 0 8px; padding-left: 18px; }
.pos-review li { font-size: .92rem; }

.pos-search input {
  width: 100%; box-sizing: border-box; min-height: 48px;
  padding: 10px 14px; font-size: 1rem;
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--card);
}

/* ---- the products ------------------------------------------------------ */
.pos-grid {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
.pos-card {
  display: flex; flex-direction: column; gap: 8px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--card); padding: 10px;
  min-width: 0;
}
.pos-card.is-out { opacity: .55; }
.pos-card-img {
  height: 92px; border-radius: 10px; background: #f2ece5;
  display: flex; align-items: center; justify-content: center; overflow: hidden;
}
.pos-card-img img { width: 100%; height: 100%; object-fit: cover; }
.pos-card-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pos-card-name {
  font-weight: 600; font-size: .95rem; line-height: 1.25;
  /* break-word, not anywhere: a product card should wrap between words like
     the sale panel does, and break inside one only when the word alone will
     not fit. The two-line clamp below still bounds the card's height. */
  overflow-wrap: break-word;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.pos-card-price { font-variant-numeric: tabular-nums; font-weight: 700; }
.pos-card-stock { font-size: .82rem; color: var(--muted); }
.pos-card-stock.out { color: #a3462f; font-weight: 600; }
.pos-add { min-height: 44px; width: 100%; }
.pos-add[disabled] { cursor: not-allowed; }

/* ==========================================================================
   THE PROGRESSIVE CATALOGUE AT THE COUNTER  (P033)
   --------------------------------------------------------------------------
   These rules were missing when P033 shipped. The markup and the behaviour
   were both correct and every functional test passed — because a test that
   clicks a control does not care how large it is. P034-A measured the tiles at
   21px high on a phone, which is well under a thumb and a long way from the
   "large, clear, touch-friendly" the Jordan operator was promised.

   44px is the floor here, matching .pos-add above. It is reached with real
   padding and min-height rather than an invisible overlay, so what the
   operator sees is what receives the tap.
   ========================================================================== */

/* ---- the category tiles ------------------------------------------------ */
.pos-cats {
  display: flex; flex-wrap: wrap; gap: 8px;
  padding: 2px 0;
}
.pos-cat {
  min-height: 44px; padding: 10px 16px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--card); color: var(--ink);
  font-size: 1rem; font-weight: 600; line-height: 1.2;
  cursor: pointer; white-space: nowrap;
}
.pos-cat:hover { background: var(--surface-2, #f5f2ed); }
/* THE CHOSEN ONE IS OBVIOUS, and not by colour alone — the border thickens
   too, so it still reads for somebody who cannot separate the two hues. */
.pos-cat.on {
  background: var(--accent); color: #fff; border-color: var(--accent);
}
.pos-cat.back { font-weight: 700; }

/* ---- products the shop knows but this counter does not sell yet -------- */
.pos-reference {
  border: 1px dashed var(--line); border-radius: var(--radius);
  background: var(--surface-2, #f7f5f1); padding: 12px;
  display: flex; flex-direction: column; gap: 10px;
}
/* DASHED, AND SAID IN WORDS. A reference product must never be mistaken for
   something that can be sold, so the container is deliberately unlike a
   product card and the heading says what these are. */
.pos-reference h2 { margin: 0; font-size: 1rem; color: var(--muted); }
.pos-reflist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.pos-reflist li {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px;
  padding: 10px 12px; background: var(--card);
  border: 1px solid var(--line); border-radius: var(--radius);
}
.pos-reflist li button { min-height: 44px; padding: 10px 16px; margin-inline-start: auto; }
.pos-refname { font-weight: 600; font-size: 1rem; min-width: 0; }
/* The English name sits beside the customer-facing one rather than replacing
   it, so a bilingual shelf reads either way round. */
.pos-refen { font-weight: 400; color: var(--muted); }
.pos-refbrand {
  font-size: .85rem; color: var(--muted);
  padding: 3px 8px; border: 1px solid var(--line); border-radius: 999px;
}

/* ---- adding a product that is not there -------------------------------- */
.pos-addnew {
  min-height: 44px; width: 100%; padding: 10px 16px; font-size: 1rem;
}
.pos-addform {
  border: 1px solid var(--accent); border-radius: var(--radius);
  background: var(--card); padding: 14px;
  display: flex; flex-direction: column; gap: 12px;
}
.pos-addform h2 { margin: 0; font-size: 1.05rem; }
.pos-addname { margin: 0; font-size: 1.05rem; font-weight: 600; }
.pos-addform label {
  display: flex; flex-direction: column; gap: 6px;
  font-size: .95rem; font-weight: 600;
}
/* Every field is a touch target too: a cashier typing a price on a phone
   should not have to aim. */
.pos-addform input,
.pos-addform select {
  min-height: 48px; box-sizing: border-box;
  padding: 10px 14px; font-size: 1rem; font-weight: 400;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--card); color: var(--ink);
}
.pos-addactions { display: flex; flex-wrap: wrap; gap: 10px; }
.pos-addactions button { min-height: 44px; padding: 10px 18px; font-size: 1rem; flex: 1 1 auto; }

/* ---- the two things that need saying clearly --------------------------- */
.pos-dup {
  margin: 0; padding: 10px 12px;
  border: 1px solid #e0b070; border-radius: var(--radius); background: #fdf6ec;
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  font-size: .95rem;
}
.pos-dup button { min-height: 44px; padding: 8px 14px; }
.pos-adderr {
  margin: 0; padding: 10px 12px;
  border: 1px solid #dd9999; border-radius: var(--radius); background: #fdf0f0;
  color: #8a2f2f; font-size: .95rem; font-weight: 600;
}

/* ---- the category tree, on the owner's products screen ----------------- */
.cat-row.cat-child { padding-left: 26px; position: relative; }
/* A child is shown as being INSIDE its parent rather than merely after it. */
.cat-row.cat-child::before {
  content: "\21B3"; position: absolute; left: 8px; color: var(--muted);
}
.cat-parent {
  min-height: 38px; padding: 6px 10px;
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--card);
}

/* ---- the cart ---------------------------------------------------------- */
.pos-cart {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--card); padding: 12px; display: flex; flex-direction: column; gap: 10px;
}
.pos-cart h2 { margin: 0; font-size: 1.05rem; }
.pos-lines { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
/* THE NAME GETS THE WHOLE WIDTH, and the controls get the row beneath it.
   Sharing one row could never work in a 340px sale panel: the steppers and the
   quantity box are 152px, the money another 86px, and the name was left with
   whatever remained — 56px, which is narrower than the word "Bracelet". A
   product name is the thing the operator reads to check they are charging for
   the right item, so it gets the full width and the controls, all still 44px,
   sit under it. */
.pos-line {
  display: grid; gap: 6px 10px; align-items: center;
  grid-template-columns: auto 1fr auto;
  grid-template-areas:
    "main    main    main"
    "qty     total   remove"
    "problem problem problem";
  padding: 8px 0; border-bottom: 1px solid var(--line);
}
.pos-line:last-child { border-bottom: none; }
/* WHY `min-content` AND NOT `0`.
   With `min-width: 0` the 1fr track may be squeezed to nothing, and
   `overflow-wrap: anywhere` then happily breaks inside a word to fit whatever
   is left: the Product Owner saw "Test Bracelet" rendered as Test / Bracele /
   t in a 56px box that needed 58px for the word alone. `min-content` is
   exactly the width of the longest word, so the column can still shrink — it
   just cannot shrink past the point where English stops being readable.
   `break-word` then wraps between words, and still breaks a single
   unbreakable word rather than overflowing. Arabic behaves the same way. */
.pos-line-main { grid-area: main; min-width: min-content; display: flex; flex-direction: column; }
.pos-line-name { font-weight: 600; overflow-wrap: break-word; }
.pos-line-unit { font-size: .82rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.pos-line-qty { grid-area: qty; display: flex; align-items: center; gap: 4px; }
.pos-step {
  min-width: 44px; min-height: 44px; font-size: 1.2rem; line-height: 1;
  border: 1px solid var(--line); border-radius: 10px; background: var(--bg);
  color: var(--ink); cursor: pointer;
}
.pos-step:hover { border-color: var(--accent); }
/* THE QUANTITY IS NOW AN INPUT, not a label. It is sized as a real touch
   target rather than a number squeezed between two buttons: on a phone this is
   the control an operator reaches for most often after the product itself.
   `appearance: textfield` suppresses the browser's own tiny spinners, which are
   unusable with a thumb and duplicate the steppers either side. */
.pos-qty {
  width: 3.5rem; min-height: 44px; padding: 0 6px;
  text-align: center; font-weight: 700; font-variant-numeric: tabular-nums;
  font-size: 1rem; font-family: inherit;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--bg); color: var(--ink);
  -moz-appearance: textfield; appearance: textfield;
}
.pos-qty:focus { outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent); }
.pos-qty::-webkit-outer-spin-button,
.pos-qty::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.pos-line-total { grid-area: total; font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; text-align: right; }
.pos-remove {
  grid-area: remove; justify-self: end; min-height: 36px; padding: 0 10px;
  border: none; background: none; color: var(--muted); cursor: pointer;
  text-decoration: underline; font-size: .85rem;
}
.pos-line-problem { grid-area: problem; margin: 0; font-size: .85rem; color: #a3462f; }

.pos-customer summary { cursor: pointer; font-size: .92rem; color: var(--muted); min-height: 32px; }
.pos-customer-fields { display: flex; flex-direction: column; gap: 8px; padding-top: 8px; }
.pos-customer-fields label { display: flex; flex-direction: column; gap: 4px; font-size: .88rem; }
.pos-customer-fields input {
  min-height: 44px; padding: 8px 12px; font-size: 1rem;
  border: 1px solid var(--line); border-radius: 10px;
}

.pos-total-row {
  display: flex; align-items: baseline; justify-content: space-between;
  border-top: 2px solid var(--line); padding-top: 10px; font-size: 1.05rem;
}
.pos-total { font-size: 1.5rem; font-weight: 800; font-variant-numeric: tabular-nums; }

.pos-complete { min-height: 56px; font-size: 1.05rem; width: 100%; }
.pos-complete[disabled] { opacity: .5; cursor: not-allowed; }
.pos-clear { min-height: 44px; width: 100%; }

/* ---- the sale that worked ---------------------------------------------- */
.pos-done { align-items: center; text-align: center; }
.pos-done-mark {
  width: 64px; height: 64px; border-radius: 50%;
  background: var(--ok); color: #ffffff; font-size: 2rem; line-height: 64px;
}
.pos-done h1 { margin: 4px 0 0; }
.pos-done-ref { margin: 0; color: var(--muted); }
.pos-receipt {
  width: 100%; max-width: 380px; text-align: left;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--card); padding: 16px;
}
/* THE STORE THE CUSTOMER WALKED INTO IS THE NAME AT THE TOP, and Marmocha is
   the quieter line under it. The order is set in the markup, in owner-pos.html
   and in lib/receipt-html.js, from the same two fields of the same model. */
.pos-receipt h2 { margin: 0; font-size: 1.25rem; line-height: 1.3; }
.pos-receipt-platform { margin: 2px 0 0; color: var(--muted); font-size: .8rem; }
.pos-receipt-when { margin: 6px 0 0; color: var(--muted); font-size: .85rem; }
.pos-receipt-reflabel {
  margin: 10px 0 0; color: var(--muted); font-size: .75rem;
  text-transform: uppercase; letter-spacing: .04em;
}
.pos-receipt-ref {
  margin: 0; font-size: 1rem; font-weight: 700; letter-spacing: .02em;
  unicode-bidi: isolate;
}
.pos-receipt-voided {
  margin: 0 0 10px; padding: 6px 10px; text-align: center;
  border: 2px solid var(--ink); border-radius: 6px;
  font-weight: 800; letter-spacing: .08em;
}
.pos-receipt-lines {
  list-style: none; margin: 12px 0; padding: 12px 0;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
}
/* FOUR THINGS, AND ONLY THE NAME MAY WRAP. The name takes the space that is
   left; the quantity, the unit price and the line total each keep their own
   run and sit together at the end, so the numbers stay in a readable column
   whichever way round the page is running. */
.pos-receipt-lines li {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 8px; padding: 4px 0; font-size: .92rem;
}
.pos-receipt-name { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.pos-receipt-qty, .pos-receipt-unit, .pos-receipt-linetotal {
  flex: 0 0 auto; white-space: nowrap; font-variant-numeric: tabular-nums;
}
.pos-receipt-unit { color: var(--muted); font-size: .85em; }
.pos-receipt-linetotal { font-weight: 600; }
.pos-receipt-sub {
  display: flex; justify-content: space-between; gap: 12px;
  margin: 0 0 4px; color: var(--muted); font-size: .92rem;
}
/* A STATEMENT, ONCE PER RECEIPT. Not a warning, and not fine print somebody
   has to squint at: the customer is told plainly what they have bought. */
.pos-receipt-disclosure {
  margin: 12px 0 0; padding-top: 10px; border-top: 1px dotted var(--line);
  color: var(--ink); font-size: .82rem; line-height: 1.5;
}
/* The name lays itself out without dragging the quantity around it, whichever
   direction its first character leans — the screen's half of the bidi fix in
   owner.js. The quantity keeps its own left-to-right run. */
/* ==========================================================================
   THE COMPOUNDED-PERFUME NOTICE  (P035-C4)
   --------------------------------------------------------------------------
   Customer-facing, on the product page, above the Add to Basket control. Not
   a warning and not fine print: a quiet, readable statement of what is being
   sold. It appears only on products whose pictures are recorded as fragrance
   references. It is deliberately absent from the SELLING screen at the
   counter — a cashier taking cash does not need it between them and the
   customer — and it IS on the receipt they hand over, once for the whole
   sale rather than once per line. See receiptNeedsPerfumeDisclosure() in
   lib/pos.js, which asks the catalogue’s own question rather than a second
   one, and `receipt.perfumeDisclosure` in the dictionary for the wording.
   ========================================================================== */
.pd-reference {
  margin: 14px 0; padding: 12px 14px;
  border: 1px solid var(--line); border-left: 3px solid var(--accent);
  border-radius: var(--radius); background: var(--card);
}
.pd-reference p { margin: 0; font-size: .9rem; line-height: 1.55; color: var(--ink); }
.pd-reference-ar { unicode-bidi: isolate; }
.pd-reference-en { unicode-bidi: isolate; margin-top: 8px !important; color: var(--muted); }

.pos-receipt-name { unicode-bidi: isolate; overflow-wrap: anywhere; }
.pos-receipt-qty { unicode-bidi: isolate; white-space: nowrap; }
.pos-receipt-total { display: flex; justify-content: space-between; margin: 0; font-size: 1.1rem; }
.pos-receipt-total strong { font-variant-numeric: tabular-nums; }
.pos-receipt-pay { margin: 8px 0 0; color: var(--muted); font-size: .9rem; }
.pos-done-actions { display: flex; flex-direction: column; gap: 10px; width: 100%; max-width: 380px; }
/* AN ANCHOR IS A TOUCH TARGET TOO. The way through to the Sales Report is a
   link rather than a button, and a rule written for buttons alone left it
   below the 44px floor while looking correct on the page — the sort of gap
   that is invisible until somebody with a thumb misses it. */
.pos-done-actions button,
.pos-done-actions a { min-height: 48px; }
.pos-done-actions a {
  display: flex; align-items: center; justify-content: center;
  text-decoration: none;
}

/* WHAT HAPPENS NEXT, AND WHAT HAPPENS TO THE PAPER, are different questions.
   New sale is the one the operator presses with somebody waiting, so it is
   primary and stands alone. Print, PDF and Share are three ways of handing
   over one receipt, so they are enclosed and labelled as one thing. Recent
   sales is a way back and stays quiet. */
.pos-primary-action { min-height: 56px; font-size: 1.05rem; }
.pos-receipt-actions {
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 10px 12px 12px; background: var(--card);
}
.pos-receipt-actions-label {
  display: block; margin-bottom: 8px; text-align: start;
  color: var(--muted); font-size: .75rem;
  text-transform: uppercase; letter-spacing: .05em;
}
.pos-receipt-actions-row { display: flex; gap: 8px; }
/* Three equal targets, each at least 44px tall, that stay side by side on a
   narrow phone instead of stacking into a column of identical buttons. */
.pos-receipt-actions-row > * {
  flex: 1 1 0; min-width: 0; min-height: 48px;
  display: inline-flex; align-items: center; justify-content: center;
  text-align: center;
}
.pos-quiet-action { min-height: 44px; }

/* ---- recent sales ------------------------------------------------------ */
.pos-recent { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.pos-recent li {
  display: grid; gap: 4px 10px; align-items: center;
  grid-template-columns: 1fr auto;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--card); padding: 10px 12px;
}
.pos-recent-when { color: var(--muted); font-size: .85rem; }
.pos-recent-ref { font-weight: 600; overflow-wrap: anywhere; }
.pos-recent-total { font-weight: 700; font-variant-numeric: tabular-nums; text-align: right; }
.pos-recent-pay { color: var(--muted); font-size: .85rem; }

/* ---- roomier once there is room ---------------------------------------- */
/* THIS RULE ASSUMES THE SHELL HAS TWO FLOW CHILDREN: the choosing half and the
   sale. It always did, and for a phase it silently did not — P033 added the
   category tiles, the reference block, the quick-add form and its button as
   further children, so auto-placement dealt them alternately into the two
   columns and the product grid landed in the 340px one. Measured at P034-C:
   340px of products and 340px of cart inside 1100px of page, on a 1920px
   screen. `.pos-pick` gives the rule its two children back.
   `minmax(0, 1fr)` rather than `1fr` so a long word in a card can never push
   the products column wider than its share. */
@media (min-width: 720px) {
  .pos-shell { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 16px; align-items: start; }
  .pos-top, .pos-notice, .pos-review, .pos-search { grid-column: 1 / -1; }
  .pos-cart { position: sticky; top: 12px; }
  .pos-done { display: flex; }
  .pos-shell[data-pos-view="recent"] { display: flex; }
}
/* With the full width actually available, cards can be a readable size rather
   than as many as will fit. 170px keeps a two-line name and a real price
   legible; the catalogue gets wider, not denser. */
@media (min-width: 1100px) {
  .pos-grid { grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); }
}

/* ==========================================================================
   THE COUNTER HEADER ON A PHONE  (P034-C, UX-04)
   --------------------------------------------------------------------------
   Measured at P034-C on a 400x598 screen: 286px of header, 48% of the
   viewport, and sticky — so half the phone was permanently spent on chrome
   and stayed spent while the operator scrolled for a product. A drawer
   toggle, the brand, an identity line, four controls and a "Managing store"
   badge were wrapping onto five rows in a container built for one.

   Everything here is scoped to `.pos-body` and to phone widths. The desktop
   header is untouched, every other owner page is untouched, and no navigation
   is redesigned: the same links are rendered by the same code in the same
   order. What changes is how much room they are asked to take.

   NOTHING IS HIDDEN THAT THE OPERATOR NEEDS TO KNOW. The person's name and
   their role badge both stay — a cashier must be able to see whose till this
   is before taking money. Only the words "Signed in as" go, because the name
   beside a role badge already says it, and the brand's "Cash Sales" subtitle
   goes because the page's own <h1> says exactly that two inches below.

   The header also stops being sticky here. That is the finding's real cost:
   a 286px band that follows you down the page is 286px the products never
   get. It scrolls away now and comes back with one flick upward.
   ========================================================================== */
@media (max-width: 719px) {
  .pos-body .owner-header { position: static; }
  /* A GRID, not a wrapping flex row. Flex decides where a line breaks from
     content widths, and with items of unknown width it put the four controls
     on three separate rows. A grid says where the rows are: who and where on
     the first, what you can do on the second.

     TWO OF THESE CHILDREN ARE NOT IN THE PAGE'S MARKUP — owner.js injects the
     drawer toggle and the "Managing store" badge — which is why measuring the
     header beat reading it. A role shown more links than the counter operator
     simply flows onto a third row, each control keeping its 44px. */
  .pos-body .owner-header-inner {
    display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
    align-items: center; padding: 8px 12px; gap: 8px;
  }
  .pos-body .owner-header-inner > .icon-btn { grid-column: 1; justify-self: start; }
  .pos-body .owner-brand { grid-column: 2 / 4; font-size: .95rem; gap: 8px; }
  /* The injected badge says "Managing store / Jordan Store / Inventory
     location / Jordan Kiosk" — 189px of header restating what the page's own
     subtitle says two inches below it, store, location and currency together.
     The duplicate goes; the awareness stays, and is asserted as staying. */
  .pos-body .store-context { display: none; }
  .pos-body .owner-brand-sub { display: none; }
  .pos-body .owner-user-label { display: none; }
  /* The name over the badge, each on exactly one line. A display name is free
     text of unknown length, and letting it wrap made the header's height a
     function of whose shift it is — 109px for "qusai" and 130px for a longer
     one. Ellipsis instead: the operator still recognises their own name, and
     the row is 44px whoever signs in. */
  /* `display: contents` dissolves the right-hand group, exactly as
     `.owner-nav` already does, so the identity and the controls become grid
     items of the header alongside the brand. Nothing is removed from the
     header and nothing is reordered — the group simply stops being a box. */
  .pos-body .owner-header-right { display: contents; }
  .pos-body .owner-user {
    grid-column: 4; justify-self: end; text-align: right;
    font-size: .82rem; color: var(--ink); font-weight: 600;
    display: flex; flex-direction: column; align-items: flex-end;
    line-height: 1.25; min-width: 0; max-width: 100%;
  }
  .pos-body .owner-user strong {
    max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .pos-body .owner-role-tag { margin-left: 0; white-space: nowrap; }
  /* 44px targets sharing the second row evenly.
     DESCENDANT selectors, not `>`: `display: contents` changes which boxes are
     generated, never which elements a combinator matches. The links are still
     DOM children of `.owner-nav` and the button of `.owner-header-right`, so a
     child selector on `.owner-header-inner` matches none of them — which is
     how this first went out at 31px instead of 44px. */
  .pos-body .owner-header a.owner-btn-sm,
  .pos-body .owner-header-right > button {
    min-height: 44px; display: inline-flex;
    align-items: center; justify-content: center;
    padding: 6px 8px; font-size: .78rem; white-space: nowrap;
  }
}

/* ==========================================================================
   P5 — VOIDING A COUNTER SALE
   --------------------------------------------------------------------------
   Same mobile-first rules as the till itself: 44px targets, nothing scrolls
   sideways, long names wrap. A void is a rarer and heavier action than a sale,
   so its confirm button is the only prominent thing on its screen.
   ========================================================================== */

/* ---- a row in Recent sales is now a button ----------------------------- */
.pos-recent-open {
  display: grid; gap: 4px 10px; align-items: center; width: 100%;
  grid-template-columns: 1fr auto;
  background: none; border: none; padding: 0; margin: 0;
  font: inherit; color: inherit; text-align: left; cursor: pointer;
  min-height: 44px;
}
.pos-recent li { padding: 6px 12px; }
.pos-recent li.is-voided { opacity: .72; }
.pos-recent li.is-voided .pos-recent-total { text-decoration: line-through; }
.pos-recent-open:hover { color: var(--accent); }

/* ---- one sale, looked at ----------------------------------------------- */
.pos-detail-lines { list-style: none; margin: 0; padding: 0; }
.pos-detail-lines li {
  display: grid; gap: 2px 10px; align-items: baseline;
  grid-template-columns: 1fr auto auto;
  padding: 8px 0; border-bottom: 1px solid var(--line);
}
.pos-detail-lines li:last-child { border-bottom: none; }
/* Isolated so the name cannot drag the quantity beside it around, whichever
   direction its first character leans — the sale detail's half of the same
   fix the receipt and the storefront carry. */
.pos-detail-name { overflow-wrap: anywhere; font-weight: 600; unicode-bidi: isolate; }
.pos-detail-qty { unicode-bidi: isolate; white-space: nowrap; }
.pos-detail-unit { color: var(--muted); font-size: .85rem; font-variant-numeric: tabular-nums; }
.pos-detail-line { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.pos-detail-meta { margin: 0; color: var(--muted); font-size: .88rem; }
.pos-detail-blocked {
  margin: 0; padding: 10px 12px; border-radius: var(--radius);
  border: 1px dashed var(--line); color: var(--muted); font-size: .9rem;
}
.pos-void-open { min-height: 48px; width: 100%; }

/* ---- the voided banner -------------------------------------------------- */
.pos-voided-banner {
  border: 1px solid #d9a2a2; background: #fdf2f2;
  border-radius: var(--radius); padding: 12px 14px;
  display: flex; flex-direction: column; gap: 8px;
}
.pos-void-figures { margin: 0; display: flex; flex-wrap: wrap; gap: 10px 20px; }
.pos-void-figures > div { display: flex; flex-direction: column; }
.pos-void-figures dt { color: var(--muted); font-size: .8rem; }
.pos-void-figures dd {
  margin: 0; font-weight: 700; font-variant-numeric: tabular-nums; font-size: 1.05rem;
}
.pos-void-when, .pos-void-why, .pos-void-restored {
  margin: 0; color: var(--muted); font-size: .88rem; overflow-wrap: anywhere;
}

/* ---- the confirmation --------------------------------------------------- */
.pos-void-warning {
  margin: 0; padding: 12px 14px; border-radius: var(--radius);
  border: 1px solid #e0b070; background: #fdf6ec; font-size: .95rem;
}
.pos-void-field { display: flex; flex-direction: column; gap: 4px; font-size: .9rem; }
.pos-void-field select, .pos-void-field textarea {
  min-height: 48px; padding: 10px 12px; font-size: 1rem;
  border: 1px solid var(--line); border-radius: 10px; background: var(--card);
  color: var(--ink); width: 100%; box-sizing: border-box;
}
.pos-void-field textarea { min-height: 64px; resize: vertical; }
.pos-void-confirm-btn { min-height: 56px; font-size: 1.05rem; width: 100%; }
.pos-void-confirm-btn[disabled] { opacity: .5; cursor: not-allowed; }

.pos-done-mark.voided { background: #a3462f; }

@media (min-width: 720px) {
  .pos-shell[data-pos-view="detail"],
  .pos-shell[data-pos-view="void-confirm"],
  .pos-shell[data-pos-view="void-done"] { display: flex; max-width: 620px; }
}

/* ==========================================================================
   HELP CENTRE  (Living Documentation V1 — M3)
   --------------------------------------------------------------------------
   Deliberately built from what the shop already has: the same wrap, the same
   card surfaces, the same ink and accent, the same rounded outlines. Help is
   part of Marmocha rather than a documentation site wearing its colours.

   READING WIDTH IS CAPPED. An article measured across a wide monitor is
   physically hard to read — the eye loses the line coming back. 720px is
   what the Information pages already use, so the two feel the same.
   ========================================================================== */
.help { margin: 22px auto 48px; max-width: 860px; }

.help-title { font-size: 1.9rem; margin: 0 0 10px; line-height: 1.25; }
.help-lead { color: var(--muted); margin: 0 0 22px; max-width: 65ch; }
.help-back { margin: 0 0 14px; }
.help-back a { color: var(--accent-dark); text-decoration: none; font-weight: 600; }
.help-back a:hover { text-decoration: underline; }

/* ---- search ---- */
.help-search { margin: 0 0 26px; }
.help-search-label {
  display: block; font-weight: 700; margin-bottom: 8px; font-size: 1.05rem;
}
.help-search-row { display: flex; gap: 10px; flex-wrap: wrap; }
.help-search-input {
  flex: 1 1 240px; min-width: 0;
  border: 1px solid var(--line); background: #fff; border-radius: 999px;
  padding: 12px 18px; font-size: 1rem; font-family: inherit; color: var(--ink);
}
.help-search-input:focus {
  outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent);
}
.help-search-go { flex: 0 0 auto; }
.help-search-hint { color: var(--muted); font-size: .85rem; margin: 8px 0 0; }

/* ---- categories ---- */
.help-categories { display: grid; gap: 22px; }
.help-category {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 16px 18px;
}
.help-category-head {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin: 0 0 10px; font-size: 1.1rem;
}
.help-category-name { color: var(--ink); text-decoration: none; }
.help-category-name:hover { color: var(--accent-dark); text-decoration: underline; }
.help-count { color: var(--muted); font-size: .82rem; font-weight: 400; }

/* ---- an article in a list ---- */
.help-article-list { display: grid; gap: 2px; }
.help-article {
  display: block; text-decoration: none; color: inherit;
  padding: 10px 12px; border-radius: 10px;
}
.help-article:hover, .help-article:focus-visible { background: #f6f1ea; }
.help-article-title { display: block; font-weight: 600; color: var(--accent-dark); }
.help-article-summary { display: block; color: var(--muted); font-size: .88rem; margin-top: 2px; }

.help-badge {
  display: inline-block; margin-left: 8px; padding: 2px 9px;
  border: 1px solid #dcd3c7; border-radius: 999px;
  background: #f7f2ea; color: var(--muted);
  font-size: .72rem; font-weight: 600; white-space: nowrap; vertical-align: middle;
}

/* ---- results ---- */
.help-results { display: grid; gap: 10px; }
.help-result {
  display: block; text-decoration: none; color: inherit;
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 14px 16px;
}
.help-result:hover, .help-result:focus-visible { border-color: var(--accent); }
.help-result-head { display: flex; align-items: baseline; flex-wrap: wrap; }
.help-result-cat { display: block; color: var(--muted); font-size: .8rem; margin: 2px 0 6px; }
.help-snippet { display: block; color: var(--ink); font-size: .92rem; line-height: 1.6; }
.help-snippet mark { background: #fbe7cf; color: inherit; padding: 0 2px; border-radius: 3px; }

/* ---- one article ---- */
.help-article-page { max-width: 720px; }
.help-article-cat { margin: 0 0 6px; font-size: .85rem; }
.help-article-cat a { color: var(--muted); text-decoration: none; }
.help-article-cat a:hover { color: var(--accent-dark); text-decoration: underline; }

.help-body { font-size: 1rem; line-height: 1.75; }
.help-body p { margin: 0 0 14px; }
.help-body h2 { font-size: 1.25rem; margin: 28px 0 10px; }
.help-body h3 { font-size: 1.05rem; margin: 22px 0 8px; }
.help-body h4 { font-size: .98rem; margin: 18px 0 6px; }
.help-body ul, .help-body ol { margin: 0 0 14px; padding-left: 22px; }
.help-body li { margin-bottom: 6px; }
.help-body a { color: var(--accent-dark); }
.help-body strong { font-weight: 700; }
.help-body code {
  background: #f4efe8; border: 1px solid #e8e1d9; border-radius: 5px;
  padding: 1px 5px; font-size: .88em; word-break: break-word;
}
.help-body pre {
  background: #f4efe8; border: 1px solid #e8e1d9; border-radius: 10px;
  padding: 12px 14px; overflow-x: auto;
}
.help-body pre code { background: none; border: none; padding: 0; }
.help-body blockquote {
  margin: 0 0 14px; padding: 2px 16px; border-left: 3px solid var(--line); color: var(--muted);
}
.help-body hr { border: none; border-top: 1px solid var(--line); margin: 22px 0; }

/* A wide table scrolls INSIDE ITS OWN BOX. Letting the page scroll sideways
   instead is the classic way a documentation page becomes unusable on a
   phone: every paragraph shifts to make room for one table nobody is
   reading. */
.help-table-wrap { overflow-x: auto; margin: 0 0 16px; }
.help-body table { border-collapse: collapse; width: 100%; min-width: 340px; font-size: .93rem; }
.help-body th, .help-body td {
  border: 1px solid var(--line); padding: 8px 10px; text-align: left; vertical-align: top;
}
.help-body th { background: #f7f2ea; font-weight: 700; }

@media (max-width: 640px) {
  .help-title { font-size: 1.5rem; }
  .help-category { padding: 14px; }
  .help-search-go { width: 100%; }
}

/* ==========================================================================
   CONTEXTUAL HELP  (M4)
   --------------------------------------------------------------------------
   A quiet link beside a heading or under a button. Subtle on purpose: it is
   an offer, not a step, and it must never compete with the thing the person
   came to do. If the reader may not open the article it is not rendered at
   all — there is deliberately no "disabled" state to style.
   ========================================================================== */
.help-context { display: inline-block; vertical-align: middle; }
.help-context-row { margin: 10px 0 0; }

.help-context-link {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--muted); text-decoration: none;
  font-size: .85rem; font-weight: 500; line-height: 1.3;
  padding: 3px 8px; border-radius: 999px; border: 1px solid transparent;
}
.help-context-link:hover { color: var(--accent-dark); border-color: var(--line); }
.help-context-link:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px; color: var(--accent-dark);
}
.help-context-ico { display: inline-flex; width: 15px; height: 15px; flex: 0 0 15px; }
.help-context-ico svg { width: 100%; height: 100%; }

/* Beside an h2 the label should not inherit the heading's weight or size. */
h1 > .help-context, h2 > .help-context, h3 > .help-context { margin-left: 8px; }
h1 > .help-context .help-context-link,
h2 > .help-context .help-context-link,
h3 > .help-context .help-context-link { font-size: .8rem; font-weight: 500; }

@media (max-width: 640px) {
  /* On a phone a heading and its link wrap rather than squeezing the heading. */
  h2 > .help-context { display: block; margin: 4px 0 0; }
  .help-context-link { padding-left: 0; }
}

/* ==========================================================================
   P8 — THE COUNTER ON A PHONE
   --------------------------------------------------------------------------
   The POS layout was already mobile-first: the base rules are a single column
   and `@media (min-width: 720px)` is what widens it. What follows is the small
   set of things the phone case still needed — a reference lookup, touch sizes
   that survive a thumb, and a receipt that prints without the shop around it.
   ========================================================================== */

/* --- finding a sale by reference ---------------------------------------- */
.pos-lookup { display: flex; flex-direction: column; gap: 6px; }
.pos-lookup > label { font-size: .85rem; font-weight: 600; color: var(--muted); }
.pos-lookup-row { display: flex; gap: 8px; }
.pos-lookup-row input {
  flex: 1 1 auto; min-width: 0; min-height: 44px; padding: 0 12px;
  font-size: 1rem; font-family: inherit;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--bg); color: var(--ink);
}
.pos-lookup-row input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.pos-lookup-row button { flex: 0 0 auto; min-height: 44px; }
.pos-lookup-hint { margin: 0; font-size: .8rem; color: var(--muted); }

/* --- touch targets ------------------------------------------------------
   Anything a thumb has to hit at the counter gets a real box. 44px is the
   smallest target that is reliably hittable while holding something in the
   other hand, which is the actual posture this is used in. */
.pos-step { min-width: 44px; min-height: 44px; }
.pos-done-actions .btn-primary,
.pos-done-actions .btn-outline { min-height: 44px; }

/* Nothing in the POS may force the page sideways. A long product name wraps;
   it never widens the till. */
.pos-shell, .pos-line, .pos-cart, .pos-receipt { max-width: 100%; }
/* `.pos-line-name` USED TO BE IN THIS RULE TOO, and that is what the Product
   Owner saw: the sale panel declared `break-word` where the name is styled and
   `anywhere` again 450 lines further down, so the later rule won and "Test
   Bracelet" broke as Test / Bracele / t. One property, one owner — the name's
   wrapping is decided beside the rest of its styling and nowhere else.
   A lookup reference keeps `anywhere`: it is a single unbroken token with no
   word boundary to wrap at, which is the case the value is actually for. */
.pos-lookup-hint { overflow-wrap: anywhere; }

/* On the narrowest phones the action row stops being a column of full-width
   buttons and becomes a wrap, so New sale / PDF / Share / Print stay on screen
   together instead of pushing the receipt off the top. */
.pos-done-actions { flex-direction: row; flex-wrap: wrap; max-width: none; }
.pos-done-actions > * { flex: 1 1 auto; min-width: 44%; }
@media (min-width: 480px) {
  .pos-done-actions > * { min-width: 0; flex: 0 1 auto; }
}

/* --- printing the receipt -----------------------------------------------
   SHOULD, and small: the browser already knows how to print. All that is
   needed is to remove the shop around the receipt, because what a customer
   should get is the slip, not the owner tooling that produced it.

   This is not a printer integration. There is no thermal driver, no paper
   size assumption and no SDK — a phone printing to whatever it can reach. */
@media print {
  .pos-shell > .pos-top,
  .pos-shell > .pos-done-actions,
  .pos-lookup,
  .pos-notice,
  /* STAFF-ONLY OPERATIONAL CONTENT IS NOT RECEIPT CONTENT.
     Human Acceptance found "You do not have permission to void a sale."
     printed on a customer's copy. It is exactly right on the operator's
     screen — it tells the cashier why there is no Void button — and it is
     nothing to do with what was bought. The message and the authorization
     behind it are untouched: lib/pos-void.js still refuses an ORDER STAFF
     void with the same 403 and the same words, and the screen still shows
     them. Only the printed page stops carrying them.

     The VOIDED banner deliberately stays printable: a reversed sale that
     prints as a live one is a receipt that lies. */
  .pos-detail-blocked,
  .pos-void-open,
  /* The three receipt actions are the thing that CAUSED the print. They are
     not receipt content and must not appear on it. */
  .pos-receipt-actions,
  .pos-primary-action,
  .pos-quiet-action,
  .no-print { display: none !important; }

  .pos-done, .pos-shell { display: block !important; }
  .pos-done-mark, .pos-done-ref { display: none !important; }

  /* ------------------------------------------------------------------
     A RECEIPT ON A SHEET OF PAPER

     This printed at 320px hard against the top-left corner, which on A4 is a
     narrow strip in one corner of a mostly empty page — the waste NOTE-019
     names. It is now a receipt-width column, centred, with a margin the
     printer can actually reach, so what comes out looks like something the
     shop meant to produce.

     WIDTH IS IN MILLIMETRES BECAUSE PAPER IS. 80mm is the receipt width the
     PDF already uses and the width a thermal roll takes, so the same slip is
     recognisably the same slip whichever way it was produced — and the day a
     roll printer is plugged in, `@page` is the only thing that changes.

     `page-break-inside: avoid` keeps a short receipt whole rather than
     letting a line of it fall onto a second sheet. The browser draws its own
     header and footer and no stylesheet can remove them; nothing here
     pretends otherwise. */
  @page { margin: 12mm; }
  .owner-main, .pos-main { padding: 0 !important; margin: 0 !important; }
  .pos-receipt {
    border: none !important; box-shadow: none !important; background: none !important;
    margin: 0 auto !important; padding: 0 !important;
    width: 80mm; max-width: 100%;
    font-size: 10.5pt; line-height: 1.45; color: #000;
    page-break-inside: avoid;
  }
  .pos-receipt h2 { font-size: 14pt; }
  .pos-receipt-lines { border-color: #000 !important; }
  .pos-receipt-disclosure { border-top-color: #666 !important; color: #000; }
  /* Operator context is not receipt content: who sold it, and the staff-only
     explanation of why there is no Void button, both stay on the screen. */
  .pos-detail-meta { display: none !important; }
}

/* ==========================================================================
   P8 — HOW MANY OF THIS ARE ALREADY IN THE SALE
   --------------------------------------------------------------------------
   The card's stepper occupies the same slot its Add button did, so a card does
   not change size when something is added to it — a grid that reflows every
   time the operator taps is a grid they lose their place in.
   ========================================================================== */
.pos-card-qty {
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
  width: 100%; min-height: 44px;
  border: 1px solid var(--accent); border-radius: 10px;
  padding: 0 4px; background: var(--bg);
}
.pos-card-qty .pos-step { flex: 0 0 auto; border: none; background: none; }
.pos-card-count {
  flex: 1 1 auto; text-align: center;
  font-weight: 700; font-size: 1rem; font-variant-numeric: tabular-nums;
  color: var(--ink);
}
/* THE COUNTERS AN OPERATOR MAY ACTUALLY OPEN, offered beside a refusal.
   A dead end is the wrong answer for somebody standing at a till with a
   customer waiting, so the refusal names the market and the next tap. */
.pos-offers { display: flex; flex-direction: column; gap: 10px; margin: 14px 0; max-width: 420px; }
.pos-offers .pos-offer { min-height: 48px; display: inline-flex; align-items: center;
  justify-content: center; text-align: center; }

/* The receipt actions on an older sale sit where the void control does, and
   must not push it off a narrow screen. */
.pos-detail-actions { margin-top: 4px; }

/* ==========================================================================
   P023 — THE RECEIPT, REACHABLE FROM THE SALE ITSELF
   --------------------------------------------------------------------------
   The strip sits directly under the reference and the status pills, above every
   administrative panel. That placement IS the fix: the actions existed and the
   operator could not find them, because they were on the till and the sale was
   opened from Orders.

   It wraps rather than scrolls. A counter operator is holding a phone, and a
   row of controls that runs off the side of a 390px screen is a row of controls
   that does not exist.
   ========================================================================== */
.receipt-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 0 0 16px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--card);
}
.receipt-strip-facts {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px;
}
.receipt-strip-label { color: var(--muted); font-size: .9rem; }
.receipt-strip-total { font-weight: 600; font-variant-numeric: tabular-nums; }

/* A reversed sale is MARKED, never hidden. The sale happened and the customer
   may still be holding their copy. */
.receipt-strip-void {
  padding: 2px 8px;
  border-radius: 999px;
  background: #fdecec;
  color: #a11;
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .06em;
}

.receipt-strip-actions { display: flex; flex-wrap: wrap; gap: 8px; }
/* A thumb, not a mouse pointer. 44px is the smallest target that is reliably
   hittable on a phone held in one hand at a counter. */
.receipt-strip-actions .btn-outline {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* The slip itself is built on load and kept out of the way until somebody
   prints. `hidden` is not used here: the element must stay laid out for the
   print stylesheet to reveal it. */
.receipt-print-only { display: none; }

.pos-receipt-void {
  margin: 0 0 6px;
  text-align: center;
  font-weight: 700;
  letter-spacing: .12em;
  color: #a11;
}

/* --- printing a receipt from the ORDER page ------------------------------
   Same intent as the till's rules, and the same class names inside the slip,
   so the printed output is the receipt and not the owner tooling around it. */
@media print {
  #detail > .owner-detail-head,
  #detail > .owner-detail-grid,
  /* Order Detail is now sections rather than a two-column grid (Completion-04
     §2). Both are named because the grid is still how other owner detail pages
     are built, and a print rule that quietly stops matching is how a receipt
     starts printing four screens of administration behind it. */
  #detail > .od-acc,
  #detail > .od-acc-controls,
  #detail > .co-banner,
  #detail > .pos-void-desk,
  .receipt-strip { display: none !important; }

  .receipt-print-only { display: block !important; }
  .receipt-print-only .pos-receipt {
    border: none !important; box-shadow: none !important;
    margin: 0 !important; padding: 0 !important;
    max-width: 320px; font-size: 11pt; color: #000;
  }
  .receipt-print-only .pos-receipt h2 { font-size: 14pt; }
}

/* --- the staff shortcut into the counter ---------------------------------
   Deliberately the most prominent thing in the shop header for the person who
   can see it, because it is the one control that operator presses all day. It
   is drawn only for a signed-in user who may sell at the market on screen; a
   shopper's header is exactly what it always was. */
.staff-cash-sale {
  min-height: 44px;
  padding: 0 14px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border-radius: 999px;
  background: var(--accent, #1f7a4d);
  color: #fff;
  font-weight: 600;
  white-space: nowrap;
  text-decoration: none;
}
.staff-cash-sale:hover { filter: brightness(1.06); }

/* ==========================================================================
   P026 — A NEW ORDER HAS ARRIVED
   --------------------------------------------------------------------------
   Marmocha sends no notifications, so this banner is the only thing that tells
   a shop an online order exists. It is therefore allowed to be the loudest
   element on the page — and it is a button, because noticing is not the job:
   opening the order is.

   Full width and thumb-height, because the person who needs it is holding a
   phone at a counter with a customer in front of them.
   ========================================================================== */
.new-orders-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  min-height: 48px;
  margin: 0 0 14px;
  padding: 12px 16px;
  border: 1px solid var(--accent-dark, #98502e);
  border-radius: 12px;
  background: var(--accent, #b5643c);
  color: #fff;
  font-size: 1rem;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}
.new-orders-banner:hover { filter: brightness(1.06); }
.new-orders-cta {
  flex: none;
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .18);
  font-size: .85rem;
  font-weight: 700;
}

/* THE LINE THAT MAKES `hidden` MEAN SOMETHING.

   `.new-orders-banner { display: flex }` is an author rule, and author rules
   beat the browser's own `[hidden] { display: none }` whatever their
   specificity — so without this the banner is painted permanently, announcing
   a new order that never came, for ever.

   That is not a hypothetical: it is the Sidebar V2 defect this project already
   bought once, where every group reported itself closed and stayed fully on
   screen. It happened again here, in a new component, three sections down the
   same stylesheet. The suite caught it only because the assertion measures
   whether the element has a box rather than whether the attribute is set. */
.new-orders-banner[hidden] { display: none !important; }

/* ==========================================================================
   P028 — WHAT PAYPAL WILL ACTUALLY CHARGE
   --------------------------------------------------------------------------
   Sits directly above the PayPal button, because a customer discovering inside
   PayPal that the amount is in another currency has already committed. It is
   deliberately plain rather than a warning colour: nothing is wrong, and a red
   box would make a normal fact look like a problem.
   ========================================================================== */
.pay-conversion {
  margin: 14px 0;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--card);
}
.pay-conversion-rows .kv { margin: 0 0 6px; }
.pay-conversion-rows .kv:last-child { margin-bottom: 0; }
.pay-conversion-rows strong { font-variant-numeric: tabular-nums; }
.pay-conversion-note {
  margin: 12px 0 0;
  padding-top: 10px;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: .9rem;
  line-height: 1.5;
}

/* ==========================================================================
   P035-C7 — THE GLOBAL HEADER CONTROLS: LANGUAGE, AND THE WAY IN AND OUT
   --------------------------------------------------------------------------
   Two small controls that sit in whichever header the page has. They are
   deliberately quiet: they must be findable without competing with the shop.
   ========================================================================== */

/* ---- LANGUAGE ------------------------------------------------------------
   Each option is written in ITS OWN language, so a reader looking for theirs
   can find it without being able to read the other one. */
.lang-switch {
  display: inline-flex; align-items: center; gap: 2px;
  border: 1px solid var(--line); border-radius: 999px;
  padding: 2px; background: #fff; flex: 0 0 auto;
}
.lang-opt {
  border: 0; background: transparent; cursor: pointer; color: var(--muted);
  font: inherit; font-size: .82rem; line-height: 1;
  /* 44px is the project's touch standard (P8). The padding gets it there
     without making the control look like a button bar. */
  min-height: 34px; padding: 0 10px; border-radius: 999px;
}
.lang-opt:hover { color: var(--ink); }
/* THE CURRENT LANGUAGE IS NOT SHOWN BY COLOUR ALONE. Weight and a solid
   background carry it too, so it survives a monochrome screen and a reader
   who does not distinguish these two colours. */
.lang-opt.is-on { color: var(--ink); font-weight: 700; background: #f4e9dd; }
.lang-opt:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.lang-sep { color: var(--line); font-size: .8rem; }

/* ONE CONTROL, AND A REAL TOUCH TARGET (P035 Batch 2).
   The switcher names the language it switches TO, so there is one word rather
   than two and nothing to wrap. That is what lets it be a proper 44px target
   inside the header instead of two 34px pills sharing the space. */
.lang-switch > .lang-opt:only-child {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 40px; padding: 0 12px; color: var(--ink); white-space: nowrap;
}
.lang-globe { display: inline-flex; flex: 0 0 auto; opacity: .75; }

/* ==========================================================================
   THE SHARED FILE CHOOSER  (P035 Batch 2)
   --------------------------------------------------------------------------
   The native control is hidden from SIGHT and from the tab order, because the
   button beside it is the thing a person reaches for and two focus stops for
   one control is worse than none. display:none is deliberate: the input is
   driven by the button's click, never by the keyboard landing on it.
   ========================================================================== */
/* ==========================================================================
   MONEY TYPED ON A PRODUCT ROW  (P035 Batch 3, B3-10)
   --------------------------------------------------------------------------
   The currency is a label, not part of the value: it is read from the store
   and never typed, so it cannot be edited into something the market does not
   sell in. The box is numeric and stays LTR in both languages, because a
   price is digits.
   ========================================================================== */
/* THE BOX GIVES WAY BEFORE THE COLUMN DOES. A fixed 6.5rem input plus the
   currency label needed more than the track could spare, so the cell
   overflowed rather than the box shrinking — which is the same min-width:auto
   trap the header switcher hit at P035-C9A. */
.prod-money { display: flex; align-items: center; gap: 6px; min-width: 0; width: 100%; }
.prod-money-cur { font-size: .74rem; color: var(--muted); flex: 0 0 auto; }
.prod-money-input {
  width: 100%; min-width: 0; max-width: 7rem; min-height: 40px; padding: 4px 8px;
  border: 1px solid var(--line); border-radius: 8px;
  font: inherit; font-variant-numeric: tabular-nums; text-align: end;
}
.prod-money-input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.prod-unpriced-flag {
  display: block; margin-top: 2px; font-size: .72rem; color: var(--danger, #a13228);
}
/* The cost sits under the price, quieter, because it is the shop's own figure
   and never the customer's. */
.prod-price { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; min-width: 0; }
.prod-cost { display: flex; align-items: center; gap: 6px; min-width: 0; }
.prod-cost-k { font-size: .68rem; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.prod-money-sm { max-width: 5.8rem; min-height: 34px; font-size: .85rem; }

/* ==========================================================================
   WHAT AN ORDER NEEDS NOW  (P035 Batch 3 — B3-03, B3-06)
   --------------------------------------------------------------------------
   Three lines in a fixed order, so a manager scanning a column reads the same
   thing in the same place on every row: the method, where it has got to, and
   what happens next. The next step is the emphasised one — it is the only
   line that tells somebody to do something.
   ========================================================================== */
.or-work { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.or-work-method { font-size: .7rem; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); }
.or-work-state { font-size: .9rem; font-weight: 600; overflow-wrap: anywhere; }
.or-work-state.is-done { color: var(--muted); font-weight: 500; }
.or-work-next { font-size: .82rem; color: var(--accent-dark, var(--ink)); overflow-wrap: anywhere; }
.or-work-where { font-size: .75rem; color: var(--muted); overflow-wrap: anywhere; }
.or-work-note { font-size: .72rem; color: var(--muted); margin-top: 2px; }

/* The work queue row says where it has got to, where it is going, whether it
   is paid for and how long it has been waiting — without opening the order. */
.fq-state { font-size: .85rem; font-weight: 600; margin-top: 2px; overflow-wrap: anywhere; }
.fq-where, .fq-age { font-size: .74rem; color: var(--muted); margin-top: 2px; overflow-wrap: anywhere; }
.fq-pay { font-size: .74rem; color: var(--danger, #a13228); margin-top: 2px; }
.fq-pay.is-paid { color: var(--muted); }

.fp-native { display: none; }
.fp { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 4px; }
.fp-btn {
  min-height: 44px; padding: 0 16px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--card, #fff); color: var(--ink);
  font: inherit; font-size: .92rem; cursor: pointer; white-space: nowrap;
}
.fp-btn:hover { border-color: var(--border-strong, var(--accent)); }
.fp-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* The chosen file's name is the reader's own text and may be Arabic or a
   Latin filename, so it is direction-neutral and wraps rather than pushing
   the row sideways on a phone. */
.fp-name { font-size: .88rem; color: var(--ink); min-width: 0; overflow-wrap: anywhere; }
.fp-name.fp-empty { color: var(--muted); }

/* ==========================================================================
   THE PRODUCT EDITOR AS AN ACCORDION  (P035 Batch 2)
   --------------------------------------------------------------------------
   It reuses Store Management's .acc-* entirely — the item, the header button,
   the number, the icon, the marker and the body all come from there, so the
   two owner surfaces are one design rather than two that resemble each other.
   What is added here is only what a FORM needs that a configuration panel did
   not: a completion summary in the header, and an action area that cannot be
   folded away.
   ========================================================================== */
.pe-acc { max-width: 900px; }
.pe-acc-controls { max-width: 900px; }

/* The summary sits between the title and the marker, takes the space that is
   left, and gives way first: a long product name must never push the open /
   closed marker off a 390px screen. */
.acc-sum {
  flex: 0 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: .82rem; font-weight: 400; color: var(--muted);
}
.acc-sum.done { color: var(--ink); }

/* THE ACTION AREA. On a phone it stays on screen, because the alternative is
   what the Product Owner reported: expanding everything and scrolling to the
   bottom to find Create product. There is exactly one button in it — a second
   one for mobile is how a form gets submitted twice. */
.pe-actions {
  max-width: 900px; margin-top: 16px;
  display: flex; flex-direction: column; gap: 8px;
}
.pe-actions .pe-save { width: 100%; min-height: 52px; font-size: 1.02rem; }

@media (max-width: 759px) {
  /* ROOM FOR THE BAR, AND EXACTLY AS MUCH AS THE BAR ACTUALLY TAKES.

     This reserved a flat 104px for a bar that measured 155px, so 51px of the
     form sat underneath it permanently — which is why Expand and Collapse
     were reported as clipped: on a 664px phone viewport they were simply
     behind it. A guessed number cannot stay right while the bar's contents
     change, so the page now measures its own bar and sets --pe-bar-h; this
     value is the fallback for the first paint and for anything that runs
     without script. */
  .pe-acc { padding-bottom: 4px; }
  .pe-main { padding-bottom: calc(var(--pe-bar-h, 72px) + 12px); }
  .pe-actions {
    position: fixed; inset-inline: 0; bottom: 0; z-index: 60;
    margin: 0; padding: 10px 12px calc(10px + env(safe-area-inset-bottom, 0px));
    background: var(--card, #fff); border-top: 1px solid var(--line);
    box-shadow: 0 -6px 20px rgba(0, 0, 0, .10);
  }
  .acc-sum { font-size: .78rem; }
}

/* ==========================================================================
   THE PHONE BELONGS TO THE PRODUCT FORM  (P035 Batch 2 — HAT remediation)
   --------------------------------------------------------------------------
   Human Acceptance on a real phone found the editor working and unusable at
   the same time, and the measurement was worse than the impression. At
   390x844, before this block:

       owner header                         349px
       page title + scope note              199px
       Expand / Collapse row                 37px
       ---------------------------------------------
       chrome above the first field         646px   (77% of the screen)
       fixed action bar                     155px   (18%)
       LEFT FOR TYPING A PRODUCT             43px   (5%)

   And on a real phone, whose viewport is shorter than 844 once the browser's
   own chrome is taken, it was 0%: the action bar covered the Expand/Collapse
   row outright, which is the "clipping" the screenshot showed.

   NOTHING IS DELETED AND NO CAPABILITY MOVES. This is density and hierarchy:
   labels whose value is obvious from what follows them, a store named twice
   in three places, navigation that the sidebar already carries, and an action
   bar padded for a desktop. Every control is still reachable, every touch
   target is still a touch target, and nothing here changes what the page can
   do — at 760px and above not one rule below applies.
   ========================================================================== */
@media (max-width: 759px) {

  /* ---- the header ------------------------------------------------------ */
  .owner-header-inner { padding: 8px 12px; gap: 8px 10px; }
  .owner-brand { font-size: .95rem; gap: 8px; }
  /* "Marmocha Product" — the page says what it is in its own title. */
  .owner-brand-sub { display: none; }

  /* THE STORE IS NAMED ONCE, AS A ROW, NOT AS A LABELLED CARD.
     "MANAGING STORE / Jordan Store / INVENTORY LOCATION / Jordan Kiosk" is
     four lines saying two things. The names carry it; the labels were what
     made the block 63px tall. */
  .store-context {
    padding: 3px 10px; gap: 6px; font-size: .78rem;
    flex-wrap: nowrap; overflow: hidden;
  }
  .store-context .store-context-label { display: none; }
  .store-context-store, .store-context-loc {
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
  }
  .store-context-loc::before { content: "·"; margin-inline-end: 6px; color: var(--muted); }

  /* ---- the environment badge ------------------------------------------
     It stays visible, and stays amber, because knowing you are on sandbox
     money matters. It simply stops being a headline: the word PayPal is the
     part a person already knows. */
  .sandbox-tag { font-size: .62rem; padding: 1px 7px; letter-spacing: .03em; }

  /* ---- what is on the right -------------------------------------------- */
  .owner-header-right { gap: 8px; row-gap: 6px; }
  /* The role-aware links are the SAME destinations the sidebar already
     lists, and the sidebar is one tap away. A permanent second navigation
     above every product field is the thing this remediation removes. */
  .owner-header-right .owner-nav { display: none; }
  /* "Signed in as" is a label for a name that is obviously a name. The name
     itself stays, and the account is also in the menu. */
  .owner-user { font-size: .72rem; }
  .owner-user [data-i18n="auth.signedInAs"] { display: none; }
  .owner-btn-sm { padding: 6px 10px; font-size: .78rem; }

  /* ---- the page's own heading ------------------------------------------ */
  /* LONGHANDS, NOT THE SHORTHAND. "padding: 12px 12px 0" here silently reset
     the bottom padding that reserves room for the fixed bar a few rules
     above — putting the foot of the form back underneath it, which is the
     exact defect this whole remediation exists to remove. The regression
     suite compares the reserved space against the bar its own height, so a
     cascade mistake like that one cannot pass again. */
  .pe-main { padding-top: 12px; padding-inline: 12px; }
  .pe-main .owner-detail-head { margin: 0 0 8px; gap: 4px; }
  .pe-main .owner-detail-head h1 { font-size: 1.15rem; margin: 0; }
  .pe-main .owner-detail-sub { font-size: .78rem; }
  /* The header already says which store this is, twice over. */
  .pe-main .owner-detail-sub[data-owner-store] { display: none; }

  /* The scope heading keeps its name and loses its paragraph: that sentence
     explains a rule that does not change while somebody types, and it cost
     99px of a 664px screen.

     EXCEPT WHEN IT IS CARRYING A REFUSAL. applyEditPermission() writes
     "Read-only for your role" into that same .scope-note and marks the
     heading .locked, so hiding it unconditionally would have told a viewer
     with no edit rights nothing at all about why the fields will not take
     their typing. The :not(.locked) is the whole difference between removing
     an explanation and removing a warning. */
  .pe-main .scope-heading { padding: 4px 0; margin: 0 0 6px; font-size: .74rem; }
  .pe-main .scope-heading:not(.locked) .scope-note { display: none; }

  /* The account name is in the menu, where the account lives. Keeping it in
     the header as well made the right-hand block wrap to a third row. */
  .owner-header-right .owner-user { display: none; }

  /* ---- Expand / Collapse ------------------------------------------------ */
  .pe-acc-controls { margin: 0 0 8px; gap: 16px; }
  .pe-acc-controls .link-btn { min-height: 40px; display: inline-flex; align-items: center; }

  /* ---- the action bar --------------------------------------------------
     One action, sized for a thumb, and nothing else competing with it. The
     draft note and Clear what I have typed moved into the page, below the
     last section — still there, no longer spending permanent screen, and no
     longer a neighbour of Create product where a thumb could find it by
     accident. */
  .pe-actions { padding: 8px 12px calc(8px + env(safe-area-inset-bottom, 0px)); gap: 6px; }
  .pe-actions .pe-save { min-height: 48px; font-size: 1rem; }
  .pe-actions #save-msg:empty { display: none; }

  /* Where the draft controls went. */
  .pe-draft-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; flex-wrap: wrap; margin: 14px 0 4px;
  }
  .pe-draft-row .pe-draft { margin: 0; font-size: .78rem; }
  .pe-draft-row .pe-draft-discard { min-height: 40px; }
}

/* The draft row is in the flow on every width; only its compact phone layout
   is above. On a desktop it sits under the accordion beside the action. */
.pe-draft-row { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin: 16px 0 0; }
.pe-draft-row:empty { display: none; }


/* On a wide screen the accordion must not become one narrow column of air.
   The sections keep a readable measure and the page does not stretch them
   across 1366px of whitespace; the action area sits under them in flow. */
@media (min-width: 1100px) {
  .pe-acc, .pe-acc-controls, .pe-actions { max-width: 980px; }
  .pe-actions { flex-direction: row; align-items: center; flex-wrap: wrap; }
  .pe-actions .pe-save { width: auto; min-width: 220px; }
}


/* ---- SIGN IN / ACCOUNT / LOG OUT ---------------------------------------- */
.hdr-auth { display: inline-flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.hdr-auth-signin {
  display: inline-flex; align-items: center; min-height: 38px;
  padding: 0 14px; border-radius: 999px;
  border: 1px solid var(--accent); color: var(--ink);
  text-decoration: none; font-size: .86rem; font-weight: 600; white-space: nowrap;
}
.hdr-auth-signin:hover { background: #f4e9dd; }
.hdr-auth-who {
  display: inline-flex; flex-direction: column; line-height: 1.15;
  font-size: .78rem; color: var(--muted); max-width: 160px;
}
.hdr-auth-who strong { color: var(--ink); font-size: .84rem; overflow: hidden; text-overflow: ellipsis; }
.hdr-auth-role { font-size: .68rem; text-transform: uppercase; letter-spacing: .06em; }
.hdr-auth-out {
  border: 1px solid var(--line); background: #fff; color: var(--ink);
  border-radius: 999px; min-height: 38px; padding: 0 12px;
  font: inherit; font-size: .82rem; cursor: pointer; white-space: nowrap;
}
.hdr-auth-out:hover { border-color: var(--accent); }
.hdr-auth-out[disabled] { opacity: .6; cursor: default; }

/* The shop header is a wrapping flex row, so the two new controls simply
   join it. On a narrow screen they wrap onto their own line rather than
   squeezing the search box into nothing. */
@media (max-width: 560px) {
  .hdr-auth-who { max-width: 96px; }
  .lang-opt { padding: 0 8px; font-size: .78rem; }
}

/* ==========================================================================
   RIGHT TO LEFT
   --------------------------------------------------------------------------
   Most of this is already handled: the layout above uses LOGICAL properties
   (inset-inline-start, margin-inline-start, border-inline-end), which flip
   with dir on their own, and the browser's own bidi algorithm handles text.

   What remains here is the short list of things a logical property cannot
   express — a transform is always physical — plus the handful of places
   where a physical value was deliberate.
   ========================================================================== */

/* THE MOBILE DRAWER SLIDES IN FROM THE SIDE THE SIDEBAR IS ON. In Arabic
   that is the right, so it must leave to the right. translateX has no
   logical form, so this is a genuine override rather than an oversight. */
@media (max-width: 768px) {
  [dir="rtl"] #sidebar { transform: translateX(100%); }
  [dir="rtl"] body.sidebar-open #sidebar { transform: translateX(0); }
}

/* The chevron points INTO the tree, which is the other way round in Arabic. */
[dir="rtl"] .sb-chev svg { transform: scaleX(-1); }

/* The active marker on the icon rail is an inset shadow, which is physical. */
[dir="rtl"] .sb-rail-btn.has-active { box-shadow: inset -2px 0 0 var(--accent); }

/* NUMBERS, MONEY, REFERENCES AND CODES STAY LEFT TO RIGHT.
   A price, an order reference, a SKU, an email address and a URL are read
   the same way in both languages. Without this, Unicode rule W2 turns the
   digits after an Arabic word into an Arabic-context number and folds them
   into the right-to-left run — which is the defect P035-C4 fixed on the
   receipt, and it must not be reintroduced here.

   `unicode-bidi: isolate` keeps each one from disturbing the text around it.
   These class names are the ones the shop already uses for exactly these
   things; the rule follows them rather than inventing new markup. */
[dir="rtl"] .mono,
[dir="rtl"] .order-ref,
[dir="rtl"] .pos-receipt-qty,
[dir="rtl"] .pos-detail-qty,
[dir="rtl"] .hdr-auth-who strong,
[dir="rtl"] .sb-count {
  direction: ltr; unicode-bidi: isolate; text-align: start;
}

/* P035-C4/C5 marked every product name dir="ltr" so a mixed Arabic/Latin
   name keeps the order it is stored in. Isolating them means an RTL page
   cannot reorder them either — the accepted behaviour, preserved. */
[dir="rtl"] [dir="ltr"] { unicode-bidi: isolate; }

/* A TIMESTAMP IS ONE THING AND MUST BE PAINTED AS ONE THING.

   "13 Sept 2026, 9:34" is a run of digits, punctuation and letters, and the
   bidi algorithm is free to reorder the neutral parts of it against an
   Arabic paragraph — which is how the Product Owner came to read
   "Sept 2026, 9:34 13" on User Management. The value was never wrong.

   `isolate` settles the run's own direction internally and stops it
   exchanging characters with whatever sits beside it. `dir` is NOT forced,
   because an Arabic-formatted date is legitimately right-to-left and a
   English-formatted one is not — each decides for itself. */
.datetime,
.user-last,
.audit-when,
.o-when,
.pk-when { unicode-bidi: isolate; white-space: nowrap; }

/* ==========================================================================
   P035-C8 — PAGINATION, CASH SALE TOOLBAR, SALES REPORT
   ========================================================================== */

/* THE ELLIPSIS between skipped runs of page numbers. 373 perfumes at five a
   page is 75 pages, and 75 buttons is not navigation. */
.page-gap { color: var(--muted); padding: 0 4px; user-select: none; }

/* A THUMB, NOT A MOUSE. The Jordan counter is operated on a phone (P8), so the
   page buttons get a real target there rather than the compact desktop one. */
@media (max-width: 768px) {
  .page-num { min-height: 40px; min-width: 40px; padding: 6px 12px; }
  .page-num.page-step { min-width: auto; }
  .pager { gap: 10px; }
  .pager-left select { min-height: 40px; }
}

/* ==========================================================================
   CASH SALE — THE STICKY PRODUCT TOOLBAR
   --------------------------------------------------------------------------
   The operator scrolls a long catalogue. Searching meant scrolling back to the
   top and adding a missing product meant scrolling to the bottom, which for a
   counter with a customer waiting is the same as the feature not being there.

   ONE toolbar holding both, stuck to the top of the picking column. It is part
   of the column rather than floating over it, so it cannot cover a product
   card or the cart — a floating control would have to be positioned around
   content that changes length every time a filter moves.
   ========================================================================== */
.pos-toolbar {
  position: sticky; top: 0; z-index: 12;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 8px 0 10px;
  background: var(--bg);
  border-bottom: 1px solid var(--line);
  margin-bottom: 10px;
}
.pos-toolbar .pos-search { flex: 1 1 220px; min-width: 0; margin: 0; }
.pos-toolbar .pos-search input { width: 100%; }
.pos-toolbar .pos-addnew { flex: 0 0 auto; margin: 0; white-space: nowrap; min-height: 44px; }

/* On a phone the two controls stack, and the button stays full width so it is
   a real target. Kept short: a tall sticky bar eats the product list. */
@media (max-width: 560px) {
  .pos-toolbar { padding: 6px 0 8px; gap: 6px; }
  .pos-toolbar .pos-search { flex: 1 1 100%; }
  .pos-toolbar .pos-addnew { flex: 1 1 100%; }
}

/* ON THE COUNTER, THE STICKY THING IS THE TOOL, NOT THE CHROME.
   .owner-header is sticky at top: 0 with a higher z-index, so a toolbar
   also stuck at 0 slides underneath it — measured: the toolbar's own top
   left corner belonged to the header. The page already made the header
   static below 720px to buy back vertical space; the counter wants that at
   every width, because what an operator needs following them down a long
   catalogue is the search box, not the brand. */
.pos-body .owner-header { position: static; }

/* ==========================================================================
   SALES REPORT
   ========================================================================== */
/* ==========================================================================
   IMPORT AND GRID  (P035-C14, owner-catalog-import.html / owner-catalog-grid.html)
   A table may scroll sideways inside its own box; the page body never does.
   ========================================================================== */
.imp-step h2 { font-size: 1.05rem; margin: 0 0 8px; }
.imp-file-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; }
.imp-file { display: flex; flex-direction: column; gap: 4px; font-size: .9rem; max-width: 100%; }
.imp-file input[type="file"] { max-width: 100%; font: inherit; }
.imp-columns summary { cursor: pointer; font-weight: 600; margin: 6px 0; }
.imp-columns dl { display: grid; grid-template-columns: max-content 1fr; gap: 6px 14px; margin: 8px 0 0; }
.imp-columns dd { margin: 0; color: var(--muted); }
.imp-scroll, .grid-scroll { overflow-x: auto; max-width: 100%; border: 1px solid var(--line); border-radius: 10px; background: #fff; }
.imp-table, .grid-table { width: 100%; border-collapse: collapse; font-size: .88rem; }
.imp-table th, .imp-table td, .grid-table th, .grid-table td { padding: 7px 9px; border-bottom: 1px solid var(--line); text-align: start; vertical-align: top; }
.imp-table th, .grid-table th { font-size: .8rem; font-weight: 700; color: #4d463f; background: #faf7f3; white-space: nowrap; position: sticky; top: 0; }
.imp-table tr.has-errors td { background: #fdf3f2; }
.imp-table tr.has-warnings td { background: #fdf8ec; }
.imp-notes { margin: 0; padding-inline-start: 18px; }
.imp-error { color: #8f2a22; }
.imp-warning { color: #7a5208; }
.imp-ok { color: #1f5e39; font-weight: 600; }
.imp-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.grid-toolbar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 12px 0 8px; }
.grid-toolbar input[type="search"] { flex: 1 1 240px; min-width: 0; padding: 9px 12px; border: 1px solid #d6cbbf; border-radius: 10px; font: inherit; }
.grid-toolbar select { padding: 8px 10px; border: 1px solid #d6cbbf; border-radius: 8px; font: inherit; min-height: 40px; max-width: 100%; background: #fff; }
.grid-table input, .grid-table select { width: 100%; min-width: 120px; padding: 6px 8px; border: 1px solid #d6cbbf; border-radius: 6px; font: inherit; font-size: .88rem; background: #fff; }
.grid-table td.is-dirty input, .grid-table td.is-dirty select { background: #fff7e6; border-color: #c98a17; }
.grid-table td.is-invalid input, .grid-table td.is-invalid select { border: 2px solid #a13228; }
.grid-cell-note { display: block; margin-top: 3px; font-size: .76rem; color: #8f2a22; }
.grid-row.is-stale td { background: #fdf3f2; }
.grid-row.is-archived td { color: var(--muted); }
.grid-bar { position: sticky; bottom: 0; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; justify-content: space-between;
  margin-top: 12px; padding: 10px 12px; background: #fff; border: 1px solid var(--line); border-radius: 12px; box-shadow: 0 -4px 14px rgba(0,0,0,.06); }
.grid-bar-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.grid-review-list { margin: 8px 0 0; padding: 0; list-style: none; max-height: 45vh; overflow: auto; }
.grid-review-list li { padding: 6px 0; border-bottom: 1px solid var(--line); overflow-wrap: anywhere; }
@media (max-width: 520px) { .grid-toolbar select, .grid-toolbar input[type="search"] { flex: 1 1 100%; } .imp-columns dl { grid-template-columns: 1fr; } }

/* ==========================================================================
   ORDERS, MOBILE FIRST  (P035-C15)
   --------------------------------------------------------------------------
   Below 780px an order stops being a table row and becomes a card: the
   reference and the time lead, the customer follows, the money is the biggest
   thing on it, and the state and next action are pills that wrap. The column
   headings are hidden and each cell says what it is instead.
   ========================================================================== */
.of-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.of-collection { margin-top: 8px; }
.of-collection > summary { cursor: pointer; font-size: .88rem; font-weight: 600; padding: 6px 2px; }
.of-collection > summary::marker { color: var(--muted); }
.of-collection > .of-chips { margin-top: 6px; }

@media (max-width: 780px) {
  .order-list { background: transparent; border: none; border-radius: 0; overflow: visible; display: flex; flex-direction: column; gap: 10px; }
  .order-row.order-head { display: none; }
  a.order-row {
    display: grid; grid-template-columns: 1fr auto; gap: 6px 10px;
    background: #fff; border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px;
  }
  a.order-row.attention { border-inline-start: 4px solid #a13228; }
  .or-ref { grid-column: 1 / -1; }
  .or-ref strong { font-size: 1rem; }
  .or-customer { grid-column: 1 / -1; }
  .or-total { grid-column: 1 / -1; font-size: 1.15rem; }
  .or-total .or-pickup { justify-content: flex-start; margin-top: 6px; }
  .or-status { grid-column: 1 / -1; }
  .or-go { display: none; }
  .or-customer::before, .or-total::before {
    content: attr(data-label); display: block; font-size: .72rem; color: var(--muted); font-weight: 600;
  }
}

/* A reference that leads nowhere still offers the way back. */
.dead-end-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }

/* ==========================================================================
   RECENT SALES, MOBILE FIRST  (P035-C15)
   --------------------------------------------------------------------------
   One sale is one card, not a squeezed table row. Reference and state lead,
   the time sits beneath, the total is the largest figure, the method is quiet.
   Wide screens lay the cards out across the width rather than leaving it
   empty. Declared AFTER the original .pos-recent rules, so these win by order.
   ========================================================================== */
.pos-recent { display: grid; grid-template-columns: 1fr; gap: 10px; }
.pos-recent li {
  background: #fff; border: 1px solid var(--line); border-radius: 12px; padding: 0; overflow: hidden;
}
.pos-recent li.is-voided { opacity: 1; border-color: #e6c9c4; background: #fffaf9; }
.pos-recent-open {
  display: grid; width: 100%; gap: 2px 10px; padding: 12px 14px; min-height: 64px;
  grid-template-columns: 1fr auto auto; align-items: center;
  background: none; border: none; text-align: start; font: inherit; color: inherit; cursor: pointer;
}
.pos-recent-open:hover, .pos-recent-open:focus-visible { background: var(--bg); }
.pos-recent-ref { grid-column: 1; font-weight: 700; font-size: 1rem; overflow-wrap: anywhere; }
.pos-recent-open .pill { grid-column: 2; justify-self: end; }
.pos-recent-go { grid-column: 3; color: var(--muted); font-size: 1.2rem; }
.pos-recent-when { grid-column: 1 / -1; color: var(--muted); font-size: .84rem; }
.pos-recent-total {
  grid-column: 1; font-weight: 800; font-size: 1.2rem; font-variant-numeric: tabular-nums; text-align: start;
}
.pos-recent-pay { grid-column: 2 / -1; justify-self: end; color: var(--muted); font-size: .84rem; }
.pos-recent li.is-voided .pos-recent-total { text-decoration: line-through; }
@media (min-width: 760px) {
  .pos-recent { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
}

/* ==========================================================================
   FULFILMENT QUEUE, MOBILE FIRST  (P035-C15)
   --------------------------------------------------------------------------
   Below 780px a task is a card: the reference and the next step lead, the
   rest is labelled because the column headings are gone. Finished work is
   quieter than work still to do — the same information, less weight.
   ========================================================================== */
@media (max-width: 780px) {
  .fq-rows { gap: 10px; }
  .fq-row {
    grid-template-columns: 1fr auto; gap: 6px 10px;
    border-radius: 12px; padding: 12px 14px; align-items: start;
  }
  .fq-ref { grid-column: 1; font-size: 1rem; }
  .fq-next { grid-column: 2; grid-row: 1; justify-self: end; }
  .fq-method, .fq-who, .fq-when { grid-column: 1 / -1; white-space: normal; overflow: visible; }
  .fq-method::before, .fq-who::before, .fq-when::before {
    content: attr(data-label) " · "; color: var(--muted); font-size: .76rem; font-weight: 600;
  }
  .fq-when { display: block; }
}
.fq-done .fq-row { background: var(--bg); }
.fq-done .fq-ref { font-weight: 600; }

/* An empty list is a state to act on, not a shrug (P035-C15). */
.prod-empty { display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center; padding: 28px 16px; }
.prod-empty p { margin: 0; }
.prod-empty .btn-outline { min-height: 44px; padding-inline: 18px; }

/* ==========================================================================
   STORE PRICING, MOBILE FIRST  (P035-C15)
   --------------------------------------------------------------------------
   One product is one card. The price box is the largest control on it and is
   a real touch target; the state is a word, not a colour; the master figure is
   labelled as reference and never looks like a second price to charge. Wide
   screens lay the cards across the width instead of a thin table.
   ========================================================================== */
.pr-list { display: grid; grid-template-columns: 1fr; gap: 10px; }
.pr-card { background: #fff; border: 1px solid var(--line); border-radius: 12px; padding: 14px; display: flex; flex-direction: column; gap: 10px; }
.pr-card.pr-blocked { border-inline-start: 4px solid #c98a17; background: #fffdf9; }
.pr-card-head { display: flex; justify-content: space-between; gap: 10px; align-items: flex-start; flex-wrap: wrap; }
.pr-ident { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pr-name { font-size: 1rem; overflow-wrap: anywhere; }
.pr-card .pr-sku { font-size: .78rem; opacity: .7; font-family: ui-monospace, Menlo, Consolas, monospace; }
.pr-card-body { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; justify-content: space-between; }
.pr-price-field { display: flex; flex-direction: column; gap: 4px; flex: 1 1 12rem; }
.pr-price-label { font-size: .8rem; color: var(--muted); font-weight: 600; }
.pr-card .pr-input-wrap { display: inline-flex; align-items: center; gap: 8px; }
.pr-card .pr-cur { font-weight: 700; color: var(--muted); }
.pr-card .pr-input { width: 100%; max-width: 11rem; min-height: 46px; font-size: 1.1rem; padding: 6px 10px; }
.pr-card .pr-master { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; white-space: normal; text-align: end; }
.pr-card .pr-master-tag { font-size: .72rem; text-transform: none; color: var(--muted); }
.pr-card .pr-master-val { font-variant-numeric: tabular-nums; color: var(--muted); }
.pr-card-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.pr-card-actions .owner-btn-sm { min-height: 40px; padding-inline: 16px; }
@media (min-width: 860px) {
  .pr-list { grid-template-columns: repeat(auto-fill, minmax(380px, 1fr)); }
}

/* ==========================================================================
   COLLECTION POINTS, MOBILE FIRST  (P035-C15)
   --------------------------------------------------------------------------
   Four questions, four groups, in the order somebody answers them. One field
   per row on a phone; two only where both are genuinely short.
   ========================================================================== */
.pk-group { margin: 0 0 18px; }
.pk-group-title {
  font-size: .82rem; font-weight: 700; color: var(--muted); letter-spacing: .04em;
  margin: 0 0 8px; padding-bottom: 6px; border-bottom: 1px solid var(--line);
}
.pk-group-visibility .pk-active { margin: 0; }
.pk-fields { display: grid; grid-template-columns: 1fr; gap: 14px; }
.pk-field textarea.pk-input { min-height: 72px; }
.pk-input { min-height: 44px; }
@media (min-width: 720px) {
  .pk-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pk-field { grid-column: 1 / -1; }
  .pk-field-short { grid-column: span 1; }
}

/* ==========================================================================
   SALES REPORT, MOBILE FIRST  (P035-C15)
   --------------------------------------------------------------------------
   Below 780px each table row becomes a card and every cell says what it is,
   because the headings are gone. Not one figure changes: the same strings the
   server sent, in tabular numerals, isolated left-to-right.
   ========================================================================== */
@media (max-width: 780px) {
  .rep-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rep-filters { grid-template-columns: 1fr; }
  .rep-field select, .rep-field input { min-height: 44px; }
  .rep-scroll { overflow-x: visible; border: none; }
  .rep-table, .rep-table tbody, .rep-table tr, .rep-table td { display: block; width: 100%; }
  .rep-table thead { display: none; }
  .rep-table tr {
    background: #fff; border: 1px solid var(--line); border-radius: 12px;
    padding: 10px 12px; margin-bottom: 10px;
  }
  .rep-table td { border: none; padding: 4px 0; display: flex; justify-content: space-between; gap: 12px; align-items: baseline; }
  .rep-table td::before {
    content: attr(data-label); color: var(--muted); font-size: .78rem; font-weight: 600; flex: 0 0 auto;
  }
  .rep-table td.num { text-align: end; }
  .rep-table td:first-child { border-bottom: 1px solid var(--line); padding-bottom: 8px; margin-bottom: 4px; }
  .rep-table td:first-child::before { align-self: flex-start; }
}

/* ==========================================================================
   USER MANAGEMENT, MOBILE FIRST  (P035-C15)
   --------------------------------------------------------------------------
   Below 780px a user is a card. The name leads; every other cell says what it
   is, because the column headings are hidden. Actions stay thumb-sized.
   ========================================================================== */
@media (max-width: 780px) {
  .user-list { background: transparent; border: none; display: flex; flex-direction: column; gap: 10px; }
  .user-row.user-head { display: none; }
  .user-row {
    grid-template-columns: 1fr; gap: 6px;
    background: #fff; border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px;
  }
  .user-row.disabled-user { border-inline-start: 4px solid #cfc6bd; }
  .user-row > div[data-label] { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; }
  .user-row > div[data-label]::before {
    content: attr(data-label); color: var(--muted); font-size: .76rem; font-weight: 600;
  }
  .user-actions { justify-content: flex-start; margin-top: 4px; }
  .user-actions .owner-btn-sm { min-height: 40px; }
}

/* ==========================================================================
   PAYMENT METHODS, MOBILE FIRST  (P035-C15)
   --------------------------------------------------------------------------
   A method is a card: its name and master switch on one line, the two channels
   beneath, each a real touch target. Read-only stays obvious because the
   controls are visibly disabled, not merely inert.
   ========================================================================== */
@media (max-width: 780px) {
  .pay-method { padding: 12px 14px; }
  .pay-method-head { flex-wrap: wrap; gap: 8px; }
  .pay-channels { flex-direction: column; align-items: stretch; gap: 8px; }
  .pay-channels .cur-toggle { min-height: 44px; }
  .pay-method .cur-toggle input { width: 20px; height: 20px; }
}
.pay-impossible { opacity: .55; }

/* ==========================================================================
   NAVIGATION AND GENERAL QUALITY  (P035-C15)
   --------------------------------------------------------------------------
   Touch first: a menu row, a menu tool and a small owner button are all at
   least 40px on a phone. Appended deliberately — these rules win by order, so
   nothing above has to be rewritten.
   ========================================================================== */
.sb-toolbtn { min-height: 38px; }
.sb-group[data-depth="1"] { margin-bottom: 6px; }

@media (max-width: 768px) {
  .sb-tools { gap: 8px; flex-wrap: wrap; }
  .sb-toolbtn { min-height: 44px; flex: 1 1 auto; font-size: .9rem; }
  .sb-item, .sb-group-head { min-height: 44px; display: flex; align-items: center; }
  .sb-group-head[data-depth="1"] { font-size: 1.02rem; }
  .owner-btn-sm { min-height: 40px; }
  .owner-toolbar .owner-search { flex-wrap: wrap; gap: 8px; }
  .owner-toolbar .owner-search input[type="search"] { flex: 1 1 100%; min-height: 44px; }
}

/* An empty state is a sentence somebody reads, not a gap. */
.empty { padding: 22px 12px; }

/* ONE VISIBLE FOCUS RING, everywhere on the owner screens. A keyboard user has
   to be able to see where they are; several controls relied on the browser
   default, which a custom background can render nearly invisible. */
.owner-body a:focus-visible,
.owner-body button:focus-visible,
.owner-body input:focus-visible,
.owner-body select:focus-visible,
.owner-body textarea:focus-visible,
.owner-body summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 6px;
}

.pos-photo { display: flex; flex-direction: column; gap: 4px; }
.pos-photo input[type="file"] { max-width: 100%; font: inherit; font-size: .9rem; }
.pos-photo-hint, .pos-photo-name { font-size: .8rem; color: var(--muted); overflow-wrap: anywhere; }
.pos-photo-name { color: var(--ink); font-weight: 600; }

.rep-periods { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; margin-bottom: 12px; }
.rep-filters {
  display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end;
  padding: 12px 0; border-top: 1px solid var(--line); margin-top: 4px;
}
.rep-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.rep-field label { font-size: .78rem; color: var(--muted); }
.rep-field select, .rep-field input {
  padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px;
  font: inherit; font-size: .88rem; background: #fff; color: var(--ink); min-height: 40px;
}
.rep-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin: 16px 0; }
.rep-card { border: 1px solid var(--line); border-radius: 12px; padding: 14px; background: #fff; }
/* READABLE FIRST (P035-C14): a label a person can read at arm's length, in
   either script — capital letters do not exist in Arabic, and tiny muted
   capitals were the least readable text on the page in English. */
.rep-card .rep-label { font-size: .86rem; font-weight: 600; color: #4d463f; }
.rep-card .rep-value { font-size: 1.5rem; font-weight: 700; margin-top: 6px; font-variant-numeric: tabular-nums; }
.rep-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--line); margin: 18px 0 12px; flex-wrap: wrap; }
.rep-tab {
  border: 0; background: transparent; color: var(--muted); cursor: pointer;
  font: inherit; font-size: .92rem; padding: 10px 14px; min-height: 44px;
  border-bottom: 2px solid transparent;
}
.rep-tab:hover { color: var(--ink); }
.rep-tab.active { color: var(--ink); font-weight: 700; border-bottom-color: var(--accent); }
.rep-table { width: 100%; border-collapse: collapse; font-size: .9rem; }
.rep-table th, .rep-table td { padding: 9px 10px; border-bottom: 1px solid var(--line); text-align: start; }
.rep-table th { font-size: .82rem; font-weight: 700; color: #4d463f; background: #faf7f3; }
.rep-table td.num, .rep-table th.num { text-align: end; font-variant-numeric: tabular-nums; }
.rep-table tbody tr:nth-child(even) td { background: #fcfaf7; }
.rep-table tbody tr:hover td { background: #f6f0e8; }
.rep-scroll { overflow-x: auto; }
.rep-note {
  border: 1px solid var(--line); border-inline-start: 3px solid var(--accent);
  border-radius: 8px; padding: 10px 12px; background: #fff;
  font-size: .85rem; color: var(--muted); margin: 12px 0;
}

/* Money, quantities, references and dates read the same way in both
   languages — the rule P035-C4 established and P035-C7 generalised. */
.rep-table [dir="ltr"], .rep-card [dir="ltr"] { unicode-bidi: isolate; }

/* ==========================================================================
   P035-C9 — CHOOSING A MARKET
   --------------------------------------------------------------------------
   What a store-scoped page shows instead of guessing. It is a question, not
   an error: the person has not done anything wrong, the page simply cannot
   know which market it is for until they say.
   ========================================================================== */
.store-pick { max-width: 640px; }
.store-pick-list { display: flex; flex-direction: column; gap: 10px; margin-top: 14px; }
.store-pick-btn {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  text-align: start; padding: 14px 16px; min-height: 56px; width: 100%;
  border-radius: 12px; cursor: pointer;
}
.store-pick-btn strong { font-size: 1rem; }
@media (min-width: 560px) {
  .store-pick-list { flex-direction: row; flex-wrap: wrap; }
  .store-pick-btn { width: auto; min-width: 200px; flex: 0 1 auto; }
}

/* ==========================================================================
   P035-C9A — THE HEADER MUST BE ABLE TO SHRINK
   --------------------------------------------------------------------------
   THE COUNTER'S 21px OF SIDEWAYS SCROLL AT 390px WAS THIS, and it was mine:
   the language switcher added in P035-C7. Measured, not guessed —

       div.lang-switch        client=84  scroll=117
       div.owner-header-inner client=390 scroll=411
       header.owner-header    client=390 scroll=411
       page                                     411   = 390 + 21

   "English" and "العربية" side by side need 117px; the header could spare 84,
   and the content spilled rather than the box giving way. Two earlier attempts
   blamed the toolbar, the pager and the grid because they measured bounding
   RECTS — and a rect cannot show content overflowing a box that itself fits.
   scrollWidth versus clientWidth showed it in one pass.

   A flex item defaults to min-width:auto, which means "never narrower than my
   content". That is the whole bug: the switcher could not shrink and the page
   grew instead. min-width:0 lets it, and wrapping gives it somewhere to go, so
   nothing is hidden and nothing is clipped.
   ========================================================================== */
.owner-header-inner, .owner-header-right, .header-actions, .owner-brand { min-width: 0; }
/* WRAPPING IS NO LONGER NEEDED, AND WAS ITSELF THE VISIBLE DEFECT.

   Two pills that wrapped inside a 999px-radius container read as a bubble
   inside a bubble, pressed against Log out — which is what the Product Owner
   reported from a real phone. The switcher now holds ONE word, so it fits the
   84px the header can spare and has nothing to stack. min-width:0 stays,
   because a flex item that cannot shrink is what grew the page by 21px in the
   first place; only the wrap and the reordering go. */
.lang-switch { min-width: 0; flex-wrap: nowrap; }

@media (max-width: 430px) {
  .owner-header-right { row-gap: 6px; }
  .lang-switch > .lang-opt:only-child { padding: 0 10px; min-height: 38px; }
}


/* ==========================================================================
   STORE WORKSPACE  (P035-C6D)
   --------------------------------------------------------------------------
   MOBILE FIRST, and the navigation is deliberately a stack of rows rather
   than a tab bar: five tabs do not fit across 390px without either shrinking
   the text or scrolling sideways, and both are worse than a list you can
   read. The desktop rule below turns the same rows into a column beside the
   content — the same markup, used the way each width can afford.
   ========================================================================== */
.ws-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 4px 0 14px; }
.ws-head .ws-ident { flex: 1 1 220px; min-width: 0; }
.ws-head h2 { margin: 0; font-size: 1.25rem; overflow-wrap: anywhere; }
.ws-head .so-meta { margin: 2px 0 0; }
.ws-back { flex: 0 0 auto; }

.ws-nav { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
.ws-tab { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; min-height: 44px; padding: 10px 14px; text-align: start;
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  font: inherit; color: inherit; cursor: pointer; }
.ws-tab:hover { border-color: var(--ink); }
.ws-tab.is-current { border-color: var(--ink); background: var(--tint, #f6f4f1); font-weight: 600; }
.ws-chev { opacity: .5; }
[dir="rtl"] .ws-chev { transform: scaleX(-1); }

.ws-section { min-width: 0; }
.ws-details { margin-top: 18px; border: 1px solid var(--line); border-radius: var(--radius); background: #fff; }
.ws-details > summary { padding: 12px 14px; cursor: pointer; min-height: 44px; display: flex; align-items: center; }
.ws-details[open] > summary { border-bottom: 1px solid var(--line); }
.ws-details > section { padding: 12px 14px; }
/* A CLOSED DISCLOSURE MUST ACTUALLY BE CLOSED.
   The browser hides a closed <details>'s non-summary children through its OWN
   stylesheet, and an AUTHOR rule beats the UA stylesheet whatever the
   specificity. .store-row is display:grid, so the rename list stayed fully
   painted — overflowing out of a 51px details box — while the disclosure
   reported itself closed. That is the same cascade conflict as the sidebar
   [hidden] line (CLAUDE.md §13), and this is the line that makes closed mean
   closed. */
.ws-details:not([open]) > *:not(summary) { display: none !important; }

/* Read mode: a method is a small card of facts, not a row of inputs. */
.fx-card { display: block; background: #fff; border: 1px solid var(--line);
  border-radius: var(--radius); padding: 14px; margin-bottom: 10px; }
.fx-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.fx-name { font-size: 1rem; }
.fx-state { font-size: .82rem; padding: 2px 10px; border-radius: 999px; border: 1px solid var(--line); }
.fx-state.on { border-color: var(--ok); color: var(--ok); }
.fx-state.off { opacity: .7; }
.fx-facts { display: flex; flex-wrap: wrap; gap: 8px 22px; margin: 10px 0 0; }
.fx-fact { min-width: 0; }
.fx-fact dt { font-size: .78rem; opacity: .7; margin: 0; }
.fx-fact dd { margin: 0; font-weight: 600; overflow-wrap: anywhere; }
.fx-actions { margin-top: 12px; }
.fx-edit-form { margin-top: 12px; padding-top: 12px; border-top: 1px dashed var(--line);
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
/* An author rule beats the browser's own [hidden] { display: none } whatever its
   specificity, so the line above would have made `hidden` inert and left every
   edit form on screen announcing itself closed. That exact cascade conflict
   shipped once already (CLAUDE.md §13) and is why this line exists. */
.fx-edit-form[hidden] { display: none; }
.fx-edit-form .fulfil-fee { display: flex; align-items: center; gap: 6px; }
.fx-edit-form .fulfil-fee-input { min-width: 6.5rem; }

/* Destinations: the default is stated once, the rows stay short. */
.dest-summary { margin-bottom: 10px; }
.dest-count { font-size: .85rem; opacity: .7; }
.dest-search { width: 100%; min-height: 44px; margin-bottom: 10px; }
.dest-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.dest-row .fulfil-dest-name { flex: 1 1 8rem; min-width: 0; overflow-wrap: anywhere; }
.dest-state { font-size: .78rem; opacity: .75; }
.dest-exception { font-size: .78rem; padding: 1px 8px; border-radius: 999px;
  border: 1px solid #c98a17; color: #8a5f0c; }
.px-empty { padding: 12px 0; }
.so-manage { margin-top: 4px; }
.so-manage-btn { width: 100%; min-height: 44px; }
.so-more > summary { cursor: pointer; font-size: .88rem; opacity: .8; min-height: 44px; display: flex; align-items: center; }

@media (min-width: 900px) {
  /* The same rows become a column beside the content — space used, not
     stretched. */
  #workspace-view { display: grid; grid-template-columns: 220px minmax(0, 1fr);
    grid-template-areas: "head head" "nav body"; gap: 0 24px; align-items: start; }
  #ws-head { grid-area: head; }
  #ws-nav { grid-area: nav; position: sticky; top: 12px; margin-bottom: 0; }
  #ws-body { grid-area: body; min-width: 0; }
  .so-manage-btn { width: auto; }
}


/* ==========================================================================
   STORE TABS + ACCORDION  (P035-C6D2)
   --------------------------------------------------------------------------
   One mental model at every width: pick a store at the top, open the sections
   you need. The tabs wrap rather than scroll sideways, because a tab a person
   cannot see is a tab they will not press.
   ========================================================================== */
.st-tabs { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 14px; }
.st-tab { display: inline-flex; align-items: center; gap: 8px; min-height: 44px;
  padding: 8px 14px; background: #fff; border: 1px solid var(--line);
  border-radius: 999px; font: inherit; color: inherit; cursor: pointer; max-width: 100%; }
.st-tab:hover { border-color: var(--ink); }
.st-tab.is-current { border-color: var(--ink); border-width: 2px; background: var(--tint, #f6f4f1); font-weight: 600; }
.st-tab-name { overflow-wrap: anywhere; }
.st-tab-state { font-size: .78rem; opacity: .7; }
.st-tab-mark.is-ready { color: var(--ok); }
.st-tab-mark.is-attention { color: #c98a17; }
.st-tab-mark.is-not_ready { color: #a13228; }

.st-head { margin: 0 0 10px; }
.st-head-top { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.st-head h2 { margin: 0; font-size: 1.2rem; overflow-wrap: anywhere; }
.st-head .so-meta { margin: 2px 0 0; }

.st-acc-controls { display: flex; gap: 14px; margin: 0 0 10px; }
.link-btn { background: none; border: 0; padding: 6px 0; font: inherit; color: inherit;
  text-decoration: underline; cursor: pointer; opacity: .75; min-height: 36px; }
.link-btn:hover { opacity: 1; }

.st-acc { display: flex; flex-direction: column; gap: 8px; }
.acc-item { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.acc-h { margin: 0; }
.acc-btn { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 48px;
  padding: 12px 14px; background: none; border: 0; font: inherit; color: inherit;
  text-align: start; cursor: pointer; }
.acc-btn:hover { background: var(--tint, #f6f4f1); }
.acc-btn[aria-expanded="true"] { font-weight: 600; border-bottom: 1px solid var(--line); }
.acc-title { flex: 1 1 auto; min-width: 0; }
.acc-mark { opacity: .6; }
.acc-body { padding: 14px; }
/* A closed section has no content at all, so this is belt and braces rather
   than the mechanism — but an author rule beats the browser's [hidden], and
   this page has paid for that lesson twice (CLAUDE.md §13). */
.acc-body[hidden] { display: none !important; }

/* ORDER DETAIL AND CHECKOUT (P035 Completion-04 §2, §4). Both read as one
   column of sections rather than two columns of open cards, so the thing an
   operator came to do is the same distance from the top on a phone as on a
   laptop. The width is bounded because a 48px header button stretched across
   a 27-inch monitor is a worse target than a narrow one: the eye has to
   travel to find the marker it is aiming at. */
.od-acc, .ck-acc { display: flex; flex-direction: column; gap: 10px; max-width: 900px; }
.od-acc-controls, .ck-acc-controls { display: flex; gap: 14px; justify-content: flex-end;
  max-width: 900px; margin: 0 0 8px; }

/* The carrier and the tracking number are two facts, not one sentence. */
.track-carrier { display: flex; flex-wrap: wrap; gap: 4px 12px; align-items: baseline; }
.track-carrier-name, .track-carrier-ref { white-space: nowrap; }

/* Overview: the numbers first. */
.kpi-row { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 14px; }
.kpi { flex: 1 1 88px; min-width: 88px; padding: 10px 12px; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--tint, #f8f7f5); }
.kpi-n { display: block; font-size: 1.35rem; font-weight: 700; line-height: 1.1; }
.kpi-l { display: block; font-size: .78rem; opacity: .7; margin-top: 2px; }
.st-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px 18px; }

/* Readiness is useful and long: one level down, never the first thing seen.
   Expand all deliberately does NOT open it — it belongs to Overview, not to
   the accordion, and forcing it open would bury the summary it sits under. */
.st-readiness { margin-top: 14px; border-top: 1px solid var(--line); padding-top: 10px; }
.st-readiness > summary { cursor: pointer; min-height: 44px; display: flex; align-items: center; opacity: .85; }
.st-readiness:not([open]) > *:not(summary) { display: none !important; }
.st-readiness .so-checks { margin-top: 8px; }

.st-staff-list { list-style: none; margin: 10px 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.st-staff-list li { display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--radius); }
.st-staff-name { flex: 1 1 8rem; min-width: 0; overflow-wrap: anywhere; }
.st-staff-role { font-size: .8rem; opacity: .75; }
.st-staff-state { font-size: .78rem; }
.st-staff-state.on { color: var(--ok); }
.st-staff-state.off { opacity: .65; }

@media (min-width: 900px) {
  /* The same model, more room — no second desktop navigation. */
  .acc-body { padding: 18px 20px; }
  .kpi { flex: 0 1 140px; }
}


/* ==========================================================================
   C6D3 — DENSITY AND HIERARCHY
   --------------------------------------------------------------------------
   The C6D2 model is unchanged. What changes here is how much of it fits on a
   screen and how quickly the eye can tell four things apart:

       a STATUS      (Enabled, Ready)          — quiet, never looks pressable
       a PRIMARY     (Add destination)         — solid, one per area
       a SECONDARY   (Edit)                    — plain text with a hairline
       a STATE CHANGE(Switch off)              — secondary, tinted as a warning

   One visual system, no per-section colour, nothing saturated.
   ========================================================================== */

/* ---- the four action classes ---------------------------------------- */
.badge { display: inline-flex; align-items: center; gap: 4px; padding: 1px 8px;
  border-radius: 999px; font-size: .76rem; line-height: 1.6; white-space: nowrap;
  border: 1px solid var(--line); background: #fff; }
.badge.is-on { color: #2c6e49; border-color: #bcd9c8; background: #f2f9f5; }
.badge.is-off { color: #6b6b6b; background: #f4f4f4; }
.badge.is-warn { color: #8a5f0c; border-color: #e6d2a6; background: #fdf8ec; }

.btn-quiet { background: none; border: 1px solid transparent; border-radius: var(--radius);
  padding: 6px 10px; min-height: 36px; font: inherit; font-size: .86rem; color: inherit;
  cursor: pointer; opacity: .85; text-decoration: underline; text-underline-offset: 3px; }
.btn-quiet:hover { opacity: 1; border-color: var(--line); background: #fff; text-decoration: none; }
.btn-quiet.is-danger { color: #8a3228; }

/* ---- store tabs ------------------------------------------------------ */
.st-tabs { gap: 8px; margin: 2px 0 12px; }
.st-tab { align-items: flex-start; gap: 8px; padding: 8px 12px; border-radius: var(--radius); }
.st-tab-body { display: flex; flex-direction: column; gap: 1px; min-width: 0; text-align: start; }
.st-tab-name { font-weight: 600; line-height: 1.25; }
.st-tab-state { font-size: .76rem; opacity: .7; font-weight: 400; line-height: 1.3; }
.st-tab.is-current { border-width: 1px; box-shadow: inset 0 0 0 1px var(--ink); background: #fff; }
.st-tab.is-current .st-tab-state { opacity: .85; }
.st-tab-mark { margin-top: 2px; }

/* ---- header ---------------------------------------------------------- */
.st-head { margin: 0 0 12px; padding-bottom: 10px; border-bottom: 1px solid var(--line); }
.st-head h2 { font-size: 1.1rem; }
.st-head .so-meta { font-size: .82rem; opacity: .8; line-height: 1.5; }
.st-acc-controls { margin: 0 0 8px; gap: 12px; }

/* ---- accordion: the header is a band, the body is the page ----------- */
.st-acc { gap: 6px; }
.acc-btn { min-height: 46px; padding: 10px 12px; background: var(--tint, #f6f4f1); }
.acc-btn:hover { background: #efece8; }
.acc-btn[aria-expanded="true"] { background: #fff; border-bottom: 2px solid var(--ink); }
.acc-title { font-size: .95rem; }
.acc-mark { width: 1em; text-align: center; }
.acc-body { padding: 12px; }

/* ---- Overview -------------------------------------------------------- */
.kpi-row { gap: 8px; margin-bottom: 12px; }
.kpi { flex: 1 1 72px; min-width: 72px; padding: 8px 10px; }
.kpi-n { font-size: 1.15rem; }
.kpi-l { font-size: .72rem; }
.st-facts { grid-template-columns: repeat(auto-fit, minmax(128px, 1fr)); gap: 8px 16px; }
.st-facts .fx-fact dt { font-size: .74rem; }
.st-facts .fx-fact dd { font-size: .9rem; font-weight: 600; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.st-readiness { margin-top: 12px; padding-top: 8px; }
.st-readiness > summary { min-height: 40px; font-size: .88rem; }

/* ---- Fulfillment: one line per method -------------------------------- */
.fx-row { display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: var(--radius); margin-bottom: 6px; background: #fff; }
.fx-main { flex: 1 1 auto; min-width: 0; }
.fx-name { display: block; font-weight: 600; font-size: .95rem; }
.fx-line { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 3px;
  font-size: .82rem; opacity: .9; }
.fx-fee { font-weight: 600; }
.fx-actions { flex: 0 0 auto; }
.fx-edit-form { margin-top: 10px; padding-top: 10px; gap: 8px; }

/* ---- Destinations: chips, not pills ---------------------------------- */
.dest-summary { gap: 6px 16px; margin-bottom: 8px; }
.dest-search { min-height: 40px; margin-bottom: 8px; }
.dest-list { display: grid; grid-template-columns: 1fr; gap: 6px; }
.dest-row { display: flex; align-items: center; gap: 8px; padding: 7px 10px;
  border: 1px solid var(--line); border-radius: var(--radius); background: #fff; font-size: .88rem; }
.dest-row.is-off { background: #fafafa; }
.dest-row .fulfil-dest-name { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.dest-addwrap { margin-top: 10px; }
.dest-addform { margin-top: 8px; display: flex; flex-wrap: wrap; gap: 8px; }
.dest-addform[hidden] { display: none !important; }

/* ---- Staff ----------------------------------------------------------- */
.st-staff-list { gap: 6px; margin: 8px 0; }
.st-staff-list li { padding: 7px 10px; font-size: .88rem; }
.st-person.is-off { background: #fafafa; }
.st-inactive { margin-top: 8px; }
.st-inactive > summary { min-height: 40px; display: flex; align-items: center;
  font-size: .86rem; opacity: .8; cursor: pointer; }
.st-inactive:not([open]) > *:not(summary) { display: none !important; }

/* ---- Store Settings -------------------------------------------------- */
.st-admin { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line); }
.st-admin #store-list[hidden] { display: none !important; }
.st-admin .cur-list { margin-top: 10px; }

@media (min-width: 900px) {
  /* Width used, not stretched: facts and destinations gain columns, the rest
     simply stops wasting height. */
  .acc-body { padding: 14px 16px; }
  .kpi { flex: 0 1 120px; }
  .st-facts { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
  .dest-list { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
  .fx-row { padding: 10px 14px; }
}


/* ==========================================================================
   C6D4 — THE MARMOCHA ADMIN VISUAL LANGUAGE
   PILOT SURFACE: Store Management (owner-stores.html)
   --------------------------------------------------------------------------
   The approved concept is a warm, restrained retail-operations look: a beige
   page, white working surfaces, one brown/orange accent used sparingly, dark
   text, quiet rules and compact density.

   MARMOCHA ALREADY WAS THAT. The palette at the top of this file — --bg
   #faf8f5, --card #ffffff, --ink #2c2622, --muted #635b54, --line #e0d7cc,
   --accent #b5643c — is the approved language already written down. So this
   block introduces NO SECOND PALETTE. It adds SEMANTIC NAMES for the
   primitives that already exist, plus the four values the concept needs and
   this file did not yet have (a muted surface, a table-header tint, a card
   radius and a soft shadow).

   That is deliberate and it is the whole point of a pilot: when this language
   is rolled out to the other owner pages, they inherit one set of tokens, not
   a second theme competing with the first.

   SCOPE. Everything that could touch another page is scoped to :is(.stores-page,.admin-ws).
   The generic component classes (.op-table, .acc-*, .st-*, .kpi, .fx-*) exist
   only on this page today; they are written to be lifted out later.
   ========================================================================== */

:root {
  /* Surfaces — three of the four are the existing primitives, renamed. */
  --surface-page:    var(--bg);
  --surface-card:    var(--card);
  --surface-muted:   #f5f1ec;
  --surface-header:  #f0eae1;

  /* Text. --text-muted is the lightest value permitted, and it is still
     about 5.6:1 on white: P035-C14 was bought by text that measured 4.8:1
     at .7rem and could not be read. Nothing quieter than this is allowed. */
  --text-primary:    var(--ink);
  --text-secondary:  var(--muted);
  --text-muted:      #6f665f;

  --border-soft:     var(--line);
  --border-strong:   #cdbfb0;

  --brand-primary:       var(--accent);
  --brand-primary-soft:  #f4e9dd;   /* the sidebar's own selected fill */
  --brand-primary-hover: var(--accent-dark);

  /* Status. Each is carried by a word as well as a colour — never colour
     alone — and each meets contrast on its own tinted background. */
  --status-success: #2c6e49;
  --status-warning: #8a5f0c;
  --status-danger:  #8a3228;

  --shadow-soft:    0 1px 2px rgba(44,38,34,.06), 0 2px 10px rgba(44,38,34,.045);
  --radius-card:    12px;
  --radius-control: 8px;
}

/* ---- the page surface ------------------------------------------------ */
:is(.stores-page,.admin-ws) { background: var(--surface-page); }
:is(.stores-page,.admin-ws) h2, :is(.stores-page,.admin-ws) h3, :is(.stores-page,.admin-ws) h4 { color: var(--text-primary); }

/* ==========================================================================
   STORE TABS — the same selected-state grammar as the sidebar
   --------------------------------------------------------------------------
   The sidebar marks the active page three ways at once: a warm fill, a
   heavier weight and a solid accent bar. Somebody who cannot separate this
   beige from that beige still sees the bar. The tabs now say it the same way,
   so the two halves of the screen read as one product.
   ========================================================================== */
:is(.stores-page,.admin-ws) .st-tab {
  background: var(--surface-card);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-control);
  color: var(--text-primary);
  box-shadow: none;
  transition: background .12s ease, border-color .12s ease;
}
:is(.stores-page,.admin-ws) .st-tab:hover { background: var(--surface-muted); border-color: var(--border-strong); }
:is(.stores-page,.admin-ws) .st-tab .st-tab-name  { color: var(--text-primary); }
:is(.stores-page,.admin-ws) .st-tab .st-tab-state { color: var(--text-secondary); }

:is(.stores-page,.admin-ws) .st-tab.is-current {
  background: var(--brand-primary-soft);
  border-color: var(--brand-primary);
  box-shadow: inset 3px 0 0 var(--brand-primary);
  padding-inline-start: 15px;
}
:is(.stores-page,.admin-ws) .st-tab.is-current .st-tab-name { font-weight: 700; }
:is(.stores-page,.admin-ws) .st-tab.is-current .st-tab-state { color: var(--text-primary); opacity: .85; }
:is(.stores-page,.admin-ws) .st-tab:focus-visible { outline: 2px solid var(--brand-primary); outline-offset: 2px; }

/* ---- the selected store, said once ---------------------------------- */
:is(.stores-page,.admin-ws) .st-head h2 { font-size: 1.22rem; font-weight: 700; letter-spacing: -.01em; }
:is(.stores-page,.admin-ws) .st-head .so-meta { color: var(--text-secondary); }

/* ==========================================================================
   SECTION HEADERS — number, icon, title, chevron
   ========================================================================== */
:is(.stores-page,.admin-ws) .acc-item {
  background: var(--surface-card);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-soft);
  overflow: hidden;
}
:is(.stores-page,.admin-ws) .acc-btn {
  display: flex; align-items: center; gap: 10px; width: 100%;
  background: var(--surface-card); border: 0; border-radius: 0;
  color: var(--text-primary); text-align: start;
}
:is(.stores-page,.admin-ws) .acc-btn:hover { background: var(--surface-muted); }
:is(.stores-page,.admin-ws) .acc-btn:focus-visible { outline: 2px solid var(--brand-primary); outline-offset: -2px; }

/* THE NUMBER carries the accent, once per header — the concept's single
   permitted flash of brand per row. */
:is(.stores-page,.admin-ws) .acc-n {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: 7px;
  background: var(--brand-primary-soft); color: var(--brand-primary-hover);
  font-size: .8rem; font-weight: 700; font-variant-numeric: tabular-nums;
}
:is(.stores-page,.admin-ws) .acc-ico { flex: 0 0 auto; display: inline-flex; color: var(--text-secondary); }
:is(.stores-page,.admin-ws) .acc-ico svg { width: 18px; height: 18px; display: block; }
:is(.stores-page,.admin-ws) .acc-title { flex: 1 1 auto; min-width: 0; font-weight: 600; color: var(--text-primary); }
:is(.stores-page,.admin-ws) .acc-mark { flex: 0 0 auto; color: var(--text-secondary); font-size: .9rem; }

/* OPEN IS OBVIOUS FROM THREE SIGNALS: the tinted band, the accent rule under
   it and the rotated chevron — not from the chevron alone. */
:is(.stores-page,.admin-ws) .acc-btn[aria-expanded="true"] {
  background: var(--surface-header);
  border-bottom: 2px solid var(--brand-primary);
}
:is(.stores-page,.admin-ws) .acc-btn[aria-expanded="true"] .acc-n { background: var(--brand-primary); color: #fff; }
:is(.stores-page,.admin-ws) .acc-btn[aria-expanded="true"] .acc-ico { color: var(--brand-primary-hover); }
:is(.stores-page,.admin-ws) .acc-body { background: var(--surface-card); }

/* A heading inside a body, used to separate information from administration. */
:is(.stores-page,.admin-ws) .op-subhead {
  margin: 0 0 8px; font-size: .78rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-secondary);
}
:is(.stores-page,.admin-ws) .st-admin .op-subhead { margin-top: 2px; }

/* ==========================================================================
   KPI CARDS
   ========================================================================== */
:is(.stores-page,.admin-ws) .kpi {
  display: flex; align-items: center; gap: 9px;
  background: var(--surface-muted); border: 1px solid var(--border-soft);
  border-radius: var(--radius-control); box-shadow: none;
}
:is(.stores-page,.admin-ws) .kpi .acc-ico { color: var(--brand-primary); }
:is(.stores-page,.admin-ws) .kpi .acc-ico svg { width: 17px; height: 17px; }
:is(.stores-page,.admin-ws) .kpi-b { display: flex; flex-direction: column; min-width: 0; }
:is(.stores-page,.admin-ws) .kpi-n {
  color: var(--text-primary); font-weight: 700; line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
:is(.stores-page,.admin-ws) .kpi-l { color: var(--text-secondary); line-height: 1.3; }

/* ---- the facts grid -------------------------------------------------- */
:is(.stores-page,.admin-ws) .st-facts .fx-fact dt { color: var(--text-secondary); font-weight: 600;
  letter-spacing: .03em; text-transform: uppercase; }
:is(.stores-page,.admin-ws) .st-facts .fx-fact dd { color: var(--text-primary); }
:is(.stores-page,.admin-ws) .st-facts .fx-fact {
  padding: 7px 10px; background: var(--surface-card);
  border: 1px solid var(--border-soft); border-radius: var(--radius-control);
}

/* ==========================================================================
   THE OPERATIONAL TABLE, AND WHAT IT BECOMES ON A PHONE
   --------------------------------------------------------------------------
   MOBILE FIRST IS THE DEFAULT HERE, not the exception. The base rules below
   are the PHONE: every row is a labelled record, stacked, with its column
   name printed beside each value from data-op-label. Only at 760px and above
   does the grid switch on and the head appear.

   A row is therefore never a wide table squeezed into 390px, and no
   information is dropped to make it fit — the labels are added, not removed.
   ========================================================================== */
:is(.stores-page,.admin-ws) .op-table { display: block; }

/* --- phone: a labelled record ---------------------------------------- */
:is(.stores-page,.admin-ws) .op-thead { display: none; }
:is(.stores-page,.admin-ws) .op-row {
  display: grid; grid-template-columns: auto 1fr; gap: 4px 10px;
  align-items: center;
  padding: 10px 12px; margin-bottom: 6px;
  background: var(--surface-card);
  border: 1px solid var(--border-soft); border-radius: var(--radius-control);
}
:is(.stores-page,.admin-ws) .op-row > .op-n {
  grid-column: 1; grid-row: 1;
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; height: 22px; padding: 0 5px; border-radius: 6px;
  background: var(--surface-muted); color: var(--text-secondary);
  font-size: .74rem; font-weight: 700; font-variant-numeric: tabular-nums;
}
:is(.stores-page,.admin-ws) .op-row > .op-main {
  grid-column: 2; grid-row: 1; min-width: 0;
  font-weight: 600; color: var(--text-primary); overflow-wrap: anywhere;
}
:is(.stores-page,.admin-ws) .op-row > .op-cell,
:is(.stores-page,.admin-ws) .op-row > .op-act { grid-column: 2; min-width: 0; }
:is(.stores-page,.admin-ws) .op-row > .op-cell {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: .85rem; color: var(--text-secondary);
}
:is(.stores-page,.admin-ws) .op-row > .op-cell[data-op-label]::before {
  content: attr(data-op-label);
  flex: 0 0 auto; min-width: 5.5em;
  font-size: .72rem; font-weight: 600; letter-spacing: .03em;
  text-transform: uppercase; color: var(--text-muted);
}
:is(.stores-page,.admin-ws) .op-row > .op-act { margin-top: 2px; }
:is(.stores-page,.admin-ws) .op-row.is-off { background: var(--surface-muted); }
:is(.stores-page,.admin-ws) .op-figure { font-variant-numeric: tabular-nums; }
:is(.stores-page,.admin-ws) .op-figure .fx-fee { color: var(--text-primary); font-weight: 700; }
:is(.stores-page,.admin-ws) .op-dash { color: var(--text-muted); }

/* --- tablet and desktop: a real table -------------------------------- */
@media (min-width: 760px) {
  :is(.stores-page,.admin-ws) .op-thead {
    display: grid; align-items: center; gap: 10px;
    padding: 7px 12px; margin-bottom: 2px;
    background: var(--surface-header);
    border: 1px solid var(--border-soft); border-radius: var(--radius-control);
    font-size: .72rem; font-weight: 700; letter-spacing: .05em;
    text-transform: uppercase; color: var(--text-secondary);
  }
  :is(.stores-page,.admin-ws) .op-row {
    display: grid; align-items: center; gap: 10px;
    margin-bottom: 0; border-radius: 0;
    border-width: 0 0 1px 0; border-color: var(--border-soft);
    background: var(--surface-card);
  }
  :is(.stores-page,.admin-ws) .op-table > .op-row:last-child,
  :is(.stores-page,.admin-ws) .op-table > .op-row:last-of-type { border-bottom-width: 0; }
  :is(.stores-page,.admin-ws) .op-table {
    border: 1px solid var(--border-soft); border-radius: var(--radius-control);
    overflow: hidden; background: var(--surface-card);
  }
  :is(.stores-page,.admin-ws) .op-table > .op-thead {
    border-width: 0 0 1px 0; border-radius: 0; margin: 0;
  }
  :is(.stores-page,.admin-ws) .op-row:hover { background: var(--surface-muted); }
  :is(.stores-page,.admin-ws) .op-row > .op-n,
  :is(.stores-page,.admin-ws) .op-row > .op-main,
  :is(.stores-page,.admin-ws) .op-row > .op-cell,
  :is(.stores-page,.admin-ws) .op-row > .op-act { grid-column: auto; grid-row: auto; }
  :is(.stores-page,.admin-ws) .op-row > .op-cell[data-op-label]::before { content: none; }
  :is(.stores-page,.admin-ws) .op-row > .op-act { margin-top: 0; justify-self: end; }
  :is(.stores-page,.admin-ws) .op-thead > .op-n { background: none; color: inherit; font-weight: 700; }

  /* One template per table, shared by its head and its rows. */
  :is(.stores-page,.admin-ws) .op-table--fulfil > .op-thead,
  :is(.stores-page,.admin-ws) .op-table--fulfil > .op-row {
    grid-template-columns: 2.2rem minmax(0,1.5fr) minmax(0,1.3fr) minmax(0,1fr) 7.5rem 5rem;
  }
  :is(.stores-page,.admin-ws) .op-table--dest > .op-thead,
  :is(.stores-page,.admin-ws) .op-table--dest > .op-row {
    grid-template-columns: 2.2rem minmax(0,2fr) minmax(0,1fr) 7.5rem 7rem;
  }
  :is(.stores-page,.admin-ws) .op-table--staff > .op-thead,
  :is(.stores-page,.admin-ws) .op-table--staff > .op-row {
    grid-template-columns: 2.2rem minmax(0,1.6fr) minmax(0,1.1fr) minmax(0,1fr) 6.5rem;
  }
  /* The edit form belongs to the row above it and spans the whole width. */
  :is(.stores-page,.admin-ws) .op-row > .fx-edit-form { grid-column: 1 / -1; }
}

/* The fulfilment editor, when it is asked for, sits under its own row.
   THE [hidden] GUARD IS LOAD-BEARING: an author display rule beats the
   browser's own [hidden]{display:none}, which is how this page once shipped
   a control that reported itself closed while staying fully on screen. */
:is(.stores-page,.admin-ws) .fx-edit-form {
  grid-column: 1 / -1;
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin-top: 8px; padding-top: 10px;
  border-top: 1px dashed var(--border-soft);
}
:is(.stores-page,.admin-ws) .fx-edit-form[hidden] { display: none; }

/* ---- destinations: the summary line above each table ----------------- */
:is(.stores-page,.admin-ws) .fulfil-sub { font-size: .86rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-secondary); }
:is(.stores-page,.admin-ws) .dest-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; padding: 0 6px; border-radius: 999px;
  background: var(--brand-primary-soft); color: var(--brand-primary-hover);
  font-size: .76rem; font-weight: 700;
}
:is(.stores-page,.admin-ws) .dest-summary .fx-fact { background: var(--surface-muted); }
:is(.stores-page,.admin-ws) .dest-search {
  border: 1px solid var(--border-soft); border-radius: var(--radius-control);
  background: var(--surface-card); color: var(--text-primary); padding: 8px 10px;
}
:is(.stores-page,.admin-ws) .dest-search:focus-visible { outline: 2px solid var(--brand-primary); outline-offset: 1px; }
:is(.stores-page,.admin-ws) .dest-list.op-table { display: block; grid-template-columns: none; }

/* ---- a notice, not a whisper ---------------------------------------- */
:is(.stores-page,.admin-ws) .op-notice {
  margin: 0 0 10px; padding: 9px 12px;
  background: var(--surface-muted);
  border: 1px solid var(--border-soft);
  border-inline-start: 3px solid var(--brand-primary);
  border-radius: var(--radius-control);
  color: var(--text-primary); font-size: .88rem; line-height: 1.5;
}
:is(.stores-page,.admin-ws) .px-empty {
  padding: 12px; background: var(--surface-muted);
  border: 1px solid var(--border-soft); border-radius: var(--radius-control);
}
:is(.stores-page,.admin-ws) .px-empty p { margin: 0 0 4px; }
:is(.stores-page,.admin-ws) .px-empty .muted-note { color: var(--text-secondary); }
:is(.stores-page,.admin-ws) .muted-note { color: var(--text-secondary); }

/* ==========================================================================
   THE FOUR ACTION CLASSES — a status must never look pressable
   ========================================================================== */
:is(.stores-page,.admin-ws) .badge {
  border-radius: 999px; font-weight: 600; font-size: .75rem;
  padding: 2px 9px; cursor: default;
}
:is(.stores-page,.admin-ws) .badge.is-on   { color: var(--status-success); border-color: #bcd9c8; background: #f1f8f4; }
:is(.stores-page,.admin-ws) .badge.is-off  { color: var(--text-secondary); border-color: var(--border-soft); background: var(--surface-muted); }
:is(.stores-page,.admin-ws) .badge.is-warn { color: var(--status-warning); border-color: #e6d2a6; background: #fdf8ec; }

/* PRIMARY — filled, one per area. */
:is(.stores-page,.admin-ws) .btn-solid {
  background: var(--brand-primary); border: 1px solid var(--brand-primary);
  color: #fff; border-radius: var(--radius-control); font-weight: 600;
  box-shadow: none;
}
:is(.stores-page,.admin-ws) .btn-solid:hover { background: var(--brand-primary-hover); border-color: var(--brand-primary-hover); }
:is(.stores-page,.admin-ws) .btn-solid:focus-visible { outline: 2px solid var(--brand-primary-hover); outline-offset: 2px; }

/* SECONDARY — outlined and quiet. */
:is(.stores-page,.admin-ws) .btn-outline {
  background: var(--surface-card); border: 1px solid var(--border-strong);
  color: var(--text-primary); border-radius: var(--radius-control); font-weight: 600;
}
:is(.stores-page,.admin-ws) .btn-outline:hover { background: var(--surface-muted); border-color: var(--brand-primary); }

:is(.stores-page,.admin-ws) .btn-quiet {
  border-radius: var(--radius-control); color: var(--text-primary);
  text-decoration: none; border: 1px solid var(--border-soft);
  background: var(--surface-card); opacity: 1; font-weight: 600;
}
:is(.stores-page,.admin-ws) .btn-quiet:hover { background: var(--surface-muted); border-color: var(--border-strong); }
:is(.stores-page,.admin-ws) .btn-quiet:focus-visible { outline: 2px solid var(--brand-primary); outline-offset: 1px; }

/* STATE CHANGE — distinct, restrained, never red-on-red. */
:is(.stores-page,.admin-ws) .btn-quiet.is-danger { color: var(--status-danger); border-color: #e4c8c2; }
:is(.stores-page,.admin-ws) .btn-quiet.is-danger:hover { background: #fbf2f0; border-color: var(--status-danger); }

/* ==========================================================================
   TYPOGRAPHY AND DIRECTION
   ========================================================================== */
:is(.stores-page,.admin-ws) { font-feature-settings: "kern" 1; }
:is(.stores-page,.admin-ws) .op-row, :is(.stores-page,.admin-ws) .acc-body { line-height: 1.5; }
/* Numbers stay LTR and tabular in both languages, so a column of fees lines
   up and an Arabic reader still sees 11.000 rather than a reversed figure. */
:is(.stores-page,.admin-ws) .op-figure, :is(.stores-page,.admin-ws) .kpi-n, :is(.stores-page,.admin-ws) .op-n,
:is(.stores-page,.admin-ws) .st-facts .fx-fact dd { font-variant-numeric: tabular-nums; }
[dir="rtl"] :is(.stores-page,.admin-ws) .op-row > .op-act { justify-self: end; }
[dir="rtl"] :is(.stores-page,.admin-ws) .acc-btn,
[dir="rtl"] :is(.stores-page,.admin-ws) .op-row { text-align: start; }

/* Arabic headings need a little more room to stay comfortable. */
[dir="rtl"] :is(.stores-page,.admin-ws) .acc-title { line-height: 1.6; }
[dir="rtl"] :is(.stores-page,.admin-ws) .op-subhead { letter-spacing: 0; }
[dir="rtl"] :is(.stores-page,.admin-ws) .fulfil-sub { letter-spacing: 0; }
[dir="rtl"] :is(.stores-page,.admin-ws) .st-facts .fx-fact dt { letter-spacing: 0; }
[dir="rtl"] :is(.stores-page,.admin-ws) .op-thead { letter-spacing: 0; }
[dir="rtl"] :is(.stores-page,.admin-ws) .op-row > .op-cell[data-op-label]::before { letter-spacing: 0; }

/* ---- nothing may push the page sideways ------------------------------ */
:is(.stores-page,.admin-ws) .op-row, :is(.stores-page,.admin-ws) .op-thead, :is(.stores-page,.admin-ws) .kpi,
:is(.stores-page,.admin-ws) .st-facts .fx-fact { min-width: 0; }
:is(.stores-page,.admin-ws) .op-main, :is(.stores-page,.admin-ws) .op-cell { overflow-wrap: anywhere; }


/* ==========================================================================
   C6D5 — CALIBRATION AGAINST THE APPROVED REFERENCE
   + THE BREADCRUMB PRIMITIVE
   --------------------------------------------------------------------------
   C6D4 established the language from a written description. This block
   calibrates it against the image the Product Owner approved, and adds the
   one navigation primitive that image contains.

   NO NEW PALETTE. Two semantic tokens are added — --status-info and
   --surface-info — because the reference uses blue for "this is how it
   works", and Marmocha had no informational colour. Blue is semantic here
   and nowhere else: it never touches a brand control.
   ========================================================================== */

:root {
  --status-info:  #1c5b8a;
  --surface-info: #eef5fb;
  --border-info:  #c4dcef;
}

/* ==========================================================================
   THE BREADCRUMB — a design-system primitive, piloted here
   --------------------------------------------------------------------------
   Compact, subordinate to the page title, never button-like. The separator
   is drawn by CSS so a screen reader announces "View Shop, Store Management,
   IZJ Store" and not a row of slashes.

   DIRECTION IS NOT HARD-CODED. The list is a flex row in the writing
   direction, so Arabic reads right to left and English left to right from
   the same rule, and a store name is dir="auto" so a Latin name inside an
   Arabic trail still reads correctly.
   ========================================================================== */
.admin-breadcrumb { margin: -2px 0 14px; }
.admin-breadcrumb[hidden] { display: none; }
.admin-breadcrumb-list {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 2px 0; margin: 0; padding: 0; list-style: none;
  font-size: .84rem; line-height: 1.5;
}
.admin-breadcrumb-item { display: inline-flex; align-items: center; min-width: 0; }
.admin-breadcrumb-item + .admin-breadcrumb-item::before {
  content: "/"; margin: 0 8px; color: var(--text-muted); font-size: .82rem;
}
.admin-breadcrumb-link {
  color: var(--text-secondary); text-decoration: none;
  border-bottom: 1px solid transparent; padding: 1px 0;
}
.admin-breadcrumb-link:hover { color: var(--brand-primary-hover); border-bottom-color: currentColor; }
.admin-breadcrumb-link:focus-visible {
  outline: 2px solid var(--brand-primary); outline-offset: 2px; border-radius: 3px;
}
/* A level that exists in the hierarchy but has no destination of its own. */
.admin-breadcrumb-label { color: var(--text-secondary); }
/* Where you are. Stronger, and deliberately not a link to itself. */
.admin-breadcrumb-current {
  color: var(--text-primary); font-weight: 700;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 60vw;
}

/* ==========================================================================
   SECTION MARKERS — solid, open or closed
   ========================================================================== */
:is(.stores-page,.admin-ws) .acc-n {
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--brand-primary); color: #fff;
  font-size: .82rem; font-weight: 700; box-shadow: none;
}
/* Open state is carried by the BAND and the RULE, not by the marker, so the
   number stays a constant anchor down the page exactly as in the reference. */
:is(.stores-page,.admin-ws) .acc-btn[aria-expanded="true"] .acc-n { background: var(--brand-primary); color: #fff; }
:is(.stores-page,.admin-ws) .acc-ico { color: var(--text-muted); }
:is(.stores-page,.admin-ws) .acc-ico svg { width: 17px; height: 17px; }
:is(.stores-page,.admin-ws) .acc-btn[aria-expanded="true"] .acc-ico { color: var(--text-secondary); }
:is(.stores-page,.admin-ws) .acc-title { font-size: 1rem; font-weight: 700; }
:is(.stores-page,.admin-ws) .acc-btn { min-height: 50px; padding: 11px 14px; }
:is(.stores-page,.admin-ws) .acc-item { border-radius: var(--radius-card); margin-bottom: 0; }
:is(.stores-page,.admin-ws) .st-acc { gap: 10px; }

/* ==========================================================================
   KPI CARDS — centred, with a circular accent badge
   ========================================================================== */
:is(.stores-page,.admin-ws) .kpi-row { gap: 10px; }
:is(.stores-page,.admin-ws) .kpi {
  flex-direction: column; align-items: center; text-align: center; gap: 6px;
  background: var(--surface-card); border: 1px solid var(--border-soft);
  border-radius: var(--radius-control); padding: 12px 10px;
}
:is(.stores-page,.admin-ws) .kpi .acc-ico {
  width: 34px; height: 34px; border-radius: 50%;
  align-items: center; justify-content: center;
  background: var(--brand-primary); color: #fff;
}
:is(.stores-page,.admin-ws) .kpi .acc-ico svg { width: 17px; height: 17px; }
:is(.stores-page,.admin-ws) .kpi-b { align-items: center; gap: 1px; }
:is(.stores-page,.admin-ws) .kpi-n { font-size: 1.32rem; font-weight: 700; }
:is(.stores-page,.admin-ws) .kpi-l { font-size: .76rem; color: var(--text-secondary); font-weight: 600; }
@media (min-width: 760px) {
  :is(.stores-page,.admin-ws) .kpi-row { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
  :is(.stores-page,.admin-ws) .kpi { flex: 1 1 auto; }
}

/* ==========================================================================
   THE OPERATIONAL TABLE, CALIBRATED
   ========================================================================== */
:is(.stores-page,.admin-ws) .op-table { border-radius: var(--radius-card); }
@media (min-width: 760px) {
  :is(.stores-page,.admin-ws) .op-thead {
    background: var(--surface-header);
    padding: 9px 14px; font-size: .73rem; color: var(--text-secondary);
    border-bottom: 1px solid var(--border-soft);
  }
  :is(.stores-page,.admin-ws) .op-row { padding: 11px 14px; }
  :is(.stores-page,.admin-ws) .op-row:hover { background: #faf7f3; }
  /* Everything but the leading name column reads centred, as in the
     reference: a column of short values is easier to scan down the middle. */
  :is(.stores-page,.admin-ws) .op-thead > .op-cell,
  :is(.stores-page,.admin-ws) .op-row > .op-cell { justify-content: center; text-align: center; }
  :is(.stores-page,.admin-ws) .op-thead > .op-n, :is(.stores-page,.admin-ws) .op-row > .op-n { justify-self: center; }
  :is(.stores-page,.admin-ws) .op-row > .op-act { justify-self: center; }
  :is(.stores-page,.admin-ws) .op-row > .op-main { justify-self: start; }
  :is(.stores-page,.admin-ws) .op-table--fulfil > .op-thead > .op-cell:first-of-type,
  :is(.stores-page,.admin-ws) .op-table--dest   > .op-thead > .op-cell:first-of-type,
  :is(.stores-page,.admin-ws) .op-table--staff  > .op-thead > .op-cell:first-of-type { text-align: start; }
}
:is(.stores-page,.admin-ws) .op-row > .op-main { display: flex; align-items: center; gap: 8px; }
:is(.stores-page,.admin-ws) .op-ico { flex: 0 0 auto; display: inline-flex; color: var(--brand-primary); }
:is(.stores-page,.admin-ws) .op-ico svg { width: 17px; height: 17px; display: block; }
:is(.stores-page,.admin-ws) .op-n { font-size: .75rem; }

/* ---- the information table: one row read across ---------------------- */
:is(.stores-page,.admin-ws) .op-table--info > .op-row { grid-template-columns: 1fr; }
:is(.stores-page,.admin-ws) .op-table--info > .op-row > .op-cell { grid-column: 1; }
@media (min-width: 760px) {
  /* Still a labelled record here: nine columns on a tablet is not a table,
     it is a squeeze. The head stays hidden until there is room for it. */
  :is(.stores-page,.admin-ws) .op-table--info > .op-thead { display: none; }
  :is(.stores-page,.admin-ws) .op-table--info > .op-row > .op-cell[data-op-label]::before {
    content: attr(data-op-label);
    flex: 0 0 auto; min-width: 8em;
    font-size: .72rem; font-weight: 600; letter-spacing: .03em;
    text-transform: uppercase; color: var(--text-muted);
  }
  :is(.stores-page,.admin-ws) .op-table--info > .op-row > .op-cell { justify-content: flex-start; text-align: start; }
}
@media (min-width: 1100px) {
  :is(.stores-page,.admin-ws) .op-table--info > .op-thead { display: grid; }
  :is(.stores-page,.admin-ws) .op-table--info > .op-thead,
  :is(.stores-page,.admin-ws) .op-table--info > .op-row {
    grid-template-columns: repeat(var(--cols, 6), minmax(0, 1fr));
    gap: 8px;
  }
  :is(.stores-page,.admin-ws) .op-table--info > .op-row > .op-cell[data-op-label]::before { content: none; }
  :is(.stores-page,.admin-ws) .op-table--info > .op-thead > .op-cell,
  :is(.stores-page,.admin-ws) .op-table--info > .op-row > .op-cell {
    justify-content: center; text-align: center;
  }
  :is(.stores-page,.admin-ws) .op-table--info > .op-row > .op-cell {
    color: var(--text-primary); font-weight: 600; overflow-wrap: anywhere;
  }
}

/* ==========================================================================
   STATUS — a dot and a word, never a button
   ========================================================================== */
:is(.stores-page,.admin-ws) .badge.is-dot {
  background: none; border: 0; padding: 0; gap: 7px;
  font-weight: 600; color: var(--text-primary);
}
:is(.stores-page,.admin-ws) .badge.is-dot .dot {
  width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto;
  background: var(--status-success);
  box-shadow: 0 0 0 2px rgba(44,110,73,.15);
}
/* NOT COLOUR ALONE: the word beside it says Enabled or Disabled, and the
   off state is additionally hollow rather than merely a different hue. */
:is(.stores-page,.admin-ws) .badge.is-dot.is-off { color: var(--text-secondary); }
:is(.stores-page,.admin-ws) .badge.is-dot.is-off .dot {
  background: var(--surface-card); border: 2px solid var(--border-strong);
  width: 9px; height: 9px; box-shadow: none;
}
:is(.stores-page,.admin-ws) .badge.is-dot.is-warn { color: var(--status-warning); }
:is(.stores-page,.admin-ws) .badge.is-dot.is-warn .dot { background: var(--status-warning); box-shadow: 0 0 0 2px rgba(138,95,12,.15); }

/* ==========================================================================
   ACTIONS — icon and word together
   ========================================================================== */
:is(.stores-page,.admin-ws) .btn-icon { display: inline-flex; align-items: center; gap: 6px; }
:is(.stores-page,.admin-ws) .ui-ico { display: inline-flex; flex: 0 0 auto; }
:is(.stores-page,.admin-ws) .ui-ico svg { width: 15px; height: 15px; display: block; }
:is(.stores-page,.admin-ws) .btn-t { white-space: nowrap; }
:is(.stores-page,.admin-ws) .btn-quiet.btn-icon { padding: 6px 11px; }
:is(.stores-page,.admin-ws) .btn-solid.btn-icon { padding: 7px 13px; }
/* The word is what carries the meaning; the glyph only repeats it. Nothing
   here is ever icon-only, so no action loses its accessible name. */
@media (max-width: 480px) {
  :is(.stores-page,.admin-ws) .op-act .btn-t { font-size: .82rem; }
}

/* ==========================================================================
   DESTINATIONS — two areas, side by side only where they fit
   ========================================================================== */
:is(.stores-page,.admin-ws) .dest-areas {
  display: grid; grid-template-columns: 1fr; gap: 16px;
}
@media (min-width: 1000px) {
  /* auto-fit, so the pair splits only when each half is still readable and
     collapses back to one column on a narrower workspace by itself. */
  :is(.stores-page,.admin-ws) .dest-areas { grid-template-columns: repeat(auto-fit, minmax(390px, 1fr)); }
}
:is(.stores-page,.admin-ws) .fulfil-dest {
  min-width: 0; padding: 12px;
  background: var(--surface-card);
  border: 1px solid var(--border-soft); border-radius: var(--radius-card);
}
:is(.stores-page,.admin-ws) .dest-bar {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 8px; margin-bottom: 10px;
}
:is(.stores-page,.admin-ws) .dest-bar .fulfil-sub { margin: 0; }
:is(.stores-page,.admin-ws) .dest-addform { margin: 0 0 10px; }
:is(.stores-page,.admin-ws) .dest-addform[hidden] { display: none !important; }
:is(.stores-page,.admin-ws) .dest-summary { margin-bottom: 10px; }

/* ==========================================================================
   THE INFORMATION NOTICE — semantic blue, used nowhere else
   ========================================================================== */
:is(.stores-page,.admin-ws) .op-notice.is-info {
  display: flex; align-items: flex-start; gap: 9px;
  background: var(--surface-info);
  border: 1px solid var(--border-info);
  border-inline-start: 3px solid var(--status-info);
  color: var(--text-primary);
}
:is(.stores-page,.admin-ws) .op-notice-ico { flex: 0 0 auto; display: inline-flex; color: var(--status-info); margin-top: 1px; }
:is(.stores-page,.admin-ws) .op-notice-ico svg { width: 17px; height: 17px; display: block; }

/* ---- an empty state that keeps the table's frame --------------------- */
:is(.stores-page,.admin-ws) .px-empty { padding: 0; background: var(--surface-card); }
:is(.stores-page,.admin-ws) .op-row.is-empty { align-items: start; }
:is(.stores-page,.admin-ws) .op-row.is-empty > .op-main { font-weight: 700; }
:is(.stores-page,.admin-ws) .px-defaults { display: flex; flex-direction: column; gap: 2px; }
:is(.stores-page,.admin-ws) .px-default { color: var(--text-secondary); font-size: .85rem; }
@media (min-width: 760px) {
  :is(.stores-page,.admin-ws) .op-table--empty > .op-row { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); }
  :is(.stores-page,.admin-ws) .op-table--empty > .op-row > .op-cell { justify-content: flex-start; text-align: start; }
}

/* ==========================================================================
   STORE TABS — calibrated
   ========================================================================== */
:is(.stores-page,.admin-ws) .st-tab { padding: 9px 13px; }
:is(.stores-page,.admin-ws) .st-tab-name { font-size: .95rem; }
:is(.stores-page,.admin-ws) .st-tab-state { font-size: .75rem; }
:is(.stores-page,.admin-ws) .st-tab.is-current { box-shadow: inset 3px 0 0 var(--brand-primary), var(--shadow-soft); }

/* ==========================================================================
   DENSITY AND HIERARCHY, FINAL PASS
   ========================================================================== */
:is(.stores-page,.admin-ws) .acc-body { padding: 14px; }
@media (min-width: 760px) { :is(.stores-page,.admin-ws) .acc-body { padding: 16px 18px; } }
:is(.stores-page,.admin-ws) .st-head h2 { font-size: 1.28rem; }
:is(.stores-page,.admin-ws) .op-subhead { font-size: .76rem; margin-bottom: 10px; }
:is(.stores-page,.admin-ws) .fulfil-sub { font-size: .82rem; }
:is(.stores-page,.admin-ws) .muted-note { font-size: .85rem; }
:is(.stores-page,.admin-ws) .st-readiness { border-top: 1px solid var(--border-soft); }

/* Mixed technical values stay direction-safe in an Arabic page. */
:is(.stores-page,.admin-ws) [dir="ltr"] { unicode-bidi: isolate; }
[dir="rtl"] :is(.stores-page,.admin-ws) .admin-breadcrumb-current { max-width: 55vw; }

/* ---- phone: nothing may push the page sideways ----------------------- */
@media (max-width: 480px) {
  :is(.stores-page,.admin-ws) .admin-breadcrumb-list { font-size: .8rem; }
  :is(.stores-page,.admin-ws) .admin-breadcrumb-current { max-width: 100%; white-space: normal; }
  :is(.stores-page,.admin-ws) .kpi-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  :is(.stores-page,.admin-ws) .kpi { padding: 10px 8px; }
  :is(.stores-page,.admin-ws) .kpi-n { font-size: 1.2rem; }
  :is(.stores-page,.admin-ws) .dest-bar { align-items: stretch; }
  :is(.stores-page,.admin-ws) .dest-bar .btn-solid { width: 100%; justify-content: center; }
}


/* ==========================================================================
   C6D5 — TWO DEFECTS FOUND BY LOOKING AT THE RENDERED PAGE
   --------------------------------------------------------------------------
   Both were invisible to every assertion that existed, and both were found
   by rendering the page to an image and comparing it with the approved
   reference. They are written up here because the reason they hid is more
   useful than the fix.

   1 — THE STATUS WAS ABSOLUTELY POSITIONED, AND HAD BEEN SINCE C6D3.
       ".badge" is first defined near the top of this file as the storefront
       product-card ribbon: position:absolute, top:10px, left:10px. Store
       Management reused the class for its status pill and set display and
       colour on it — but never reset POSITION. So every status on this page
       was taken out of flow and painted at the corner of the nearest
       positioned ancestor: the STATUS column rendered empty, and its cell
       measured zero pixels tall.

       It survived two rounds of geometry assertions because the badge itself
       genuinely has width and height. "The element has a box" is not the
       same claim as "the element is in the box it belongs to", and only the
       second one is what a reader sees. The permanent suite now asserts
       containment, not existence.

   2 — THE IDENTITY ROW STACKED UNDER ITS OWN COLUMN HEAD.
       The head laid out as nine columns and the row laid out as nine
       columns — and every cell still sat in column 1, nine rows deep. The
       phone rule that pins each cell to a single column is written with one
       more class than the desktop rule that releases it, so it won the
       cascade at every width. Specificity, not order.
   ========================================================================== */

/* 1 — back into the flow it never should have left. */
:is(.stores-page,.admin-ws) .badge { position: static; top: auto; left: auto; right: auto; }

/* 2 — release the identity cells once there is room for real columns. */
@media (min-width: 1100px) {
  :is(.stores-page,.admin-ws) .op-table--info > .op-row > .op-cell { grid-column: auto; }
}

/* While looking: an Arabic word must not be broken across lines to fit a
   narrow column. "anywhere" will split mid-word, which is how الافتراضي came
   to render as two fragments; "break-word" only breaks when a single word
   genuinely cannot fit. */
:is(.stores-page,.admin-ws) .op-main, :is(.stores-page,.admin-ws) .op-cell { overflow-wrap: break-word; }

/* ==========================================================================
   SALES REPORT V2  —  P035 Phase C
   --------------------------------------------------------------------------
   MOBILE FIRST, and literally so: every rule below is the 390px rule, and the
   widening happens in min-width blocks at the end. The desktop tables are the
   enhancement (.rep-desk), not the base — a ten-column table is not rendered
   until there is room for it, and the card list stops being rendered once
   there is.

   Nothing here introduces a new palette. The tokens are the ones the rest of
   the admin already uses, so the report reads as the same product even though
   it is a richer page than most.
   ========================================================================== */

/* ---- the controls that are always on screen ---- */
.rep-controls { margin: 4px 0 8px; }
.rep-controls-row { display: flex; gap: 8px; align-items: stretch; margin-top: 10px; }
.rep-search { flex: 1 1 auto; min-width: 0; }
.rep-search input {
  width: 100%; box-sizing: border-box; min-height: 44px;
  padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px;
  font: inherit; font-size: .92rem; background: #fff; color: var(--ink);
}
.rep-filter-btn {
  display: inline-flex; align-items: center; gap: 8px; flex: 0 0 auto;
  min-height: 44px; padding: 10px 14px; cursor: pointer;
  border: 1px solid var(--line); border-radius: 10px; background: #fff;
  font: inherit; font-size: .9rem; color: var(--ink); font-weight: 600;
}
.rep-filter-btn:hover { background: var(--surface-muted); }
.rep-filter-icon { font-size: 1rem; line-height: 1; }
.rep-filter-count {
  background: var(--accent); color: #fff; border-radius: 999px;
  font-size: .76rem; font-weight: 700; padding: 1px 7px; min-width: 18px; text-align: center;
}
.rep-custom { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 10px; }
.rep-custom input { min-height: 44px; }
.rep-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.rep-chips:empty { margin-top: 0; }
.rep-chip {
  border: 1px solid var(--line); background: var(--brand-primary-soft); color: var(--ink);
  border-radius: 999px; padding: 6px 12px; font: inherit; font-size: .82rem;
  cursor: pointer; min-height: 32px;
}
.rep-chip:hover { border-color: var(--border-strong); }

/* ---- the filter sheet: a bottom sheet on a phone, a side panel on a desk -- */
.rep-sheet-backdrop { position: fixed; inset: 0; background: rgba(28,22,18,.42); z-index: 120; }
.rep-sheet {
  position: fixed; inset-inline: 0; bottom: 0; z-index: 121;
  background: #fff; border-top: 1px solid var(--line);
  border-radius: 16px 16px 0 0; box-shadow: var(--shadow);
  max-height: 86vh; display: flex; flex-direction: column;
}
.rep-sheet[hidden], .rep-sheet-backdrop[hidden] { display: none; }
.rep-sheet-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px; border-bottom: 1px solid var(--line);
}
.rep-sheet-head h2 { margin: 0; font-size: 1.05rem; }
.rep-sheet-close {
  border: 0; background: transparent; font-size: 1.6rem; line-height: 1;
  cursor: pointer; color: var(--muted); min-width: 44px; min-height: 44px;
}
.rep-sheet-body { padding: 14px 16px; overflow-y: auto; display: grid; gap: 12px; }
.rep-sheet-body .rep-field select { min-height: 44px; width: 100%; }
.rep-sheet-foot {
  display: flex; gap: 10px; padding: 12px 16px;
  border-top: 1px solid var(--line); background: var(--surface-muted);
}
.rep-sheet-foot > * { flex: 1 1 0; min-height: 44px; }

/* ---- KPI and profitability cards ---- */
.rep-h2 { font-size: 1.02rem; margin: 20px 0 10px; }
.rep-kpis { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin: 12px 0; }
.rep-kpi {
  border: 1px solid var(--line); border-radius: 12px; padding: 12px;
  background: #fff; min-width: 0;
}
/* READABLE FIRST, the floor P035-C14 bought: .8rem is 12.8px and the rule is
   13px. A KPI label is the most-read text on this page and it is read at arm's
   length, in two scripts. */
.rep-kpi-label { font-size: .85rem; font-weight: 600; color: #4d463f; line-height: 1.3; }
.rep-kpi-value {
  font-size: 1.25rem; font-weight: 700; margin-top: 6px;
  font-variant-numeric: tabular-nums; overflow-wrap: anywhere;
}
.rep-kpi-note { font-size: .78rem; color: var(--text-muted); margin-top: 5px; line-height: 1.35; }
.rep-profit .rep-kpi { background: #fffdfb; border-color: #ead9c8; }

.rep-delta { font-size: .76rem; margin-top: 6px; display: flex; flex-wrap: wrap; gap: 4px; align-items: baseline; }
.rep-delta.up { color: var(--ok); }
.rep-delta.down { color: #a33a2a; }
.rep-delta.flat, .rep-delta.none { color: var(--text-muted); }
.rep-delta-note { color: var(--text-muted); }

.rep-tag {
  display: inline-block; font-size: .7rem; font-weight: 700; border-radius: 999px;
  padding: 1px 8px; background: #f4e9dd; color: #8a4a2a; border: 1px solid #e3cdb5;
  vertical-align: middle;
}

/* ---- alerts: one warm, one neutral, neither alarming ---- */
.rep-alert {
  border: 1px solid var(--line); border-inline-start: 3px solid var(--accent);
  border-radius: 10px; padding: 12px 14px; margin: 12px 0; background: #fff;
}
.rep-alert.warn { border-inline-start-color: #c0762a; background: #fffaf2; }
.rep-alert.info { border-inline-start-color: var(--accent); background: #fdfaf7; }
.rep-alert strong { display: block; font-size: .92rem; margin-bottom: 4px; }
.rep-alert p { margin: 4px 0; font-size: .85rem; color: var(--muted); line-height: 1.5; }
.rep-alert-detail { font-size: .8rem !important; }
.rep-alert .btn-outline { margin-top: 8px; display: inline-block; }
.rep-inline-warn {
  font-size: .8rem; color: #8a4a2a; background: #fffaf2;
  border: 1px solid #ead9c8; border-radius: 8px; padding: 8px 10px; margin: 8px 0 0;
}

/* ---- analysis panels ---- */
.rep-analysis { display: grid; gap: 12px; }
.rep-panel { border: 1px solid var(--line); border-radius: 12px; background: #fff; padding: 14px; }
.rep-panel-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.rep-panel-head h3 { margin: 0; font-size: .96rem; }
.rep-pill {
  font-size: .74rem; color: var(--muted); border: 1px solid var(--line);
  border-radius: 999px; padding: 2px 10px; white-space: nowrap;
}

.rep-chart { height: 130px; }
.rep-chart svg { width: 100%; height: 100%; display: block; }
.rep-area { fill: rgba(181, 100, 60, .14); stroke: none; }
.rep-line { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.rep-axis {
  display: flex; justify-content: space-between; margin-top: 6px;
  /* Chart-local, never page-wide: an SVG's x axis increases to the right in
     every language, so the labels for it must too. */
  direction: ltr;
}
.rep-axis-label { font-size: .72rem; color: var(--text-muted); }
.rep-data { margin-top: 10px; }
.rep-data summary { font-size: .82rem; color: var(--muted); cursor: pointer; min-height: 32px; padding: 6px 0; }
.rep-data .rep-table { margin-top: 6px; }

.rep-bars { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.rep-bar-top { display: flex; justify-content: space-between; gap: 10px; align-items: baseline; }
.rep-bar-label { font-size: .88rem; font-weight: 600; }
.rep-bar-value { font-size: .88rem; font-variant-numeric: tabular-nums; }
.rep-bar-track { height: 8px; border-radius: 999px; background: var(--surface-muted); margin: 6px 0 4px; overflow: hidden; }
.rep-bar-fill { height: 100%; border-radius: 999px; background: var(--accent); }
.rep-bar-sub { font-size: .76rem; color: var(--text-muted); }

/* ---- the card list: the primary form of every long list on a phone ---- */
.rep-cards-list { list-style: none; margin: 12px 0; padding: 0; display: grid; gap: 8px; }
.rep-item { border: 1px solid var(--line); border-radius: 12px; background: #fff; overflow: hidden; }
.rep-item.open { border-color: var(--border-strong); }
.rep-item-head {
  width: 100%; display: flex; align-items: flex-start; gap: 10px; text-align: start;
  border: 0; background: transparent; font: inherit; color: inherit;
  padding: 12px; cursor: pointer; min-height: 56px;
}
.rep-item-head.static { cursor: default; }
.rep-item-head:hover { background: #fdfbf8; }
.rep-item-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.rep-item-title { font-weight: 600; font-size: .92rem; overflow-wrap: anywhere; }
.rep-item-sub { font-size: .78rem; color: var(--text-muted); overflow-wrap: anywhere; }
.rep-item-figs { flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-end; gap: 4px; }
.rep-item-fig { display: flex; flex-direction: column; align-items: flex-end; font-size: .9rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.rep-item-fig em { font-style: normal; font-size: .74rem; font-weight: 400; color: var(--text-muted); }
.rep-item-badges { display: flex; flex-wrap: wrap; gap: 4px; justify-content: flex-end; }
.rep-item-chev { flex: 0 0 auto; color: var(--muted); font-size: .8rem; padding-top: 2px; }
.rep-item-body { padding: 0 12px 12px; border-top: 1px solid var(--line); }
.rep-dls { margin: 10px 0 0; display: grid; gap: 8px; }
.rep-dl { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; }
.rep-dl dt { font-size: .8rem; color: var(--text-muted); }
.rep-dl dd { margin: 0; font-size: .86rem; text-align: end; overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }

.rep-rank { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin: 12px 0 0; font-size: .82rem; color: var(--muted); }

.rep-empty {
  border: 1px dashed var(--line); border-radius: 10px;
  padding: 18px 14px; text-align: center; color: var(--muted);
  font-size: .88rem; background: #fdfcfa; margin: 12px 0;
}

.rep-row-muted td { color: var(--text-muted); }

/* AN IDENTIFIER IS NOT PROSE (HAT-03, HAT-07). A SKU and an order reference
   are single tokens a person reads out, types into a search box and compares
   character by character. `.rep-item-title` and the table cells allow a long
   word to break anywhere, which turned JO-00002 into "JO-" / "00002" and
   MAR-20260923-5263 into three pieces.

   nowrap keeps the token whole; the isolation keeps its characters in order
   inside an Arabic line. It is scoped to identifiers alone, so no product
   name, customer name or note loses its ability to wrap — the report does
   not get wider. */
.rep-id {
  direction: ltr;
  unicode-bidi: isolate;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
/* In the one place an identifier is the card's headline, it must not inherit
   the break-anywhere rule that heading otherwise needs for long product
   names. */
.rep-item-title .rep-id { overflow-wrap: normal; word-break: keep-all; }

/* Money, quantities, references and dates read the same way in both
   languages — the rule P035-C4 established and P035-C7 generalised. */
.rep-kpi [dir="ltr"], .rep-item [dir="ltr"], .rep-bars [dir="ltr"], .rep-alert [dir="ltr"] { unicode-bidi: isolate; }

/* THE DESKTOP TABLE DOES NOT EXIST ON A PHONE. Not "scrolls sideways" — it is
   not rendered at all, so it cannot widen the document and produce the
   horizontal overflow a 390px gate refuses. */
.rep-desk { display: none; }

@media (min-width: 720px) {
  .rep-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .rep-custom { grid-template-columns: repeat(4, minmax(0, 1fr)); max-width: 640px; }
  .rep-analysis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rep-panel-wide { grid-column: 1 / -1; }
  .rep-chart { height: 180px; }
  /* Below this width the sheet is a sheet; above it, a side panel that does
     not cover the report it is filtering. */
  .rep-sheet {
    inset-inline-start: auto; inset-inline-end: 0; top: 0; bottom: 0;
    width: 380px; max-height: none; border-radius: 0;
    border-inline-start: 1px solid var(--line); border-top: 0;
  }
}

@media (min-width: 1000px) {
  .rep-kpis { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .rep-profit { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  /* The card list gives way to the table, and vice versa. */
  .rep-cards-list { display: none; }
  .rep-desk { display: block; }
  .rep-rank { display: none; }
}

/* ==========================================================================
   CASH SALE V2 — THE SALE IS ALWAYS REACHABLE  (P035)
   --------------------------------------------------------------------------
   A phone shows one thing at a time. The catalogue is what the operator
   browses and the cart is what they are building, and before this the second
   scrolled away while they looked for the first — so they could not see what
   they had added, how many, or what it came to without leaving the search
   they were in the middle of.

   PHONE ONLY, BY CONSTRUCTION. Above the two-column breakpoint the cart is
   already beside the catalogue, and a second copy of a total is two places to
   read one number. The bar and the sheet are therefore not rendered at all on
   a desktop — display:none, not merely repositioned — so nothing can drift
   between them.
   ========================================================================== */
.pos-bar {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 60;
  background: var(--card);
  border-top: 1px solid var(--line);
  box-shadow: 0 -6px 20px rgba(0, 0, 0, .10);
  padding: 8px 12px calc(8px + env(safe-area-inset-bottom, 0px));
}
.pos-bar-main {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 56px;              /* a thumb, not a fingernail */
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--brand-primary-soft);
  color: var(--ink);
  font: inherit;
  text-align: start;
  cursor: pointer;
}
.pos-bar-main:hover { border-color: var(--border-strong); }
.pos-bar-left { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.pos-bar-title { font-weight: 700; font-size: .95rem; }
.pos-bar-sub { font-size: .78rem; color: var(--text-muted); }
.pos-bar-total {
  flex: 0 0 auto;
  font-weight: 700;
  font-size: 1.05rem;
  font-variant-numeric: tabular-nums;
  unicode-bidi: isolate;
}
.pos-bar-chev { flex: 0 0 auto; color: var(--muted); font-size: .8rem; }
/* AN EMPTY SALE OFFERS NO CHECKOUT, because a control that cannot work is
   worse than no control: it is tapped, and nothing happens. */
.pos-bar-empty {
  margin: 0;
  padding: 12px;
  text-align: center;
  font-size: .85rem;
  color: var(--muted);
  border: 1px dashed var(--line);
  border-radius: 12px;
  background: var(--surface-muted);
}

.pos-sheet-backdrop {
  position: fixed; inset: 0; z-index: 55;
  background: rgba(28, 22, 18, .42);
}

/* THE PHONE LAYOUT. The bar is fixed, so the page needs room beneath it or
   its last row is unreachable — the classic fixed-footer trap. */
@media (max-width: 759px) {
  .pos-shell { padding-bottom: 96px; }

  /* The cart becomes a sheet: closed it is out of the way, open it is the
     thing you are looking at, and it can never be taller than the screen. */
  .pos-cart {
    position: fixed;
    inset-inline: 0;
    bottom: 0;
    z-index: 61;
    margin: 0;
    max-height: 82vh;
    display: none;
    flex-direction: column;
    overflow-y: auto;
    border-radius: 16px 16px 0 0;
    border-top: 1px solid var(--line);
    box-shadow: 0 -10px 30px rgba(0, 0, 0, .18);
    padding-bottom: calc(14px + env(safe-area-inset-bottom, 0px));
  }
  .pos-cart.pos-cart-open { display: flex; }

  /* THE TOTAL AND THE COMPLETION ACTION DO NOT SCROLL AWAY. With twenty
     lines in the sale the operator must not have to reach the bottom of a
     list to find out what to charge, or what to press. */
  .pos-total-row,
  .pos-cart .pos-actions {
    position: sticky;
    bottom: 0;
    background: var(--card);
    border-top: 1px solid var(--line);
    padding-top: 10px;
    z-index: 1;
  }

  /* Cart lines stay compact so more of the sale is visible at once, and a
     long Arabic name wraps rather than pushing the figures off the row. */
  .pos-line { align-items: flex-start; }
  .pos-line-name { overflow-wrap: anywhere; }
}

/* ABOVE THE PHONE BREAKPOINT THE BAR AND THE SHEET DO NOT EXIST. */
@media (min-width: 760px) {
  .pos-bar, .pos-sheet-backdrop { display: none; }
  .pos-cart { position: static; max-height: none; display: block; }
}

/* CASH SALE V2 — the completed sale, read at a glance (P035).
   The receipt beneath is the customer's document; these two lines are the
   operator's answer: what was taken, and what left the shelf. */
.pos-done-total {
  margin: 4px 0 0;
  font-size: 1.9rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  unicode-bidi: isolate;
  color: var(--ink);
}
.pos-done-items {
  margin: 2px 0 12px;
  font-size: .88rem;
  color: var(--muted);
  overflow-wrap: anywhere;
}
