/* =========================================================================
   ApexPOS - Apple design layer                       loads after css/app.css
   -------------------------------------------------------------------------
   Additive only: nothing in app.css is edited, so removing the <link> and
   <script> lines in index.html returns the app to exactly how it was.

   1 foundations - 2 typography - 3 materials - 4 interaction
   5 presentation - 6 dark appearance - 7 accessibility
   ========================================================================= */

/* ---------- 1. Foundations ---------------------------------------------- */
:root{
  color-scheme: light;

  /* Motion. Real springs live in js/apple.js; these curves back the CSS-only
     parts. Response ~0.4s, critically damped - Apple fluid-interface values. */
  --ap-ease:        cubic-bezier(.32,.72,0,1);
  --ap-ease-out:    cubic-bezier(.22,1,.36,1);
  --ap-ease-bounce: cubic-bezier(.2,1.18,.32,1);
  --ap-press: 110ms;
  --ap-move:  400ms;
  --ap-sheet: 300ms;

  /* Materials - weight encodes hierarchy. Never stack thin on thin. */
  --ap-blur: 24px;
  --ap-sat: 180%;
  --ap-mat-thin:   rgba(255,255,255,.62);
  --ap-mat:        rgba(255,255,255,.76);
  --ap-mat-thick:  rgba(255,255,255,.88);
  --ap-sheet-mat:  rgba(255,255,255,.96);
  --ap-mat-edge:   rgba(255,255,255,.60);
  --ap-scrim:      rgba(14,17,22,.40);
  --ap-hairline:   rgba(16,20,26,.10);

  /* Elevation - a bigger surface reads thicker. */
  --ap-lift-1: 0 1px 2px rgba(16,20,26,.06), 0 1px 1px rgba(16,20,26,.04);
  --ap-lift-2: 0 8px 20px -10px rgba(16,20,26,.30), 0 2px 6px -3px rgba(16,20,26,.14);
  --ap-lift-3: 0 36px 68px -26px rgba(16,20,26,.46), 0 10px 26px -14px rgba(16,20,26,.26);
}

/* ---------- 2. Typography - tracking and leading follow size ------------- */
/* A single letter-spacing is wrong somewhere: large type wants negative
   tracking, small type wants a touch positive. */
h1.page,
.signin-brand h1,
.dash-hi{ letter-spacing:-.021em; line-height:1.08; }

.kcard-value,
.pos-balance .value,
.pay-total .v,
.pin-display,
.qb-totals .qb-trow.grand span:last-child,
.pos-signin-grid .pos-key.num{
  letter-spacing:-.018em;
  font-variant-numeric: tabular-nums;
  font-feature-settings:"tnum" 1;
}

.panel>header h2,
.modal>header h2{ letter-spacing:-.012em; }

/* Small, uppercase, tracked-out labels get a little more air, not less. */
.drawer-section,
table thead th,
.kcard-label{ letter-spacing:.085em; }

/* Money and counts must line up column to column. */
.money,.amount,.price,.total,
td.num,th.num,.c-price,.c-ext,.c-hand,
.qb-trow span:last-child,
.balance .v,.balance b{
  font-variant-numeric: tabular-nums;
  font-feature-settings:"tnum" 1;
}

/* ---------- 3. Materials - translucent chrome, content passes beneath ---- */
@media screen{

  /* Sticky topbar in the rail layout: content genuinely scrolls under it.
     This layout uses a light header on purpose (it sits beside the dark
     rail), so the material is a translucent version of that same surface -
     not the dark --header, which would leave dark text on a dark bar. */
  body.has-rail .topbar{
    background: color-mix(in srgb, var(--surface) 72%, transparent);
    -webkit-backdrop-filter: blur(var(--ap-blur)) saturate(var(--ap-sat));
    backdrop-filter: blur(var(--ap-blur)) saturate(var(--ap-sat));
    border-bottom-color: transparent;
  }

  /* Scroll edge effect: separation appears only once content is under the
     chrome - not a permanent 1px rule. .ap-scrolled is set by js/apple.js. */
  .topbar{
    transition: box-shadow var(--ap-move) var(--ap-ease),
                border-color var(--ap-move) var(--ap-ease),
                background var(--ap-move) var(--ap-ease);
  }
  body.has-rail .topbar.ap-scrolled{
    border-bottom-color: var(--line);
    box-shadow: 0 10px 22px -18px rgba(16,20,26,.55);
  }

  /* Vibrancy: text over a translucent surface needs a little more contrast
     and weight than the same text over a solid one. */
  body.has-rail .topbar .clock{ color: var(--ink); }
  body.has-rail .topbar .brand small,
  body.has-rail .topbar small{ color: var(--ink-2); font-weight:500; }

  /* Sticky table headers - the rows slide underneath them. */
  table thead th,
  .pos-basket thead th,
  .qb-row.qb-head{
    -webkit-backdrop-filter: blur(14px) saturate(var(--ap-sat));
    backdrop-filter: blur(14px) saturate(var(--ap-sat));
  }

  /* Sticky action bars float over the form they belong to. */
  .save-bar,
  .pos-balance{
    background: var(--ap-mat);
    -webkit-backdrop-filter: blur(var(--ap-blur)) saturate(var(--ap-sat));
    backdrop-filter: blur(var(--ap-blur)) saturate(var(--ap-sat));
    border-top: 1px solid var(--ap-mat-edge);
  }

  /* Toasts float free above everything - the smallest surface, lightest blur. */
  .toast{
    background: rgba(28,32,38,.82);
    -webkit-backdrop-filter: blur(18px) saturate(var(--ap-sat));
    backdrop-filter: blur(18px) saturate(var(--ap-sat));
    box-shadow: var(--ap-lift-2);
    border: 1px solid rgba(255,255,255,.10);
  }

  /* Drawer: a structural region, so a heavier material than a button. */
  .drawer{
    background: color-mix(in srgb, var(--header) 82%, transparent);
    -webkit-backdrop-filter: blur(30px) saturate(var(--ap-sat));
    backdrop-filter: blur(30px) saturate(var(--ap-sat));
    border-right: 1px solid rgba(255,255,255,.10);
    box-shadow: var(--ap-lift-3);
  }
  .drawer-scrim{ background: var(--ap-scrim); }
}

/* ---------- 4. Interaction - feedback on press, not on release ---------- */
/* js/apple.js sets .ap-press on pointerdown so touch feels as instant as
   mouse; :active covers the keyboard and no-JS paths. */
.btn, .tile, .pos-key, .qb-tender, .qb-action, .qb-side, .qb-tool,
.drawer-link, .rail-key, .page-nav-item, .nav button, .cats button,
button.primary, .kcard, .qb-tab{
  -webkit-tap-highlight-color: transparent;
  /* Background stays quick: a hover that takes 400ms to arrive reads as lag,
     not polish. Only the press transform gets the softer curve. */
  transition: transform var(--ap-press) var(--ap-ease-out),
              filter    var(--ap-press) var(--ap-ease-out),
              background 150ms var(--ap-ease);
}

/* Held for one frame while the appearance swaps, so nothing animates
   between two palettes. Set by js/apple.js. */
:root.ap-theming,
:root.ap-theming *,
:root.ap-theming *::before,
:root.ap-theming *::after{
  transition: none !important;
  animation: none !important;
}
.btn.ap-press, .tile.ap-press, .pos-key.ap-press, .qb-tender.ap-press,
.qb-action.ap-press, .qb-side.ap-press, .qb-tool.ap-press, .kcard.ap-press,
button.primary.ap-press, .cats button.ap-press{
  transform: scale(.972);
  filter: brightness(.97);
}
.drawer-link.ap-press, .rail-key.ap-press,
.page-nav-item.ap-press, .nav button.ap-press, .qb-tab.ap-press{
  transform: scale(.985);
}
/* Disabled controls must not pretend to respond. */
.ap-press:disabled, :disabled.ap-press{ transform:none; filter:none; }

/* Keys on a till are hit at speed, often with a thumb - give them real size. */
@media screen and (pointer:coarse){
  .pos-key, .qb-tender, .qb-side, .btn{ min-height:44px; }
}

/* One focus treatment, visible on every surface including brand colour. */
:focus-visible{
  outline:2px solid var(--brand);
  outline-offset:2px;
  border-radius:6px;
}
.topbar :focus-visible, .drawer :focus-visible, .qb-win:focus-visible{
  outline-color:#fff;
}

/* ---------- 5. Presentation - sheets that arrive as material ------------- */
@media screen{
  /* The scrim is a plain dim, deliberately with no blur of its own: a
     backdrop-filter here would nest inside the sheet's own one and cancel
     it, leaving a see-through form over live page content. One material
     per stack. */
  .backdrop{ background: var(--ap-scrim); }

  /* A dialog is a large, text-heavy surface, so it takes the thickest
     material and the deepest shadow - legibility first, translucency only
     as a hint of what is behind. */
  .modal{
    background: var(--ap-sheet-mat);
    -webkit-backdrop-filter: blur(40px) saturate(var(--ap-sat));
    backdrop-filter: blur(40px) saturate(var(--ap-sat));
    border:1px solid var(--ap-mat-edge);
    box-shadow: var(--ap-lift-3);
    border-radius:18px;
  }
  .modal>header{ border-bottom:1px solid var(--ap-hairline); }
  .modal>footer{ border-top:1px solid var(--ap-hairline); background:transparent; }

  /* Materialize, do not just fade: blur and scale arrive together. */
  .backdrop.ap-in{ animation: ap-scrim-in 260ms var(--ap-ease-out) both; }
  .backdrop.ap-in>.modal{ animation: ap-sheet-in var(--ap-sheet) var(--ap-ease) both; }
  @keyframes ap-scrim-in{ from{opacity:0} to{opacity:1} }
  @keyframes ap-sheet-in{
    from{ opacity:0; transform:scale(.965) translateY(8px); filter:blur(6px); }
    to  { opacity:1; transform:none;                        filter:blur(0);   }
  }

  .ap-grabber{ display:none; }

  /* Narrow screens present the same dialog as a bottom sheet - so it gets a
     grabber, and it dismisses down the way it came in (js/apple.js). */
  @media (max-width:700px){
    .modal{ border-radius:20px 20px 0 0; }
    .backdrop.ap-in>.modal{ animation-name: ap-sheet-up; }
    @keyframes ap-sheet-up{
      from{ opacity:0; transform:translateY(14%); }
      to  { opacity:1; transform:none; }
    }
    .ap-grabber{
      display:block;
      width:38px; height:5px; border-radius:999px;
      background: var(--ink-3); opacity:.35;
      margin:8px auto 0; flex:0 0 auto;
      touch-action:none; cursor:grab;
    }
    .modal.ap-dragging{ transition:none; cursor:grabbing; }
  }
}

/* Appearance control injected into the topbar by js/apple.js. */
.ap-appearance{ position:relative; display:inline-flex; }
/* The topbar is dark in the till layout and light in the rail layout, so the
   control takes its colour from whichever bar it lands in rather than
   assuming one of them. */
.ap-appearance-btn{
  width:34px; height:34px; display:inline-flex; align-items:center;
  justify-content:center; border:0; border-radius:999px; cursor:pointer;
  color: inherit;
  background: color-mix(in srgb, currentColor 12%, transparent);
  transition:background var(--ap-move) var(--ap-ease),
             transform var(--ap-press) var(--ap-ease-out);
}
.ap-appearance-btn:hover{ background: color-mix(in srgb, currentColor 22%, transparent); }
body.has-rail .topbar .ap-appearance-btn{ color: var(--ink-2); }
body.has-rail .topbar .ap-appearance-btn:hover{ color: var(--ink); }

/* ---------- Settings: one page, no category rail ------------------------
   The rail showed one section at a time, which made every visit a two-step:
   find the category, then read the setting. Settings is now a single page
   you scroll, and the search box still narrows it. js/sectors.js does the
   matching half - it un-hides the sections the rail used to keep closed. */
.with-nav > .settings-rail{ display:none; }
/* Both forms: the app sets the column width on `.with-nav` and again, more
   specifically, on `body.has-rail .with-nav`. */
.with-nav:has(> .settings-rail),
body.has-rail .with-nav:has(> .settings-rail){ grid-template-columns:minmax(0,1fr); }

/* ---------- Till: more room for the receipt lines -----------------------
   The list of scanned items is the part of the counter screen a cashier
   actually reads, so the chrome around it gives height back. Nothing is
   removed - it is all padding and leading. */
.qb-doc-title{ padding:7px 16px 5px; font-size:17px; }
.qb-tabs{ min-height:32px; padding-top:3px; }

/* The payment row and the totals sit side by side, and the taller of the two
   sets the height. Trimming the tenders alone would change nothing while the
   totals column stands taller, so both come down together. */
.qb-tenders{ gap:8px; }
.qb-tender{ min-height:42px; padding:6px 9px; }
.qb-lower-left{ gap:8px; }

.qb-totals{ padding:7px 14px; gap:2px; }
.qb-totals .qb-trow{ line-height:17px; }
.qb-totals .qb-trow.grand{ margin-top:2px; padding-top:6px; line-height:1.15; }

/* A finger needs a bigger target than a mouse pointer does, so a touch till
   keeps the full-size keys and pays for them out of the receipt instead. */
@media screen and (pointer:coarse){
  .qb-tender{ min-height:48px; padding:8px 10px; }
}

/* ---------- Dialogs: keep them one column -------------------------------
   The shell layout places the top bar, the notice bar and main in the second
   column of the page grid, but its selector - body.has-rail .banner - is not
   scoped to the shell. Any notice inside a dialog is caught by it too, and a
   child explicitly placed in column 2 makes the dialog body grow a second
   column it was never designed for: fields end up in one column and the text
   explaining them in the other, with a hole between. Notices inside a dialog
   flow with everything else. */
body.has-rail .backdrop .banner,
body.has-rail .modal .banner{ grid-column:auto; }

/* ---------- Print: nothing but the receipt ------------------------------
   The "a new version of the till is ready" bar is appended straight to
   <body> with no class of its own, so the app's print rules - which hide
   .shell - have nothing to select and it prints under every receipt a
   customer is handed. Anything that turns up at body level is excluded,
   except the dialog the receipt is inside and the dedicated print root, so
   a future stray element cannot end up on a customer's receipt either. */
@media print{
  body > div:not(#app):not(#print-root):not(.backdrop){ display:none !important; }
}

/* ---------- Sign-on: hold the layout still ------------------------------
   The hint under the heading is two lines while it asks for an operator ID
   and one line once it knows who you are. The card is centred, so that lost
   line used to pull the field and the keypad up by ten pixels the moment you
   pressed Enter - the keys moving out from under a finger already on its way
   down. Reserving both lines keeps everything where it was. */
.pos-signin .signin-main > p.tiny.muted{
  min-height:40px;
  min-height:2lh;
}

/* ---------- Shop type (sector packs) ------------------------------------ */
.ap-sector-grid{
  display:grid; gap:12px;
  grid-template-columns:repeat(auto-fit, minmax(232px, 1fr));
  margin-top:14px;
}
.ap-sector-card{
  position:relative; display:grid; gap:5px; align-content:start;
  text-align:left; cursor:pointer;
  padding:16px 16px 18px;
  border-radius:14px;
  border:1px solid var(--line);
  background:var(--surface);
  color:var(--ink);
  font:inherit;
  box-shadow:var(--ap-lift-1);
  transition:border-color 150ms var(--ap-ease),
             background 150ms var(--ap-ease),
             transform var(--ap-press) var(--ap-ease-out),
             box-shadow 150ms var(--ap-ease);
}
.ap-sector-card:hover:not(:disabled){ border-color:var(--brand); box-shadow:var(--ap-lift-2); }
.ap-sector-card:disabled{ opacity:.55; cursor:default; box-shadow:none; }
.ap-sector-card:active{ transform:scale(.985); }
.ap-sector-card.is-on{
  border-color:var(--brand);
  background:var(--brand-wash);
  box-shadow:0 0 0 1px var(--brand) inset;
  cursor:default;
}
.ap-sector-glyph{ font-size:22px; line-height:1; }
.ap-sector-name{ font-weight:750; font-size:15px; letter-spacing:-.008em; }
.ap-sector-blurb{ font-size:12.5px; line-height:1.45; color:var(--ink-2); }
.ap-sector-badge{
  position:absolute; top:12px; right:12px;
  font-size:10.5px; font-weight:800; letter-spacing:.075em; text-transform:uppercase;
  padding:3px 8px; border-radius:999px;
  background:var(--brand); color:var(--brand-ink, #fff);
}

/* The change list in the confirmation - what it is, and what it becomes. */
.ap-sector-list{ margin:6px 0 0; padding:0; list-style:none; display:grid; gap:1px;
  border:1px solid var(--line); border-radius:11px; overflow:hidden; background:var(--line); }
.ap-sector-list li{
  display:flex; align-items:baseline; justify-content:space-between; gap:14px;
  padding:9px 12px; background:var(--surface); font-size:13px;
}
.ap-sector-key{ color:var(--ink); font-weight:600; }
.ap-sector-move{ color:var(--ink-2); white-space:nowrap; font-variant-numeric:tabular-nums; }

/* Open-shift prompt in the till's empty receipt area. The blocked action and
   the way to unblock it belong in the same place. */
/* Open shift, in the empty space at the foot of the till's left rail. It
   matches the rail's own buttons, with just enough weight to be found when
   selling is blocked. */
.qb-side-list .ap-shift-rail{
  margin-top:auto;                    /* sit at the bottom of the free space */
  font-weight:700;
  color:var(--brand);
  background:var(--brand-soft);
  border-top:1px solid var(--brand-line);
}
.qb-side-list .ap-shift-rail:hover:not(:disabled){
  background:color-mix(in srgb, var(--brand) 22%, var(--surface));
}

/* The open-shift chip stays a way in once the shift is running, so it has to
   look like one. */
.qb-status .qb-stat.ap-actionable{
  cursor:pointer;
  transition: filter var(--ap-press) var(--ap-ease-out),
              transform var(--ap-press) var(--ap-ease-out);
}
.qb-status .qb-stat.ap-actionable:hover{ filter:brightness(1.06); }
.qb-status .qb-stat.ap-actionable:active{ transform:scale(.97); }

/* In the counter screen the control sits in a compact menu bar, so it is
   sized to that bar rather than to the roomier shell topbar. */
.ap-appearance.ap-in-till{ margin-left:auto; }
.ap-appearance.ap-in-till .ap-appearance-btn{ width:26px; height:26px; }
.ap-appearance.ap-in-till .ap-appearance-btn svg{ width:16px; height:16px; }
.ap-appearance.ap-in-till .ap-menu{ top:calc(100% + 6px); }
.ap-appearance-btn.ap-press{ transform:scale(.92); }
.ap-appearance-btn svg{ width:19px; height:19px; }
.ap-menu{
  position:absolute; top:calc(100% + 8px); right:0; z-index:200;
  min-width:206px; padding:6px;
  border-radius:14px;
  background:var(--ap-mat-thick);
  -webkit-backdrop-filter:blur(30px) saturate(var(--ap-sat));
  backdrop-filter:blur(30px) saturate(var(--ap-sat));
  border:1px solid var(--ap-mat-edge);
  box-shadow:var(--ap-lift-3);
  /* Anchored to the control that opened it. */
  transform-origin: top right;
  animation: ap-menu-in 220ms var(--ap-ease-out) both;
}
@keyframes ap-menu-in{
  from{ opacity:0; transform:scale(.94) translateY(-4px); }
  to  { opacity:1; transform:none; }
}
.ap-menu[hidden]{ display:none !important; }
.ap-menu-label{
  font-size:11px; font-weight:800; letter-spacing:.085em;
  text-transform:uppercase; color:var(--ink-3); padding:8px 10px 4px;
}
.ap-menu-item{
  width:100%; display:flex; align-items:center; gap:9px;
  padding:9px 10px; border:0; border-radius:9px; background:transparent;
  color:var(--ink); font:inherit; font-size:14px; font-weight:600;
  text-align:left; cursor:pointer;
  transition:background var(--ap-press) var(--ap-ease-out);
}
.ap-menu-item:hover{ background:color-mix(in srgb, var(--ink) 8%, transparent); }
.ap-menu-item[aria-checked="true"]{ color:var(--brand); }
.ap-menu-item .ap-tick{ margin-left:auto; opacity:0; }
.ap-menu-item[aria-checked="true"] .ap-tick{ opacity:1; }
.ap-menu-sep{ height:1px; margin:6px 4px; background:var(--ap-hairline); }

/* =========================================================================
   6. Dark appearance
   Screen only - printed receipts and reports stay ink on white paper.
   js/apple.js resolves auto/light/dark to data-theme on <html>.
   ========================================================================= */
@media screen{
:root[data-theme="dark"]{
  color-scheme: dark;

  --bg:        #0C0E12;
  --surface:   #15181E;
  --surface-2: #1C2029;
  --ink:       #F2F5F9;
  --ink-2:     #AEB8C4;
  --ink-3:     #7C8794;
  --line:      #282D37;
  --shadow:    0 1px 2px rgba(0,0,0,.55);
  --shop-ground:#101317;

  /* Apple dark system colours: brighter, so they hold contrast on black. */
  --ok:     #30D158;
  --danger: #FF453A;
  --warn:   #FF9F0A;

  /* branding.js writes --brand-soft inline from the shop colour, and an
     inline style beats a stylesheet - so this one tint is reclaimed with
     !important. The shop's own --brand is deliberately left untouched. */
  --brand-soft: color-mix(in srgb, var(--brand) 24%, #0C0E12) !important;
  --brand-wash: color-mix(in srgb, var(--brand) 13%, #15181E);
  --brand-line: color-mix(in srgb, var(--brand) 42%, #15181E);
  --ok-soft:     color-mix(in srgb, var(--ok)     20%, #0C0E12);
  --danger-soft: color-mix(in srgb, var(--danger) 20%, #0C0E12);
  --warn-soft:   color-mix(in srgb, var(--warn)   20%, #0C0E12);
  --primary-light: color-mix(in srgb, var(--brand) 30%, #0C0E12);
  --info-soft:     color-mix(in srgb, var(--info)  22%, #0C0E12);
  --line-strong: #39424F;

  /* Shadows were tuned for ink on paper; on a dark screen they need depth,
     not grey haze. */
  --shadow-input:   0 2px 8px rgba(0,0,0,.45);
  --shadow-md:      0 10px 28px rgba(0,0,0,.55);
  --shadow-lg:      0 40px 90px rgba(0,0,0,.75);
  --shadow-primary: 0 8px 20px rgba(0,0,0,.50);

  /* The legacy till exposes its whole palette through --shop-*, so the
     counter screen re-themes from these nine values rather than from a
     pile of per-element overrides. */
  --shop-ground:    #0F1216;
  --shop-wash:      #1A1F27;
  --shop-rule:      #2B323D;
  --shop-tab:       #232935;
  --shop-tabhover:  #2C3340;
  --shop-hover:     #1E242E;
  --shop-sel:       #17351F;
  --shop-face:      #1C2029;
  --shop-facehover: #242A35;

  --ap-mat-thin:  rgba(28,32,40,.62);
  --ap-mat:       rgba(24,28,35,.76);
  --ap-mat-thick: rgba(26,30,38,.88);
  --ap-sheet-mat: rgba(22,26,33,.96);
  --ap-mat-edge:  rgba(255,255,255,.10);
  --ap-scrim:     rgba(0,0,0,.58);
  --ap-hairline:  rgba(255,255,255,.09);
  --ap-lift-1: 0 1px 2px rgba(0,0,0,.45);
  --ap-lift-2: 0 8px 20px -10px rgba(0,0,0,.70), 0 2px 6px -3px rgba(0,0,0,.50);
  --ap-lift-3: 0 36px 68px -26px rgba(0,0,0,.85), 0 10px 26px -14px rgba(0,0,0,.60);
}

/* --- surfaces that were hard-coded white ------------------------------- */
:root[data-theme="dark"] .qb-dropdown,
:root[data-theme="dark"] .qb-user,
:root[data-theme="dark"] .qb-scan,
:root[data-theme="dark"] .qb-customer,
:root[data-theme="dark"] .qb-lines,
:root[data-theme="dark"] .qb-tab.active,
:root[data-theme="dark"] .qb-navrow .qb-tab.active,
:root[data-theme="dark"] .qb-tabmenu.open .qb-tab,
:root[data-theme="dark"] .qb-open .backdrop .grid,
:root[data-theme="dark"] .pos-signin .pin-field .pin-display,
:root[data-theme="dark"] .pos-signin-grid .pos-key.num{
  background: var(--surface); color: var(--ink);
}
:root[data-theme="dark"] .signin-card.pos-signin{ background: var(--surface); }
:root[data-theme="dark"] .qb-action{
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  color: var(--ink);
}

/* --- zebra striping, hovers, selection -------------------------------- */
:root[data-theme="dark"] .qb-row:nth-child(2n):not(.qb-head),
:root[data-theme="dark"] .qb-open .backdrop .tile:nth-child(2n){
  background: var(--surface-2);
}
:root[data-theme="dark"] .btn:hover:not(:disabled),
:root[data-theme="dark"] .qb-action:hover:not(:disabled),
:root[data-theme="dark"] .qb-tool:hover:not(:disabled),
:root[data-theme="dark"] .qb-side:hover:not(:disabled),
:root[data-theme="dark"] .qb-side-foot .qb-side:hover:not(:disabled),
:root[data-theme="dark"] .qb-lines .qb-row:hover:not(.qb-head),
:root[data-theme="dark"] .pos-signin-grid .pos-key.num:hover:not(:disabled){
  background: color-mix(in srgb, #fff 8%, var(--surface));
}
:root[data-theme="dark"] .pos-signin-grid .pos-key.num:active:not(:disabled){
  background: color-mix(in srgb, #fff 13%, var(--surface));
}
:root[data-theme="dark"] .qb-lines .qb-row.selected,
:root[data-theme="dark"] .qb-rowtools,
:root[data-theme="dark"] .qb-tender:hover:not(:disabled),
:root[data-theme="dark"] .qb-tender.momo:hover:not(:disabled),
:root[data-theme="dark"] .signin-trust{
  background: var(--brand-soft);
}
:root[data-theme="dark"] .qb-tab,
:root[data-theme="dark"] .qb-tabs .qb-tab,
:root[data-theme="dark"] .pos-signin-grid .pos-key.util,
:root[data-theme="dark"] .pos-signin-grid .pos-key.action{
  background: var(--surface-2); color: var(--ink-2);
}
:root[data-theme="dark"] .pos-signin-grid .pos-key.util:hover:not(:disabled),
:root[data-theme="dark"] .pos-signin-grid .pos-key.action:hover:not(:disabled),
:root[data-theme="dark"] .qb-tabs .qb-tab:hover{
  background: color-mix(in srgb, var(--brand) 30%, var(--surface-2));
  color: var(--ink);
}
:root[data-theme="dark"] .signin-avatar{
  background: var(--brand-soft); color: var(--ink);
}

/* --- disabled states --------------------------------------------------- */
:root[data-theme="dark"] .btn:disabled,
:root[data-theme="dark"] .qb-side:disabled,
:root[data-theme="dark"] .qb-tender:disabled,
:root[data-theme="dark"] .qb-tender.momo:disabled,
:root[data-theme="dark"] .qb-action:disabled,
:root[data-theme="dark"] .qb-action.primary:disabled,
:root[data-theme="dark"] .pos-key:disabled,
:root[data-theme="dark"] .pos-key.num:disabled,
:root[data-theme="dark"] .pos-key.accent:disabled,
:root[data-theme="dark"] .pos-key.danger:disabled,
:root[data-theme="dark"] input:disabled,
:root[data-theme="dark"] select:disabled,
:root[data-theme="dark"] textarea:disabled{
  background: var(--surface-2); color: var(--ink-3);
  border-color: var(--line);
}

/* --- text that was hard-coded dark ------------------------------------- */
:root[data-theme="dark"] .qb,
:root[data-theme="dark"] .qb-menutitle,
:root[data-theme="dark"] .qb-menuitem,
:root[data-theme="dark"] .qb-tab.active,
:root[data-theme="dark"] .qb-tabmenu.open .qb-tab,
:root[data-theme="dark"] .qb-user,
:root[data-theme="dark"] .qb-trow.grand,
:root[data-theme="dark"] .qb-open .backdrop .tile-price{ color: var(--ink); }

:root[data-theme="dark"] .qb-clock,
:root[data-theme="dark"] .qb-tab,
:root[data-theme="dark"] .qb-row.qb-head,
:root[data-theme="dark"] .qb-trow,
:root[data-theme="dark"] .qb-status,
:root[data-theme="dark"] .qb-open .backdrop .tile-meta,
:root[data-theme="dark"] .signin-trust p,
:root[data-theme="dark"] .signin-foot,
:root[data-theme="dark"] .signin-status,
:root[data-theme="dark"] .foot-ic,
:root[data-theme="dark"] table thead th,
:root[data-theme="dark"] .btn{ color: var(--ink-2); }

:root[data-theme="dark"] .pos-signin-grid .pos-key.util,
:root[data-theme="dark"] .pos-signin-grid .pos-key.action{
  color: color-mix(in srgb, var(--brand) 55%, #fff);
}

/* Status text on tinted chips: lift to the dark-mode system colours. */
:root[data-theme="dark"] .pill.ok,   :root[data-theme="dark"] .tag.ok,
:root[data-theme="dark"] .balance.change, :root[data-theme="dark"] .banner.ok,
:root[data-theme="dark"] .qb-stat.ok{ color: var(--ok); }
:root[data-theme="dark"] .pill.warn, :root[data-theme="dark"] .tag.warn,
:root[data-theme="dark"] .banner.warn, :root[data-theme="dark"] .lock-note,
:root[data-theme="dark"] .balance.due, :root[data-theme="dark"] .line-onhand.warn,
:root[data-theme="dark"] .tile-expiry.warn, :root[data-theme="dark"] .today-row.warn,
:root[data-theme="dark"] .qb-stat.warn{ color: var(--warn); }
:root[data-theme="dark"] .pill.bad,  :root[data-theme="dark"] .tag.bad,
:root[data-theme="dark"] .banner.bad, :root[data-theme="dark"] .banner.err,
:root[data-theme="dark"] .line-onhand.bad,
:root[data-theme="dark"] .qb-row .c-hand.short{ color: var(--danger); }
:root[data-theme="dark"] .banner.info{
  color: color-mix(in srgb, var(--brand) 45%, #fff);
}
:root[data-theme="dark"] .qb-stat.act{
  background: var(--warn-soft); color: var(--warn);
}
:root[data-theme="dark"] .qb-stat.act:hover,
:root[data-theme="dark"] .qb-status .open-shift:hover{
  background: color-mix(in srgb, var(--warn) 30%, #0C0E12);
}
:root[data-theme="dark"] .rail-badge{ background: var(--danger-soft); color: var(--danger); }
:root[data-theme="dark"] .qb-open .backdrop .badge-promo{
  background: var(--surface-2); color: var(--ink-2);
}

/* The sign-on illustration has its white page baked into the PNG. On a dark
   card it would glare, so it is dimmed and framed - it reads as a picture on
   the surface rather than a hole cut out of it. */
:root[data-theme="dark"] img.signin-art{
  filter: brightness(.62) saturate(.85) contrast(1.06);
  border-radius: var(--radius-lg, 14px);
}

/* A receipt is paper. It stays white in every appearance, on screen and in
   print, so what the cashier previews is what the printer produces. */
:root[data-theme="dark"] .receipt,
:root[data-theme="dark"] .receipt-preview{ background:#fff; color:#000; }
}

/* =========================================================================
   7. Accessibility - reduced motion, transparency and contrast
   ========================================================================= */
@media (prefers-reduced-motion: reduce){
  .backdrop.ap-in,
  .backdrop.ap-in>.modal,
  .ap-menu{ animation: ap-fade 160ms ease both; }
  @keyframes ap-fade{ from{opacity:0} to{opacity:1} }
  .ap-press{ transform:none !important; }
}

@media (prefers-reduced-transparency: reduce){
  .modal, .ap-menu, .save-bar, .pos-balance, .toast,
  body.has-rail .topbar, .drawer,
  table thead th, .pos-basket thead th, .qb-row.qb-head{
    -webkit-backdrop-filter:none !important;
    backdrop-filter:none !important;
  }
  .modal, .ap-menu{ background: var(--surface); }
  .save-bar, .pos-balance{ background: var(--surface); }
  .toast{ background: var(--ink); }
  body.has-rail .topbar{ background: var(--surface); }
  .drawer{ background: var(--header); }
  .backdrop{ background: rgba(14,17,22,.72); }
}

@media (prefers-contrast: more){
  :root{ --ap-hairline: rgba(16,20,26,.34); }
  .modal, .ap-menu, .panel, .toast{
    border:1px solid var(--ink-2);
    -webkit-backdrop-filter:none; backdrop-filter:none;
    background: var(--surface);
  }
  :focus-visible{ outline-width:3px; }
}

/* -------------------------------------------------------------------------
   The chosen period chip, in the dark.

   app.css paints the selected chip `background: var(--ink); color:#fff`.
   In the light theme --ink is nearly black and that reads well; in the dark
   theme --ink is nearly white, so the label went white on white and the
   selected period could not be read at all. Found on the accounting screen,
   but it is the same component Reports uses, so this fixes both.
------------------------------------------------------------------------- */
:root[data-theme="dark"] .cats button[aria-pressed="true"]{
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
}
