/* =========================================================
   DeepestTrack design tokens
   Palette: deep berry-plum for authority, warm gold for
   value, a blush swatch strip as the recurring signature motif.
   ========================================================= */
:root{
  --bg: #FBF6F4;
  --surface: #FFFFFF;
  --ink: #2A1E27;
  --muted: #8C7A86;
  --border: #ECE1E4;

  --plum: #5C2748;
  --plum-dark: #3C1830;
  --plum-light: #7A3A63;
  --gold: #C6963F;
  --gold-light: #F1DCB0;
  --blush: #F2D9E1;
  --blush-deep: #E3AFC4;

  --success: #3E8F5F;
  --success-bg: #E7F5EC;
  --danger: #C0453B;
  --danger-bg: #FBEAE8;
  --warning: #C7862B;
  --warning-bg: #FCF0DF;
  --info: #396C9E;
  --info-bg: #E7F0FA;

  --radius: 10px;
  --radius-sm: 6px;
  --shadow: 0 2px 10px rgba(60,24,48,0.06), 0 1px 2px rgba(60,24,48,0.05);
  --shadow-lg: 0 12px 32px rgba(60,24,48,0.14);
  --font-display: 'Fraunces', serif;
  --font-body: 'Inter', system-ui, sans-serif;
}

/* Disable double-tap-to-zoom on the POS and Image Calculator pages only —
   cashiers tapping product tiles/buttons quickly during a sale can
   accidentally trigger the browser's double-tap zoom gesture. This does
   NOT disable pinch-to-zoom (still available if genuinely needed), only
   the accidental double-tap kind. Scoped via the page-specific body
   class set in includes/header.php, so other pages are unaffected. */
body.page-pos, body.page-calculator_pos{
  touch-action: manipulation;
}

*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
body{
  font-family: var(--font-body);
  background: var(--bg);
  color: var(--ink);
  font-size: 14.5px;
  line-height: 1.5;
}
h1,h2,h3,.display{ font-family: var(--font-display); letter-spacing:-0.01em; }
a{ color: var(--plum); text-decoration:none; }
.muted{ color: var(--muted); }

/* ---------- Swatch strip signature motif ---------- */
.swatch-strip{ display:flex; gap:4px; }
.swatch-strip span{ width:8px; height:8px; border-radius:50%; display:inline-block; }
.swatch-strip span:nth-child(1){ background: var(--blush-deep); }
.swatch-strip span:nth-child(2){ background: var(--gold); }
.swatch-strip span:nth-child(3){ background: var(--plum-light); }

/* ================= AUTH PAGE ================= */
.auth-body{ background: linear-gradient(135deg, var(--plum-dark), var(--plum) 60%, var(--plum-light)); min-height:100vh; }
.auth-wrap{ display:grid; grid-template-columns: 1.1fr 1fr; max-width:960px; margin:0 auto; min-height:100vh; align-items:center; gap:0; }
.auth-brand{ color:#fff; padding:40px; }
.auth-brand-mark{ width:56px;height:56px;border-radius:14px; object-fit:cover; display:block; margin-bottom:22px;}
.auth-brand h1{ font-size:38px; margin:0 0 10px; }
.auth-brand p{ color: var(--blush); margin:0 0 20px; max-width:320px; }
.auth-points{ list-style:none; padding:0; margin:0; display:flex; flex-direction:column; gap:10px; }
.auth-points li{ padding-left:22px; position:relative; color:#EFDFE8; font-size:13.5px; }
.auth-points li::before{ content:'✓'; position:absolute; left:0; color:var(--gold); font-weight:700; }
.auth-card{ background:var(--surface); border-radius:18px; padding:40px 36px; box-shadow: var(--shadow-lg); margin:24px; }
.auth-card h2{ margin:0 0 4px; font-size:26px; }
.auth-card form{ margin-top:20px; display:flex; flex-direction:column; gap:12px; }
.auth-card label{ font-size:12.5px; font-weight:600; color:var(--muted); text-transform:uppercase; letter-spacing:.04em; }
.password-field{ display:flex; align-items:center; border:1px solid var(--border); border-radius:var(--radius-sm); background:#fff; }
.password-field input{ border:none; background:transparent; flex:1; width:auto; min-width:0; }
.password-field input:focus{ outline:none; }
.password-field:focus-within{ outline:2px solid var(--plum-light); outline-offset:1px; }
.password-toggle{ background:none; border:none; cursor:pointer; font-size:16px; padding:6px 12px 6px 4px; color:var(--muted); line-height:1; flex:none; }
.password-toggle:hover{ color:var(--ink); }
.hint{ font-size:12px; color:var(--muted); margin-top:16px; }
@media (max-width: 760px){ .auth-wrap{ grid-template-columns:1fr; } .auth-brand{ text-align:center; display:flex; flex-direction:column; align-items:center;} }

/* ================= FORM CONTROLS ================= */
input, select, textarea{
  font-family: var(--font-body);
  font-size: 14px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: #fff;
  color: var(--ink);
  width: 100%;
}
input[type="checkbox"], input[type="radio"]{
  width: 16px;
  height: 16px;
  padding: 0;
  flex: none;
  cursor: pointer;
}
/* The login field the server says is wrong */
input.input-error, .password-field.input-error{ border-color:var(--danger) !important; box-shadow:0 0 0 3px var(--danger-bg) !important; }
input:focus, select:focus, textarea:focus{
  outline: 2px solid var(--plum-light);
  outline-offset: 1px;
  border-color: var(--plum-light);
}
label{ display:block; font-size:12.5px; font-weight:600; color:var(--muted); margin-bottom:4px; }
.field{ margin-bottom:14px; }
.form-row{ display:flex; gap:14px; flex-wrap:wrap; }
.form-row > *{ flex:1; min-width:160px; }

/* ================= SEARCH AUTOCOMPLETE ================= */
.ac-wrap{ position:relative; }
.ac-wrap.has-selection input{ background:var(--blush); border-color:var(--blush-deep); font-weight:600; color:var(--plum-dark); }
.ac-clear{
  position:absolute; right:8px; top:50%; transform:translateY(-50%);
  background:none; border:none; color:var(--muted); cursor:pointer; font-size:16px;
  line-height:1; padding:2px 4px; display:none;
}
.ac-wrap.has-selection .ac-clear{ display:block; }
.ac-dropdown{
  position:absolute; top:calc(100% + 4px); left:0; right:0; z-index:50;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-sm);
  box-shadow:var(--shadow-lg); max-height:280px; overflow-y:auto; display:none;
}
.ac-dropdown.open{ display:block; }
.ac-item{ padding:8px 12px; cursor:pointer; font-size:13.5px; display:flex; align-items:center; gap:8px; border-bottom:1px solid var(--border); }
.ac-item:last-child{ border-bottom:none; }
.ac-item:hover, .ac-item.active{ background:var(--blush); }
.ac-item .ac-tag{ font-size:10px; text-transform:uppercase; letter-spacing:.03em; color:var(--muted); font-weight:700; min-width:44px; }
.ac-item .ac-label{ flex:1; color:var(--ink); }
.ac-empty{ padding:10px 12px; font-size:13px; color:var(--muted); }

/* ================= BUTTONS ================= */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:6px;
  padding: 10px 18px; border-radius: var(--radius-sm); border:1px solid transparent;
  font-weight:600; font-size:13.5px; cursor:pointer; transition:.15s ease;
}
.btn-primary{ background: var(--plum); color:#fff; }
.btn-primary:hover{ background: var(--plum-dark); }
.btn-gold{ background: var(--gold); color: var(--plum-dark); }
.btn-gold:hover{ background:#B98630; }
.btn-outline{ background:transparent; border-color: var(--border); color: var(--ink); }
.btn-outline:hover{ border-color: var(--plum); color:var(--plum); }
.btn-icon-only{ padding:6px 10px; font-size:1.05em; line-height:1; }
.btn-ghost{ background:transparent; color: var(--muted); }
.btn-ghost:hover{ color: var(--ink); }
.btn-danger{ background: var(--danger); color:#fff; }
.btn-danger:hover{ background:#A23A31; }
.btn-sm{ padding:6px 12px; font-size:12.5px; }
.btn-block{ width:100%; }
.btn:disabled{ opacity:.5; cursor:not-allowed; }
.icon-btn{ background:none; border:none; font-size:20px; cursor:pointer; color:var(--ink); padding:4px 8px; border-radius:6px; }
.icon-btn:hover{ background: var(--blush); }

/* ================= APP SHELL ================= */
.app-shell{ display:flex; min-height:100vh; }
.sidebar{
  width: 236px; background: var(--plum-dark); color:#EADFE4; flex-shrink:0;
  display:flex; flex-direction:column; padding: 20px 14px; position:sticky; top:0; height:100vh; overflow-y:auto; -webkit-overflow-scrolling:touch;
}
.sidebar-brand{ display:flex; align-items:center; gap:10px; padding: 4px 10px 22px; }
.sidebar-brand-link{ display:flex; align-items:center; gap:10px; text-decoration:none; }
.sidebar-brand-link:hover .name{ opacity:.85; }
.sidebar-brand .mark{ width:34px;height:34px;border-radius:9px; object-fit:cover; display:block; }
.sidebar-brand .name{ font-family: var(--font-display); font-size:19px; color:#fff; }
.nav-label{ font-size:11px; text-transform:uppercase; letter-spacing:.08em; color:#B291A5; margin: 18px 10px 6px; }
.nav-item{ display:flex; align-items:center; gap:10px; padding:9px 10px; border-radius:8px; color:#EADFE4; font-size:13.5px; font-weight:500; }
.nav-item:hover{ background: rgba(255,255,255,0.06); }
.nav-item.active{ background: var(--gold); color: var(--plum-dark); font-weight:600; }
.nav-item-row{ display:flex; align-items:center; border-radius:8px; }
.nav-item-row.active .nav-item{ background: var(--gold); color: var(--plum-dark); font-weight:600; }
.nav-star{ cursor:pointer; opacity:.35; padding:6px 10px; font-size:14px; color:#EADFE4; user-select:none; }
.nav-star:hover{ opacity:.9; }
.nav-star[data-starred="1"]{ opacity:1; color: var(--gold); }
.nav-ic{ width:18px; text-align:center; }

.main-col{ flex:1; min-width:0; display:flex; flex-direction:column; }
.topbar{ display:flex; align-items:center; gap:14px; padding: 16px 26px; background: var(--surface); border-bottom:1px solid var(--border); position:sticky; top:0; z-index:5; flex-wrap:wrap; }
.page-title{ font-size:21px; margin:0; flex:1; min-width:120px; }
.topbar-right{ display:flex; align-items:center; gap:14px; flex-wrap:wrap; }
.role-badge{ font-size:11px; text-transform:uppercase; letter-spacing:.04em; font-weight:700; padding:4px 10px; border-radius:20px; background:var(--blush); color:var(--plum);}
.user-menu{ display:flex; align-items:center; gap:10px; }
.user-name{ font-weight:600; font-size:13.5px; }
.content{ padding: 24px 26px 60px; }
#menuToggle{ display:none; }

/* Collapses the sidebar to the ☰ icon on any screen ≤1080px wide, in
   EITHER orientation — matches the app's own "mobile view" threshold
   used elsewhere (isMobileProductView() in pos.js). This single rule
   covers phones, and tablets in both portrait (e.g. iPad Pro 12.9" at
   1024px) and landscape — a tablet doesn't have room for the full
   sidebar AND an 8-column product grid at the same time. */
@media (max-width: 1080px){
  .sidebar{ position:fixed; z-index:20; transform:translateX(-100%); transition:.2s ease; box-shadow: var(--shadow-lg); }
  .sidebar.open{ transform:translateX(0); }
  #menuToggle{ display:inline-block; }
}

/* ================= CARDS / TABLES ================= */
.card{ background:var(--surface); border:1px solid var(--border); border-radius: var(--radius); padding:20px; box-shadow: var(--shadow); }
.card + .card{ margin-top:18px; }
.card-head{ display:flex; align-items:center; justify-content:space-between; margin-bottom:14px; gap:10px; flex-wrap:wrap; }
.card-head h3{ margin:0; font-size:16px; }

.grid{ display:grid; gap:18px; }
.grid-4{ grid-template-columns: repeat(4, 1fr); }
.grid-3{ grid-template-columns: repeat(3, 1fr); }
.grid-2{ grid-template-columns: repeat(2, 1fr); }
@media (max-width: 920px){ .grid-4{grid-template-columns:repeat(2,1fr);} .grid-3{grid-template-columns:repeat(2,1fr);} }
@media (max-width: 600px){ .grid-4,.grid-3,.grid-2{grid-template-columns:1fr;} }

.stat-card{ background:var(--surface); border:1px solid var(--border); border-radius:var(--radius); padding:18px; box-shadow: var(--shadow); position:relative; overflow:hidden;}
.stat-card .label{ font-size:12px; color:var(--muted); text-transform:uppercase; letter-spacing:.05em; font-weight:600; }
.stat-card .value{ font-family: var(--font-display); font-size:28px; margin-top:6px; }
.stat-card .delta{ font-size:12px; margin-top:6px; font-weight:600; }
.stat-card .delta.up{ color:var(--success); }
.stat-card .delta.down{ color:var(--danger); }
.stat-card .bar{ position:absolute; left:0; top:0; bottom:0; width:4px; }
.stat-card.c-plum .bar{ background:var(--plum); }
.stat-card.c-gold .bar{ background:var(--gold); }
.stat-card.c-success .bar{ background:var(--success); }
.stat-card.c-danger .bar{ background:var(--danger); }

table{ width:100%; border-collapse:collapse; font-size:13.5px; }
th{ text-align:left; font-size:11.5px; text-transform:uppercase; letter-spacing:.04em; color:var(--muted); padding:10px 12px; border-bottom:2px solid var(--border); font-weight:700;}
td{ padding:11px 12px; border-bottom:1px solid var(--border); vertical-align:middle; }
tbody tr:hover{ background: #FCF7F9; }
.table-wrap{ overflow-x:auto; }

.badge{ display:inline-flex; align-items:center; gap:4px; font-size:11px; font-weight:700; padding:3px 9px; border-radius:20px; text-transform:uppercase; letter-spacing:.03em;}
.badge-success{ background:var(--success-bg); color:var(--success); }
.badge-danger{ background:var(--danger-bg); color:var(--danger); }
.badge-warning{ background:var(--warning-bg); color:var(--warning); }
.badge-info{ background:var(--info-bg); color:var(--info); }
.badge-plum{ background: var(--blush); color:var(--plum); }

.alert{ padding:12px 16px; border-radius:var(--radius-sm); font-size:13.5px; margin-bottom:14px; }
.alert-error{ background:var(--danger-bg); color:var(--danger); }
.alert-success{ background:var(--success-bg); color:var(--success); }
.alert-warning{ background:var(--warning-bg); color:var(--warning); }

.empty-state{ text-align:center; padding:50px 20px; color:var(--muted); }
.empty-state .ico{ font-size:38px; margin-bottom:10px; }

.pager{ display:flex; gap:6px; margin-top:14px; justify-content:flex-end; }
.pager a, .pager span{ padding:6px 11px; border-radius:6px; border:1px solid var(--border); font-size:12.5px; }
.pager a:hover{ border-color:var(--plum); }
.pager .current{ background:var(--plum); color:#fff; border-color:var(--plum); }

/* ================= MODAL ================= */
.modal-backdrop{ position:fixed; inset:0; background:rgba(42,30,39,0.5); display:none; align-items:center; justify-content:center; z-index:50; padding:20px;}
.modal-backdrop.open{ display:flex; }
/* Inline collapsible table rows (Platform → Edit plan / Manage) — NOT
   the full-screen overlay modal above. A <tr> must stay display:table-row
   to render correctly inside its table; toggled purely by class so there's
   no inline style around to fight the .open rule's specificity. */
.plan-row{ display:none; }
.plan-row.open{ display:table-row; }
.modal{ background:#fff; border-radius:14px; width:100%; max-width:560px; max-height:90vh; overflow-y:auto; -webkit-overflow-scrolling:touch; padding:26px; box-shadow:var(--shadow-lg); }
.modal-head{ display:flex; justify-content:space-between; align-items:center; margin-bottom:16px; }
.modal-head h3{ margin:0; }
.modal-close{ background:none; border:none; font-size:22px; cursor:pointer; color:var(--muted); }
.modal-actions{ display:flex; justify-content:flex-end; gap:10px; margin-top:20px; }
/* The receipt modal specifically has 4 action buttons in a deliberately
   narrow (340px) modal meant to echo actual receipt paper proportions —
   left as a single nowrap row, each button's own text was squeezed
   into an awkward two-line wrap. A clean 2x2 grid reads far better at
   that width and gives each button a larger, easier tap target. */
#receiptBackdrop .modal-actions{ flex-wrap:wrap; justify-content:center; }
#receiptBackdrop .modal-actions .btn{ flex:1 1 calc(50% - 5px); }
#receiptBackdrop .modal-actions .btn-icon-only{ flex:0 0 44px; }
#qpReceiptBackdrop .modal-actions{ flex-wrap:wrap; justify-content:center; }
#qpReceiptBackdrop .modal-actions .btn{ flex:1 1 calc(50% - 5px); }
#qpReceiptBackdrop .modal-actions .btn-icon-only{ flex:0 0 44px; }

/* ================= POS SCREEN ================= */
.pos-grid{ display:grid; grid-template-columns: 1fr 380px; gap:18px; align-items:start; }
@media (max-width: 1080px){
  .pos-grid{ grid-template-columns:1fr; }
  /* .cart-panel itself no longer needs anything undone here — it has
     no sticky/height-cap at any width now (see its own rule above).
     Only .cart-items and .product-grid still get capped-height, own-
     scroll treatment above this breakpoint (useful there since cart
     and grid sit side-by-side and can each be genuinely long); once
     stacked into one column below it, everything should just scroll
     with the page as one normal list, same reasoning as .cart-panel. */
  .cart-items{ max-height:none; overflow-y:visible; overscroll-behavior:auto; }
  .product-grid{ max-height:none; overflow-y:visible; overscroll-behavior:auto; }
}

/* While the camera scanner is running, on mobile-view screens (the same
   ≤1080px breakpoint pos.js already treats as "mobile" via
   isMobileProductView()), hide the browsable product grid so the cart
   panel sits right below the scan box instead of requiring a scroll past
   the product tiles. Desktop keeps both visible side by side as before.
   Toggled via the 'camera-active' class in scanner.js. */
@media (max-width: 1080px){
  .pos-grid.camera-active #productGrid,
  .pos-grid.camera-active #productToggle{ display:none !important; }
}

/* Tablet landscape (~601–1080px wide, landscape): keep the product grid
   and cart side-by-side like desktop — both just grow with the page now
   like every other size, no independent scroll boxes anymore (see the
   product-grid/cart-items fix elsewhere in this file for why). */
@media (min-width: 601px) and (max-width: 1080px) and (orientation: landscape){
  .pos-grid{ grid-template-columns: 1fr 340px; }
  .pos-grid .product-grid{ grid-template-columns: repeat(6, 1fr); grid-auto-rows:190px; }
}

/* Large tablets in landscape (iPad Pro / big Android tablets are wider
   than 1080px) — touch-only, so a desktop browser window is untouched.
   Same 6 product columns as the smaller tablets above. */
@media (min-width: 1081px) and (max-width: 1440px) and (orientation: landscape) and (hover: none) and (pointer: coarse){
  .pos-grid .product-grid{ grid-template-columns: repeat(6, 1fr); }
}

/* Tablet portrait (~601–1080px wide, portrait): stacked layout. */
@media (min-width: 601px) and (max-width: 1080px) and (orientation: portrait){
  .pos-grid .product-grid{ grid-template-columns: repeat(4, 1fr); grid-auto-rows:190px; }
}
.scan-box{ display:flex; gap:10px; margin-bottom:16px; }
.scan-box input{ font-size:16px; padding:13px 14px; flex:1; }
#scannerToggleBtn{ white-space:nowrap; }
#scannerToggleBtn.active{ background:var(--gold,#e0b13a); border-color:var(--gold,#e0b13a); color:#fff; }
#productListScannerToggleBtn.active{ background:var(--gold,#e0b13a); border-color:var(--gold,#e0b13a); color:#fff; }
.scanner-box{ position:relative; width:100%; max-width:320px; margin-bottom:8px; border-radius:8px; overflow:hidden; border:2px solid var(--border); transition:border-color .15s, box-shadow .15s; }
.scanner-box video{ display:block; width:100%; aspect-ratio:16/9; height:auto; object-fit:cover; background:#000; }
.scanner-box.flash-ok{ border-color:#2e9e5b; box-shadow:0 0 0 3px rgba(46,158,91,.25); }
.scanner-box.flash-err{ border-color:#c0392b; box-shadow:0 0 0 3px rgba(192,57,43,.25); }
@keyframes scanner-flash-fade { from{ opacity:1; } to{ opacity:0; } }
/* "Shutter" cue on a successful scan: the live camera preview briefly dims
   to black and back, like a camera closing and reopening. This runs on top
   of the still-live video feed (scanning never actually pauses) — it's a
   strong visual signal for noisy environments where the beep alone might
   not be heard. Triggered by adding/removing this class in JS. */
.scanner-box video.shutter-blink{ animation: shutter-blink .35s ease; }
@keyframes shutter-blink{
  0%   { opacity:1; }
  35%  { opacity:0; }
  65%  { opacity:0; }
  100% { opacity:1; }
}
.scanner-status.muted{ opacity:.7; }
.scan-status-ok{ color:#2e9e5b; font-weight:600; }
.product-grid{ display:grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows:170px; gap:8px; padding-right:4px;
  /* Paired with .cart-panel's own sticky+scroll below: on wide screens
     the two sit side by side as independent panes, each scrolling on
     its own — the cart stays put while you browse, and vice versa.
     This is only safe to bring back now that grid-auto-rows above gives
     every row a fixed, known height: that's what makes content-
     visibility (on .product-tile) actually skip work for off-screen
     tiles instead of silently doing nothing, which is what made an
     internal scroll box here feel stuck/janky before. overscroll-
     behavior:contain stops a scroll that hits the top/bottom of this
     box from "leaking" into scrolling the page underneath it — the
     usual cause of a nested scroll box feeling broken on trackpads/
     touch once you reach its edge. Turned off entirely on narrow/mobile
     screens below, where the grid and cart stack in one column instead
     and both just scroll with the page as one normal, single scroll. */
  max-height:calc(100vh - 100px); overflow-y:auto; overscroll-behavior:contain;
}
.product-tile{ background:#fff; border:1px solid var(--border); border-radius:8px; padding:8px; cursor:pointer; text-align:left; transition:.12s;
  /* The actual root cause: .product-grid below sizes its rows by
     content (the default "auto" grid behavior) — which means the
     browser can't know how tall a row is without first laying out
     every tile in it, images included. That dependency is exactly what
     defeats content-visibility:auto below: it can only skip work for
     an element once the browser is confident it knows that element's
     size without rendering it, and content-sized grid rows are the one
     case where it can't be confident. Fixing the grid itself to use a
     firm row height (see .product-grid rules) removes that dependency
     entirely — every tile's box is now known from its width alone, so
     the browser genuinely never has to touch an off-screen tile's
     image at all, on any browser, not just ones with the newest
     content-visibility support. overflow:hidden here is what makes an
     unusually long product name clip gracefully instead of pushing the
     tile taller than the row height the grid is now relying on. */
  overflow:hidden; content-visibility:auto; contain-intrinsic-size:0 170px;
}
.ptile-img{ width:100%; aspect-ratio:1/1; object-fit:cover; border-radius:6px; margin-bottom:6px; background:var(--blush); display:block; }
.product-tile:hover{ border-color:var(--plum-light); box-shadow: var(--shadow); transform:translateY(-1px); }
.product-tile .pname{ font-weight:600; font-size:11px; margin-bottom:2px; line-height:1.25; min-height:28px; }
/* No image at all for this product (see includes/pos_render.php) — text
   carries the whole tile instead, same spirit as the Text Calculator's picker:
   centered, a little larger and bolder, no wasted placeholder box. */
.product-tile.no-image{ text-align:center; display:flex; flex-direction:column; justify-content:center; min-height:84px; }
.product-tile.no-image .pname{ font-size:12.5px; font-weight:700; min-height:0; }
.product-tile .pprice{ color:var(--plum); font-weight:700; font-size:12px; }
.product-tile .pstock{ font-size:9.5px; color:var(--muted); margin-top:1px; }
.product-tile.low .pstock{ color:var(--danger); font-weight:600; }

.cart-panel{ background:#fff; border:1px solid var(--border); border-radius:var(--radius); padding:18px;
  /* This used to be position:sticky with a max-height capping it to the
     screen, so it could stay pinned in view while scrolling a long
     product grid beside it. Given up on entirely — capping the panel's
     height meant something inside it (Clear Cart, in practice) could
     always end up needing its OWN scroll to reach, inside a small,
     easy-to-miss box with no visible hint that there was more below.
     On a short landscape phone screen that inner scroll area could
     shrink to almost nothing, hiding everything below "Items in Sale"
     entirely. No height cap at all means no clipping is possible on
     any screen size or orientation — full stop — at the cost of the
     panel no longer sticking to the top on a tall desktop screen. */
  display:flex; flex-direction:column;
}
.cart-panel > *{ flex:0 0 auto; }
.cart-items{ margin: 12px -4px;
  /* Only the item list scrolls on its own now — not the customer
     field above it or the totals/payment/checkout button below it,
     and not the camera above the whole panel. flex:1 1 auto (overriding
     .cart-panel > *'s default above) is what makes this the ONE part of
     the panel that gives up height first when everything doesn't fit —
     min-height keeps it from vanishing entirely even on a short screen,
     but it shrinks below its own 600px cap before anything else in the
     panel loses a pixel, which is exactly why the checkout button below
     it never gets pushed out of view anymore. 600px comfortably fits at
     least 10 cart lines (each ~55-60px with its price/qty subline) before
     the scrollbar kicks in — on a shorter screen where that doesn't
     actually fit, flex:1 1 auto still lets it shrink down to min-height
     rather than pushing the checkout button off-screen. overscroll-
     behavior:contain keeps a scroll that hits the top/bottom of this
     box from "leaking" into scrolling the page behind it. */
  flex:1 1 auto; min-height:120px; max-height:600px; overflow-y:auto; overscroll-behavior:contain;
}
.cart-line{ display:flex; align-items:center; gap:8px; padding:8px 4px; border-bottom:1px solid var(--border); }
.cart-line .ci-num{ flex:0 0 auto; width:20px; height:20px; border-radius:50%; background:var(--bg-soft, #f1eeeb); color:var(--muted); font-size:11px; font-weight:700; display:flex; align-items:center; justify-content:center; }
.cart-line .ci-name{ flex:1; font-size:12.5px; font-weight:600; }
.cart-line .ci-sub{ font-size:11px; color:var(--muted); }
.cart-line input.qty{ width:52px; padding:5px; text-align:center; }
.cart-line .ci-remove{ background:none;border:none;color:var(--danger);cursor:pointer;font-size:15px; }
.cart-totals div{ display:flex; justify-content:space-between; padding:4px 0; font-size:13.5px; }
.cart-totals .grand{ font-size:19px; font-family:var(--font-display); font-weight:700; border-top:1px dashed var(--border); margin-top:8px; padding-top:10px;}

/* ================= RECEIPT PRINT ================= */
.receipt{ width:300px; margin:0 auto; font-family: 'Inter', monospace; font-size:12.5px; }
.receipt h2{ text-align:center; margin:0 0 2px; font-size:16px; }
.receipt .center{ text-align:center; }
.receipt table{ width:100%; font-size:11.5px; }
.receipt hr{ border:none; border-top:1px dashed #999; margin:8px 0; }
@media print{
  .no-print{ display:none !important; }
  body{ background:#fff; }
  .receipt{ width:100%; }
  /* Note: printElement() in assets/js/btprinter.js prints receipts,
     labels, and other documents through a separate isolated document
     (a hidden iframe containing only that element + this stylesheet),
     not by hiding the rest of the current page — an earlier version did
     that with CSS here, but hidden elements still occupy their layout
     space, which produced a blank trailing page. The isolated-document
     approach has no leftover space, so no blank page. */
}

/* ================= MISC ================= */
.tag-list{ display:flex; gap:6px; flex-wrap:wrap; }
.kbd{ background:var(--blush); border-radius:4px; padding:1px 6px; font-size:11px; font-weight:700; color:var(--plum); }
.flex-between{ display:flex; align-items:center; justify-content:space-between; gap:10px; flex-wrap:wrap; }
.text-right{ text-align:right; }
.mt-0{ margin-top:0; }
.w-full{ width:100%; }

@media (max-width: 700px){
  table{ display:block; overflow-x:auto; white-space:nowrap; -webkit-overflow-scrolling:touch; }
  table thead, table tbody{ display:table-row-group; }
  table tr{ display:table-row; }
  table th, table td{ display:table-cell; }
}

/* ================= MOBILE OVERFLOW FIXES ================= */
html, body{ overflow-x: hidden; max-width: 100%; }
img, svg, table{ max-width: 100%; }
.card, .stat-card, .product-tile, .modal{ max-width: 100%; box-sizing: border-box; }

@media (max-width: 600px){
  .content{ padding: 16px 14px 50px; }
  .topbar{ padding: 12px 14px; flex-wrap: wrap; gap: 8px; }
  .page-title{ font-size: 17px; flex-basis: 100%; order: 2; }
  .topbar-right{ flex-wrap: wrap; gap: 8px; font-size: 12px; }
  .user-name{ display: none; } /* saves space on small phones; role badge still shows who's active */
  .stat-card .value{ font-size: 21px; word-break: break-word; }
  .form-row > *{ min-width: 0; flex-basis: 100%; }
  .cart-line{ flex-wrap: wrap; }
  .cart-line > div[style*="flex:1"]{ flex-basis: 100%; }
  .cart-line input.qty{ width: 46px; }
  .scan-box{ flex-wrap: wrap; }
  .scan-box input{ flex-basis: 100%; }
  .pos-grid .product-grid{ grid-template-columns: repeat(4, 1fr); gap:6px; grid-auto-rows:170px; }
  .pos-grid .product-tile{ padding:5px; border-radius:6px; }
  .pos-grid .product-tile .pname{ font-size:9.5px; min-height:22px; margin-bottom:1px; }
  .pos-grid .product-tile .pprice{ font-size:10.5px; }
  .pos-grid .product-tile .pstock{ font-size:8px; }
  .pos-grid .ptile-img{ margin-bottom:3px; }
  .calc-picker-row{ gap:6px; }
  .calc-pic-tile{ padding:5px; border-radius:6px; }
  .calc-pic-name{ font-size:9.5px; margin-bottom:1px; }
  .calc-pic-price{ font-size:10.5px; }
  .calc-pic-tile img, .calc-pic-placeholder{ margin-bottom:3px; }
  .calc-pic-placeholder{ font-size:15px; }
}

/* =========================================================
   Image Calculator
   Was entirely unstyled (no .calc-* rules existed at all) —
   this was almost certainly why item name/qty/price could look
   "missing": unconstrained images and unstyled stacked divs
   pushed the text out of the visible area rather than laying
   out as a proper line item.
   ========================================================= */
.calc-page{ max-width:920px; margin:0 auto; display:flex; flex-direction:column; gap:14px; }

.calc-branchbar{ display:flex; align-items:center; justify-content:space-between; background:var(--surface); border:1px solid var(--border); border-radius:10px; padding:10px 14px; font-size:13px; }
.calc-branchbar select{ width:auto; }

.calc-topbar{ display:flex; justify-content:flex-end; }
.calc-mode-select{ width:auto; }

/* Picture picker — hidden until JS adds .open when multiple products share a price */
.calc-picker{ display:none; background:var(--surface); border:1px solid var(--border); border-radius:10px; padding:14px; }
.calc-picker.open{ display:block; }
.calc-picker-label{ font-size:13px; margin-bottom:10px; color:var(--muted); }
.calc-picker-section{ margin-bottom:14px; }
.calc-picker-section:last-child{ margin-bottom:0; }
.calc-picker-section-header{
  font-size:12px; font-weight:700; text-transform:uppercase; letter-spacing:.03em;
  color:var(--muted); margin-bottom:6px; display:flex; align-items:center; gap:6px;
}
.calc-picker-section-count{
  background:var(--bg); border-radius:10px; padding:1px 7px; font-size:10.5px; font-weight:600;
}
.calc-picker-row{ display:grid; grid-template-columns:repeat(4, minmax(0, 1fr)); gap:8px; }
/* Same root cause as .product-grid/.product-tile on the main POS
   screen (see the comment there): this row used content-sized ("auto")
   grid rows, so the browser can't skip laying out an off-screen tile's
   image without first rendering it — which is exactly what made this
   picker's scroll feel janky with images on, while the Text Calculator
   equivalent (no images) never showed the problem. A firm row height
   removes that dependency, so content-visibility genuinely gets to
   skip off-screen tiles' image work. */
.calc-picker-row{ grid-auto-rows:170px; }
.calc-pic-tile{ display:flex; flex-direction:column; align-items:stretch; gap:0; width:100%; padding:8px; border:1px solid var(--border); border-radius:8px; background:#fff; cursor:pointer; text-align:left; transition:.12s; overflow:hidden; content-visibility:auto; contain-intrinsic-size:0 170px; }
.calc-pic-tile:hover{ border-color:var(--plum-light); box-shadow: var(--shadow); transform:translateY(-1px); }
.calc-pic-tile img{ width:100%; aspect-ratio:1/1; height:auto; object-fit:cover; border-radius:6px; margin-bottom:6px; background:var(--blush); flex-shrink:0; }
.calc-pic-placeholder{ width:100%; aspect-ratio:1/1; display:flex; align-items:center; justify-content:center; font-size:20px; border-radius:6px; margin-bottom:6px; background:var(--blush); }
.calc-pic-name{ font-weight:600; font-size:11px; margin-bottom:2px; line-height:1.25; display:block; }
.calc-pic-price{ color:var(--plum); font-weight:700; font-size:12px; display:block; }
.calc-picker-categories{ display:flex; gap:8px; flex-wrap:wrap; margin-top:10px; }
.calc-picker-categories .calc-cat-pill{
  display:flex; align-items:center; gap:6px;
  padding:7px 12px; border-radius:18px; border:1px solid var(--border);
  background:var(--bg); cursor:pointer; font-size:12.5px; font-weight:600; color:var(--ink);
}
.calc-picker-categories .calc-cat-pill:hover{ border-color:var(--plum-light); }
.calc-picker-categories .calc-cat-pill.active{ background:var(--plum); border-color:var(--plum); color:#fff; }
.calc-picker-categories .calc-cat-pill-qty{
  background:rgba(0,0,0,.1); border-radius:10px; padding:1px 6px; font-size:11px;
}
.calc-picker-categories .calc-cat-pill.active .calc-cat-pill-qty{ background:rgba(255,255,255,.25); }

/* Same items-at-this-price list — one column, full width, on every device size */


/* Dead/unused markup (never toggled by JS) — keep it out of the way rather than an empty box always on screen */
.calc-selected{ display:none; }

.calc-sale-panel{ background:var(--surface); border:1px solid var(--border); border-radius:10px; padding:14px; }
.calc-sale-head{ display:flex; align-items:center; justify-content:space-between; margin-bottom:8px; }
.calc-sale-head h3{ margin:0; font-size:14px; }
.calc-icon-btn{ background:none; border:none; font-size:16px; cursor:pointer; padding:4px 8px; border-radius:6px; }
.calc-icon-btn:hover{ background:var(--blush); }

/* Only this list of items should scroll — not the whole sale panel
   (header + Hold/Held/Clear buttons above, running Total below), and
   not the camera above the panel. overscroll-behavior:contain keeps a
   scroll that hits the top/bottom of this box from "leaking" into the
   page behind it. */
.calc-sale-items{ display:flex; flex-direction:column; gap:6px; max-height:300px; overflow-y:auto; overscroll-behavior:contain; }
.calc-empty{ color:var(--muted); font-size:13px; padding:16px 0; text-align:center; }

/* One row per item — this is the piece that was rendering unstyled: an
   <img> with no size constraint plus several divs with no flex layout,
   which stacked vertically and pushed name/qty/price out of the visible
   scroll area. Now a proper single-line layout. */
.calc-sale-line{ display:flex; align-items:center; gap:10px; padding:6px 4px; border-bottom:1px solid var(--border); }
.calc-sale-num{ flex:0 0 auto; width:18px; height:18px; border-radius:50%; background:var(--bg-soft, #f1eeeb); color:var(--muted); font-size:10px; font-weight:700; display:flex; align-items:center; justify-content:center; }
.calc-sale-line img{ width:34px; height:34px; object-fit:cover; border-radius:6px; flex-shrink:0; }
.calc-sale-placeholder{ width:34px; height:34px; flex-shrink:0; display:flex; align-items:center; justify-content:center; font-size:15px; background:var(--blush); border-radius:6px; }
.calc-sale-name{ flex:1; min-width:0; font-size:13px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.calc-sale-qty{ font-size:12.5px; color:var(--muted); flex-shrink:0; }
.calc-sale-sub{ font-weight:700; font-size:13px; flex-shrink:0; min-width:60px; text-align:right; }
.calc-sale-del{ background:none; border:none; color:var(--danger); font-size:16px; cursor:pointer; flex-shrink:0; padding:2px 6px; }

.calc-sale-total{ display:flex; justify-content:space-between; align-items:center; margin-top:10px; padding-top:10px; border-top:2px solid var(--ink); font-weight:800; font-size:16px; }
.calc-sale-total #calcSaleTotal.calc-pop{ animation:calc-pop .25s ease; }
@keyframes calc-pop{ 0%{ transform:scale(1.15); color:var(--gold); } 100%{ transform:scale(1); } }

.calc-unit{ background:var(--surface); border:1px solid var(--border); border-radius:10px; padding:14px; }
.calc-display-panel{ text-align:right; padding:10px 6px 16px; border-bottom:1px solid var(--border); margin-bottom:12px; position:relative; }
.calc-selected-preview{ display:none; align-items:center; gap:8px; float:left; text-align:left; }
.calc-selected-preview.show{ display:flex; }
.calc-selected-preview img{ width:32px; height:32px; object-fit:cover; border-radius:6px; }
.calc-selected-placeholder{ width:32px; height:32px; display:none; align-items:center; justify-content:center; font-size:15px; background:var(--blush); border-radius:6px; }
.calc-selected-label{ font-size:12px; color:var(--muted); }
.calc-selected-name{ font-size:13px; font-weight:700; color:var(--ink); margin-right:2px; }

/* Offline sync banner — always a single line, especially on mobile/tablet.
   The long explanation sentence only shows when there's room for it; the
   status + pending count always stay together and never wrap onto their
   own stacked lines. */
.offline-banner-row{ display:flex; justify-content:space-between; align-items:center; gap:8px; flex-wrap:nowrap; }
.offline-banner-status{ display:flex; align-items:center; gap:8px; flex-wrap:nowrap; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; min-width:0; flex:1; }
.offline-count{ flex-shrink:0; white-space:nowrap; }
@media (max-width: 900px){
  .offline-desc{ display:none; }
  .offline-banner-status b{ font-size:13px; }
  .offline-banner-status{ font-size:12.5px; }
}

/* Disable pull-to-refresh on POS and Image Calculator — an accidental
   swipe-down mid-sale would otherwise reload the page and lose the cart. */
body.page-pos, body.page-calculator_pos{ overscroll-behavior-y: contain; }

/* Out-of-stock product tiles — visually inert, not just error-on-click. */
.product-tile.out-of-stock{ opacity:0.4; filter:grayscale(60%); cursor:not-allowed; pointer-events:none; }

/* Stock quantity line, shown above the calculator keypad once an item is
   selected (via ×, the price picker, or the category browse grid). */
.calc-stock-line{ text-align:center; font-size:13px; font-weight:600; padding:6px 10px; margin-bottom:6px; border-radius:8px; background:var(--bg,#faf8f6); color:var(--ink); }
.calc-stock-line.calc-stock-low{ background:#fff7ed; color:#9a3412; }
.calc-stock-line.calc-stock-out{ background:#fef2f2; color:var(--danger); }
.calc-expression{ font-size:14px; color:var(--muted); min-height:18px; }
.calc-display{ font-size:36px; font-weight:800; color:var(--ink); line-height:1.2; }
.calc-hint{ font-size:12px; color:var(--muted); margin-top:4px; }

.calc-keypad{ display:grid; grid-template-columns:repeat(4, 1fr); gap:8px; }
.calc-key{ padding:16px 0; font-size:18px; font-weight:600; border:1px solid var(--border); border-radius:8px; background:var(--bg); cursor:pointer; }
.calc-key:active{ background:var(--blush); }
.calc-key-fn{ background:var(--blush); color:var(--plum-dark); }
.calc-key-op{ background:var(--gold-light); color:var(--plum-dark); font-weight:800; }
.calc-key-equals{ background:var(--gold); color:#fff; }
.calc-key-pay{ background:var(--plum); color:#fff; grid-row:span 1; }
.calc-key-zero{ grid-column:span 2; }

.calc-pay-summary > div{ display:flex; justify-content:space-between; padding:4px 0; font-size:13px; }
.calc-pay-summary .grand{ font-weight:800; font-size:15px; border-top:1px solid var(--border); margin-top:4px; padding-top:8px; }

@media (min-width: 700px){
  .calc-page{ flex-direction:row; flex-wrap:wrap; align-items:flex-start; max-width:820px; }
  .calc-page .calc-sale-panel{ flex:1 1 320px; order:2; }
  .calc-page .calc-unit{ flex:1 1 320px; order:1; }
  .calc-page .calc-branchbar, .calc-page .calc-topbar, .calc-page .calc-picker, .calc-page .calc-selected, .calc-page #calcError{ order:0; width:100%; }
}

/* ================= PAGE LOADING ANIMATION ================= */
/* Branded splash shown while a page's own resources (images, fonts)
   finish loading — see the inline script right after <body> in
   includes/header.php that fades this out once ready. */
#pageLoader{
  position:fixed; inset:0; z-index:99999;
  display:flex; align-items:center; justify-content:center;
  background:var(--surface, #fff);
  transition:opacity .35s ease;
}
#pageLoader.page-loader-hide{ opacity:0; pointer-events:none; }
.page-loader-mark{
  width:56px; height:56px; border-radius:14px; position:relative; z-index:1;
  animation:pageLoaderPulse 1.1s ease-in-out infinite;
}
.page-loader-ring{
  position:absolute; width:84px; height:84px; border-radius:50%;
  border:3px solid var(--blush, #f3dde3); border-top-color:var(--plum, #6d2149);
  animation:pageLoaderSpin .9s linear infinite;
}
@keyframes pageLoaderPulse{
  0%, 100%{ transform:scale(1); opacity:1; }
  50%{ transform:scale(0.92); opacity:.85; }
}
@keyframes pageLoaderSpin{
  to{ transform:rotate(360deg); }
}
@media (prefers-reduced-motion: reduce){
  .page-loader-mark, .page-loader-ring{ animation:none; }
}
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}

/* ---------- "Item added" toast (see assets/js/item_added_toast.js) ---------- */
.item-added-toast{
  position:fixed; left:50%; bottom:24px; transform:translateX(-50%) translateY(20px);
  background:#1E8449; color:#fff; padding:12px 20px; border-radius:999px;
  font-size:14px; font-weight:600; box-shadow:var(--shadow-lg, 0 8px 24px rgba(0,0,0,.18));
  display:flex; align-items:center; gap:8px; z-index:2000;
  opacity:0; pointer-events:none; transition:opacity .2s ease, transform .2s ease;
  max-width:90vw; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.item-added-toast.item-added-toast-show{
  opacity:1; transform:translateX(-50%) translateY(0);
}
.item-added-toast-ico{
  display:inline-flex; align-items:center; justify-content:center;
  width:18px; height:18px; border-radius:50%; background:rgba(255,255,255,.25);
  font-size:12px; flex-shrink:0;
}
@media (max-width:480px){
  .item-added-toast{ bottom:16px; font-size:13px; padding:10px 16px; }
}

/* ---------- "New online order" alert (see assets/js/order_alerts.js) ----------
   Top-right and dismiss-only-by-click-or-timeout, unlike the bottom-center
   item-added toast above — this one is reporting something that happened
   elsewhere (a customer placing an order), not confirming the action the
   person just took, so it needs to be noticeable and stick around longer. */
.order-alert-toast{
  position:fixed; top:16px; right:16px; max-width:360px;
  background:#fff; border:1px solid var(--border); border-left:4px solid var(--plum, #6b2d5c);
  color:var(--text, #222); padding:12px 14px; border-radius:8px;
  font-size:13.5px; box-shadow:var(--shadow-lg, 0 8px 24px rgba(0,0,0,.18));
  display:flex; align-items:flex-start; gap:10px; z-index:2100;
  opacity:0; pointer-events:none; transform:translateY(-10px); transition:opacity .2s ease, transform .2s ease;
}
.order-alert-toast.order-alert-toast-show{ opacity:1; pointer-events:auto; transform:translateY(0); }
.order-alert-toast-ico{ font-size:16px; flex-shrink:0; line-height:1.3; }
.order-alert-toast-body{ flex:1; line-height:1.4; }
.order-alert-toast-view{ flex-shrink:0; align-self:center; background:var(--plum, #6b2d5c); color:#fff !important; padding:5px 12px; border-radius:6px; font-size:12.5px; font-weight:600; text-decoration:none; white-space:nowrap; }
.order-alert-toast-close{ flex-shrink:0; background:none; border:none; color:var(--muted); font-size:16px; line-height:1; cursor:pointer; padding:2px; }
@media (max-width:480px){
  .order-alert-toast{ left:12px; right:12px; top:12px; max-width:none; }
}
#enablePushBtn.btn-success-state{ color:#1E8449; border-color:#1E8449; cursor:default; }


/* ================= POS CATEGORY PILLS =================
   Categories sit four to a row. Collapsed = one horizontal row (the
   first four). The arrow bar underneath opens the rest: every further
   group of four drops onto its own row below (the fifth category starts
   the next row), and tapping the arrow again folds back to the single
   horizontal row. The category currently being filtered stays visible
   even when collapsed. */
.cat-pills{ display:grid; grid-template-columns:repeat(4, minmax(0, 1fr)); gap:6px; width:100%; }
.cat-pills .cat-pill{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.cat-pills:not(.open) .cat-pill:nth-child(n+5):not(.btn-primary){ display:none; }
.cat-pills .cat-toggle{ grid-column:1 / -1; padding:3px 10px; line-height:1.2; }
#categoryPillsWrap{ display:block !important; }


/* ================= DAY / MONTH / YEAR DATE PICKER =================
   (assets/js/date_dmy.js) three dropdowns in place of the single native
   calendar; the original date input stays in the page, hidden, holding
   the real YYYY-MM-DD value. */
.dmy-picker{ display:inline-flex; flex:0 0 auto; flex-wrap:wrap; gap:6px; align-items:center; max-width:100%; min-width:0; width:auto; vertical-align:middle; }
/* Each dropdown sizes itself to its longest entry (31 / September / 2026),
   never shrinks, and ignores the page-wide "full width" input rule and the
   160px-minimum / stretch rules of .form-row, which used to squeeze all
   three into slivers that cut the text off. */
.dmy-picker select{ width:auto !important; min-width:0; flex:0 0 auto; padding:10px 6px 10px 10px; text-overflow:clip; }
.form-row > .dmy-picker, .field > .dmy-picker{ flex:0 0 auto; min-width:0; width:auto; }
@media (max-width: 760px){ .form-row > .dmy-picker{ flex:0 0 auto; } }
input.dmy-source{ position:absolute !important; width:1px !important; height:1px !important; opacity:0 !important; pointer-events:none !important; margin:0 !important; padding:0 !important; border:0 !important; overflow:hidden; clip:rect(0 0 0 0); }


/* ================= MOUSE WHEEL SHOULD NEVER GET "STUCK" =================
   The inner scroll boxes on the POS pages (product grid, cart, Quick/
   Manual POS cart, calculator sale list) used overscroll-behavior:contain,
   which stops the wheel from carrying on to the page once the box hits its
   top or bottom — with a mouse it feels like scrolling "stopped working".
   On devices with a mouse, let the wheel pass on to the page at the edges.
   Touch devices keep the old behaviour. */
@media (hover: hover) and (pointer: fine){
  .product-grid, .cart-items, .calc-sale-items, .qp-cart-wrap{ overscroll-behavior: auto !important; }
}

/* Tiles must not move under a mouse pointer: a tile that lifts (hover) or
   shrinks (press) can slip out from under the cursor between press and
   release, which made a product need a second click. With a mouse the
   highlight is colour/shadow only; touch screens keep the press feedback. */
@media (hover: hover) and (pointer: fine) {
  .calc-pic-tile:hover, .calc-pic-tile:active,
  .calc-text-tile:hover, .calc-text-tile:active { transform:none !important; }
  .calc-pic-tile, .calc-text-tile { content-visibility:visible !important; }
}
