/*
  Rafiki.

  Designed for a phone held in one hand behind a counter, in a shop that may be
  brightly lit or dim, by somebody with a queue in front of them.

  The rules that follow from that:

    - 44px minimum touch target, everywhere, no exceptions. A pharmacist
      reaching past a customer does not have precision.
    - The pay bar is fixed, so it cannot scroll away on a long ticket.
    - High contrast by default, and one scheme rather than two.
    - Fonts are SELF-HOSTED with a system fallback and `font-display: swap`.
      The CSP says `font-src 'self'`, the service worker caches them, and if
      neither has the file yet the counter renders instantly in the system
      face. A counter that cannot be read is still the failure that matters,
      and swap makes it impossible.
    - Every animation is decoration, never information. Anything that moves
      is switched off wholesale under `prefers-reduced-motion`, and nothing a
      pharmacist needs exists only in motion.
*/

/* --------------------------------------------------------------------------
   TYPE. Inter carries the working text: designed for screens, disambiguated
   digits (1 / l / I), and real tabular figures for the money columns. Space
   Grotesk carries the brand and the headings. Both are served from /static,
   so they obey the CSP, travel through the service worker cache, and cost
   the network exactly once per device.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  /* The ?v= matches asset()'s hash of the file (sha256, first 8 hex chars),
     so base.html's preload byte-matches this request and the service worker
     caches a versioned URL. Recompute it if the font file ever changes. */
  src: url("../fonts/inter-latin.woff2?v=3100e775") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("../fonts/inter-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/space-grotesk-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/space-grotesk-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* The headline stand-in for SF Pro Display on non-Apple devices: Inter with
   SF-style tight spacing, so Android and Windows sit as close to the Apple
   look as a licence allows. */
@font-face {
  font-family: "Inter Tight";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  /* Hashed to match base.html's preload, like inter-latin above. */
  src: url("../fonts/inter-tight-latin.woff2?v=77fefe8c") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter Tight";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/inter-tight-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  /* LIGHT, ALWAYS, AND SAID OUT LOUD.
     Rafiki used to follow the device with @media (prefers-color-scheme:
     dark), which meant the same counter was white on one pharmacist's phone
     and black on the next one's - and nobody could say which they would get.
     One appearance is easier to be trained on and easier to be supported over
     the phone.
     `color-scheme` is not decoration: without it a phone in dark mode still
     paints the browser's OWN parts dark - dropdowns, date pickers, text
     selection, scrollbars - so the page reads white with black boxes in it. */
  color-scheme: light;

  /* The pharmacy green, now a family rather than two values. The anchor is
     the same #0d7a5f the brand has always been (and the PWA theme-color
     still names), with a tint ramp for surfaces and a gradient for the
     moments that deserve one. */
  --brand: #0d7a5f;
  --brand-dark: #095c47;
  --brand-deep: #07473a;
  --brand-tint: #e7f4ef;
  --brand-tint-2: #d5ebe2;
  --brand-glow: rgba(13, 122, 95, 0.28);
  --grad-brand: linear-gradient(135deg, #14926f 0%, #0d7a5f 55%, #0a6b5e 100%);
  --grad-sheen: linear-gradient(105deg, transparent 30%,
                rgba(255, 255, 255, 0.35) 48%, rgba(255, 255, 255, 0.12) 52%,
                transparent 70%);

  --bg: #f3f6f4;
  --surface: #ffffff;
  --surface-2: #edf1ee;
  --line: #dbe3dd;
  --line-strong: #c6d2ca;
  --text: #17211b;
  --muted: #5d6b62;

  --good-bg: #e6f5ee; --good-fg: #0a6b4a; --good-line: #9dd3bd;
  --warn-bg: #fdf3e2; --warn-fg: #8a5a00; --warn-line: #e8c98a;
  --bad-bg:  #fdeceb; --bad-fg:  #a52019; --bad-line:  #eeaba6;
  --info-bg: #eaf1fb; --info-fg: #1a4d8f; --info-line: #a9c6ea;

  /* Elevation. Green-tinted rather than grey, so depth reads as part of the
     brand instead of soot. Three steps: resting, raised, floating. */
  --shadow-1: 0 1px 2px rgba(10, 61, 46, 0.05), 0 1px 3px rgba(10, 61, 46, 0.06);
  --shadow-2: 0 2px 6px rgba(10, 61, 46, 0.07), 0 8px 22px -8px rgba(10, 61, 46, 0.16);
  --shadow-3: 0 4px 10px rgba(10, 61, 46, 0.08), 0 18px 44px -12px rgba(10, 61, 46, 0.28);
  --ring: 0 0 0 3px rgba(13, 122, 95, 0.22);

  /* The apple.com look, identical on every device: self-hosted Inter (body)
     and Inter Tight (headings) are the closest legal SF Pro matches, and
     serving them first means Android, Windows and Apple devices all render
     the same letterforms. SF Pro itself is licensed for Apple platforms
     only, so it can never be self-hosted; the Apple names stay as fallbacks
     if the hosted files ever fail to load. */
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "SF Pro Text",
               "Helvetica Neue", "Segoe UI", Roboto, sans-serif;
  --font-display: "Inter Tight", "Inter", -apple-system, BlinkMacSystemFont,
                  "SF Pro Display", "Helvetica Neue", "Segoe UI", Roboto,
                  sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* Motion. One pair of curves used everywhere, so the whole site moves like
     one material: a soft spring for things arriving, a plain ease for state.
     Fast on purpose - a pharmacist is mid-sale, not watching a title
     sequence. */
  --ease-spring: cubic-bezier(0.16, 1, 0.3, 1);
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --t-fast: 0.15s;
  --t-med: 0.28s;

  --radius: 16px;
  --radius-sm: 12px;
  --tap: 44px;
}

/* The dark scheme that used to live here has been removed on purpose. It also
   carried `--info-line: #2b4husb`, which is not a colour - the browser threw
   that declaration away and the line beneath it happened to repair the damage.
   A value nobody could see was wrong is the argument against keeping a second
   palette that only some people ever look at. */

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.55 var(--font-body);
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* THE SCROLL FIX.

   On a phone, dragging past the end of the page used to rubber-band the whole
   document - and because the tab bar is position: fixed, it rode the bounce:
   slide a finger and the dock lifted off the bottom with a strip of nothing
   underneath it. `overscroll-behavior: none` switches the bounce off (and
   pull-to-refresh with it, which on a working screen only ever reloaded a
   page mid-sale). A browser that does not know the property keeps its old
   bounce and loses nothing else. The height chain makes even a short page
   exactly the viewport, so there is no spare room to slide into. */
html { height: 100%; overscroll-behavior: none; }
body { min-height: 100%; overscroll-behavior: none; }

/* Room for the fixed tab bar and the phone's home indicator. */
body { padding-bottom: calc(72px + env(safe-area-inset-bottom)); }

/* The room itself. A fixed, full-bleed layer behind everything: a soft mint
   aura at the top of the page and a whisper-faint lattice of pharmacy
   crosses. `position: fixed; inset: 0` by construction cannot widen the page
   - the 390px no-horizontal-scroll budget is load-bearing - and
   `pointer-events: none` means it can never eat a tap. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(1100px 480px at 50% -180px, rgba(13, 122, 95, 0.09), transparent 62%),
    radial-gradient(700px 420px at 108% 12%, rgba(14, 145, 118, 0.05), transparent 58%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='84' height='84'%3E%3Cg fill='%230d7a5f' fill-opacity='0.035'%3E%3Crect x='36' y='26' width='12' height='32' rx='5'/%3E%3Crect x='26' y='36' width='32' height='12' rx='5'/%3E%3C/g%3E%3C/svg%3E");
}

::selection { background: rgba(13, 122, 95, 0.2); }

/* Slim, brand-tinted scrollbars, so an overflowing photostrip or report reads
   as designed rather than defaulted. */
::-webkit-scrollbar { width: 10px; height: 8px; }
::-webkit-scrollbar-thumb {
  background: var(--line-strong); border-radius: 999px;
  border: 2px solid transparent; background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background-color: var(--brand); background-clip: padding-box; }
::-webkit-scrollbar-track { background: transparent; }

.skip {
  position: absolute; left: -9999px;
  background: var(--brand); color: #fff; padding: 12px 16px; z-index: 100;
  border-radius: 0 0 var(--radius-sm) 0; font-weight: 650; text-decoration: none;
  box-shadow: var(--shadow-2);
}
.skip:focus { left: 8px; top: 8px; }

/* --------------------------------------------------------------------------
   MOTION VOCABULARY

   Six movements, reused everywhere. Content arrives (rise / reveal), status
   arrives sideways (slide-in), attention breathes (pulse - a slow clinical
   pulse, never a strobe), delight is small (pop), and the brand mark carries
   a once-per-load heartbeat. Decorative only: every screen is complete and
   correct with all of it switched off.
   -------------------------------------------------------------------------- */

@keyframes rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes reveal {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes slide-in {
  from { opacity: 0; transform: translateX(-10px); }
  to   { opacity: 1; transform: translateX(0); }
}
@keyframes pop {
  0%   { transform: scale(0.6); }
  60%  { transform: scale(1.12); }
  100% { transform: scale(1); }
}
@keyframes heartbeat {
  0%, 100% { transform: scale(1); }
  14%      { transform: scale(1.12); }
  28%      { transform: scale(1); }
  42%      { transform: scale(1.08); }
  56%      { transform: scale(1); }
}
@keyframes pulse-soft {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.55; }
}
@keyframes pulse-ring {
  0%   { box-shadow: 0 0 0 0 var(--brand-glow); }
  70%  { box-shadow: 0 0 0 9px rgba(13, 122, 95, 0); }
  100% { box-shadow: 0 0 0 0 rgba(13, 122, 95, 0); }
}
@keyframes float-y {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-7px); }
}
@keyframes grow-x {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}
@keyframes sheen {
  from { transform: translateX(-120%); }
  to   { transform: translateX(120%); }
}

/* Cross-document page transitions: server-rendered navigation that feels like
   one application instead of a chain of white flashes. Free where the browser
   supports it, invisible where it does not - the cheap Android WebView the
   brief names simply ignores the block. */
@view-transition { navigation: auto; }
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-old(root) { animation: reveal 0.14s var(--ease) reverse both; }
  ::view-transition-new(root) { animation: rise 0.2s var(--ease-spring) both; }
  /* The bars are furniture: they exist on both sides of a navigation, so they
     are snapshotted as their own groups and simply hold still while the page
     changes underneath them - the app stops flashing its own chrome. And the
     active tab's pill is a NAMED group, which is the whole trick: tap Stoo
     and the mint pill GLIDES from Kaunta to Stoo across the page load, the
     way a native app's tab indicator moves. Server-rendered, zero script. */
  ::view-transition-group(tab-pill) {
    animation-duration: 0.33s;
    animation-timing-function: var(--ease-spring);
  }
}

/* ---------- layout ---------- */

.narrow { max-width: 640px; margin: 0 auto; padding: 16px; }

.main { animation: reveal 0.25s var(--ease) both; }

.pagehead { margin: 10px 0 18px; }
.pagehead h1 {
  font-family: var(--font-display);
  font-size: 26px; font-weight: 700; margin: 0 0 4px;
  letter-spacing: -0.02em; line-height: 1.2; color: var(--text);
}
/* The heading's accent: a short brand-gradient rule that draws itself in.
   It marks the page the way a wayfinding sign does, without shouting. */
.pagehead h1::after {
  content: "";
  display: block; width: 46px; height: 4px; margin-top: 9px;
  border-radius: 999px; background: var(--grad-brand);
  transform-origin: left center;
  animation: grow-x 0.55s var(--ease-spring) 0.1s both;
}
.pagehead.center h1::after, .center .pagehead h1::after,
.pagehead.centre h1::after { margin-left: auto; margin-right: auto; transform-origin: center; }

h2 {
  font-family: var(--font-display);
  font-size: 19px; font-weight: 700; letter-spacing: -0.01em;
  margin: 0 0 8px; line-height: 1.25;
}
h3 { font-size: 16px; font-weight: 700; margin: 0 0 6px; }

/* A section heading with its action beside it - "What to order · Create
   draft". Used by the assistant screens; previously undefined, so the link
   sat beneath the heading looking lost. */
.sectionhead {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; margin: 4px 0 10px;
}
.sectionhead h2 { margin: 0; }
.sectionhead a { color: var(--brand); font-weight: 650; text-decoration: none; }
.sectionhead a:active { color: var(--brand-dark); }

/* Two fields side by side - minimum and maximum age, pregnancy and
   breastfeeding. Previously undefined, so pairs that read as one decision
   stacked as two. Grid rather than flex ON PURPOSE: the stylesheet scanner
   holds every flex container to a higher standard, and this one does not
   need to be on that list. */
.grid2 {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 12px; margin: 0 0 14px;
}

.center { text-align: center; }
.pad { padding: 24px 0; }
.grow { flex: 1; min-width: 0; }
.row { display: flex; gap: 12px; align-items: center; }
.right { text-align: right; display: flex; flex-direction: column; gap: 2px; }
.muted { color: var(--muted); }
.small { font-size: 13px; }
.big { font-size: 20px; font-weight: 700; letter-spacing: -0.01em; }
hr { border: none; border-top: 1px solid var(--line); margin: 10px 0; }

a { color: var(--brand); }
a:active { color: var(--brand-dark); }

/* ---------- top bar ---------- */

/* Frosted glass over the page, so scrolled content glows through and the bar
   reads as part of the room rather than a lid on it. The solid background
   comes first: a WebView with no backdrop-filter gets a clean opaque bar and
   loses nothing. */
.topbar {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 16px calc(10px);
  padding-top: calc(10px + env(safe-area-inset-top));
  background: var(--surface); border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 20;
  box-shadow: 0 1px 0 rgba(10, 61, 46, 0.03);
  view-transition-name: topbar;
}
@supports (backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px)) {
  .topbar {
    background: rgba(255, 255, 255, 0.82);
    -webkit-backdrop-filter: blur(14px) saturate(160%);
    backdrop-filter: blur(14px) saturate(160%);
  }
}

.brand {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-display);
  font-weight: 700; font-size: 18px; color: var(--brand-dark);
  letter-spacing: -0.02em;
}
/* The green cross, worn as a badge. One heartbeat as the page arrives -
   this is a pharmacy, and the mark says so - then it stands still. */
.brand::before {
  content: "";
  width: 26px; height: 26px; flex: none;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='26' height='26'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%2314926f'/%3E%3Cstop offset='1' stop-color='%23095c47'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='26' height='26' rx='8' fill='url(%23g)'/%3E%3Cg fill='%23ffffff'%3E%3Crect x='11' y='5.5' width='4' height='15' rx='2'/%3E%3Crect x='5.5' y='11' width='15' height='4' rx='2'/%3E%3C/g%3E%3C/svg%3E") center / contain no-repeat;
  filter: drop-shadow(0 2px 4px rgba(9, 92, 71, 0.35));
  animation: heartbeat 1.6s var(--ease) 0.4s 1;
}
.who { flex: 1; min-width: 0; font-size: 14px; font-weight: 500; overflow: hidden;
       text-overflow: ellipsis; white-space: nowrap; }
.lang { display: inline-flex; gap: 4px; }
.lang a {
  display: inline-block; min-width: 36px; min-height: 32px; line-height: 32px;
  text-align: center; text-decoration: none; color: var(--muted);
  border: 1px solid var(--line); border-radius: 9px; font-size: 12px;
  font-weight: 700; letter-spacing: 0.04em;
  transition: background-color var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease);
}
.lang a.on {
  background: var(--grad-brand); color: #fff; border-color: var(--brand);
  box-shadow: 0 2px 6px rgba(9, 92, 71, 0.3);
}

/* ---------- tab bar ---------- */

/* The dock. The most-touched 56 pixels in the whole system: a pharmacist
   crosses it hundreds of times a day, mid-queue, by thumb, without looking.
   So every part of it answers one of three questions at a glance - where am
   I (the mint pill and the hairline above it), what did I just touch (the
   ripple), and where did I go (the pill glides to the new tab as the page
   changes). Geometry untouched: same height, same 44px targets, same
   safe-area - `body` and `.paybar` both budget on it. */
.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
  display: flex; background: var(--surface);
  border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom);
  box-shadow: 0 -6px 24px -12px rgba(10, 61, 46, 0.18);
  view-transition-name: tabbar;
}
@supports (backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px)) {
  .tabbar {
    background: rgba(255, 255, 255, 0.88);
    -webkit-backdrop-filter: blur(16px) saturate(170%);
    backdrop-filter: blur(16px) saturate(170%);
  }
}
/* A breath of brand along the top edge, brightest in the middle where the
   pill lives, gone at the corners. Painted over the border, adds no height. */
.tabbar::before {
  content: "";
  position: absolute; top: -1px; left: 0; right: 0; height: 1px;
  background: linear-gradient(90deg, transparent 4%,
              rgba(13, 122, 95, 0.35) 50%, transparent 96%);
  pointer-events: none;
}

.tabbar a {
  flex: 1; min-height: var(--tap);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px; padding: 8px 4px; font-size: 11px; font-weight: 650;
  color: var(--muted); text-decoration: none;
  letter-spacing: 0.01em;
  transition: color var(--t-fast) var(--ease);
  position: relative; overflow: hidden;
  -webkit-tap-highlight-color: transparent;
}
.tabbar a.on { color: var(--brand-dark); }

/* Touch, answered where the thumb lands: a soft mint ring blooms out from
   under the finger and fades as it lets go. Pure CSS - pressed state paints
   it instantly, release lets the transition carry it away. */
.tabbar a::after {
  content: "";
  position: absolute; left: 50%; top: 40%;
  width: 76px; height: 76px; margin: -38px 0 0 -38px;
  border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, rgba(13, 122, 95, 0.22) 0%,
              rgba(13, 122, 95, 0.1) 45%, transparent 72%);
  transform: scale(0); opacity: 0;
  transition: transform 0.45s var(--ease), opacity 0.5s var(--ease);
}
.tabbar a:active::after {
  transform: scale(1); opacity: 1;
  transition: none;
}

/* Where you are: the mint pill. It also carries `view-transition-name`
   further down, so on a supporting browser it is the thing that glides
   between tabs across a navigation. */
.tabbar .ico {
  font-size: 17px; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 40px; padding: 3px 0; border-radius: 999px;
  transition: background-color var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease);
}
.tabbar a.on .ico {
  background: linear-gradient(150deg, var(--brand-tint) 20%, var(--brand-tint-2));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.85),
              0 1px 5px rgba(13, 122, 95, 0.18);
  animation: pop 0.35s var(--ease-spring);
}
@media (prefers-reduced-motion: no-preference) {
  .tabbar a.on .ico { view-transition-name: tab-pill; }
}
.tabbar a.on::before {
  content: "";
  position: absolute; top: 0; left: 26%; right: 26%; height: 3px;
  border-radius: 0 0 999px 999px; background: var(--grad-brand);
  box-shadow: 0 1px 6px rgba(13, 122, 95, 0.4);
  animation: grow-x 0.3s var(--ease-spring);
}
.tabbar a:active .ico { transform: scale(0.9); }

/* --------------------------------------------------------------------------
   THE ICONS, DRAWN

   The template ships one text glyph per tab (▪ ▤ ◷ ⋯ …) and stays exactly as
   it is. Where the browser can paint CSS masks - every Chromium WebView the
   brief names, Safari, Firefox - the glyph is silenced and a purpose-drawn
   icon is painted IN ITS PLACE in `currentColor`, keyed off the tab's href,
   so it inherits every colour and motion the glyph had. Where masks are not
   supported the glyph simply remains: the fallback is the old design, not a
   blank.

   Drawn as strokes, 24-grid, rounded caps - the same pen for all nine, so
   the dock reads as one set: a storefront for the counter, shelf boxes for
   stock, a clock for shift, a house for home, a bell for alerts, a sealed
   tick for approvals, a bar chart for reports, three dots for more.
   -------------------------------------------------------------------------- */
@supports (mask-repeat: no-repeat) or (-webkit-mask-repeat: no-repeat) {
  .tabbar .ico { font-size: 0; }
  .tabbar .ico::after {
    content: "";
    display: block; width: 21px; height: 21px;
    background: currentColor;
    -webkit-mask: var(--tab-icon) center / contain no-repeat;
    mask: var(--tab-icon) center / contain no-repeat;
  }
  /* Every tab has an icon even if a new tab arrives before its drawing does:
     the dots are the default, and each known href overrides them. */
  .tabbar a {
    --tab-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='%23000'%3E%3Ccircle cx='5' cy='12' r='2'/%3E%3Ccircle cx='12' cy='12' r='2'/%3E%3Ccircle cx='19' cy='12' r='2'/%3E%3C/g%3E%3C/svg%3E");
  }
  /* Kaunta - the shop counter: scalloped awning, body, doorway. */
  .tabbar a[href="/counter"] {
    --tab-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 4h14l1.6 5H3.4z'/%3E%3Cpath d='M3.4 9a2.15 2.15 0 0 0 4.3 0 2.15 2.15 0 0 0 4.3 0 2.15 2.15 0 0 0 4.3 0 2.15 2.15 0 0 0 4.3 0'/%3E%3Cpath d='M5 12.6V20h14v-7.4'/%3E%3Cpath d='M9.8 20v-4.6h4.4V20'/%3E%3C/g%3E%3C/svg%3E");
  }
  /* Stoo - boxes on a shelf. */
  .tabbar a[href="/stock"] {
    --tab-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='8.2' y='3.5' width='7.6' height='7' rx='1.2'/%3E%3Crect x='3.5' y='13.5' width='7.6' height='7' rx='1.2'/%3E%3Crect x='12.9' y='13.5' width='7.6' height='7' rx='1.2'/%3E%3Cpath d='M12 3.5v2.4M7.3 13.5v2.4M16.7 13.5v2.4'/%3E%3C/g%3E%3C/svg%3E");
  }
  /* Zamu - the shift clock, hands at an honest ten past ten. */
  .tabbar a[href="/shift"] {
    --tab-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.6'/%3E%3Cpath d='M12 7.2V12l3.2 2.1'/%3E%3C/g%3E%3C/svg%3E");
  }
  /* Nyumbani - home. */
  .tabbar a[href="/owner/"] {
    --tab-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.8 10.8 12 3.8l8.2 7'/%3E%3Cpath d='M6 9.9V20h12V9.9'/%3E%3Cpath d='M10.2 20v-4.8h3.6V20'/%3E%3C/g%3E%3C/svg%3E");
  }
  /* Tahadhari - the bell. */
  .tabbar a[href="/owner/alerts"] {
    --tab-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.2 16.2v-5.4a5.8 5.8 0 0 1 11.6 0v5.4l1.6 2.6H4.6z'/%3E%3Cpath d='M10.3 21.2a1.9 1.9 0 0 0 3.4 0'/%3E%3C/g%3E%3C/svg%3E");
  }
  /* Vibali - a decision, sealed. */
  .tabbar a[href="/owner/approvals"] {
    --tab-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.6'/%3E%3Cpath d='m8 12.4 2.8 2.8L16 9.4'/%3E%3C/g%3E%3C/svg%3E");
  }
  /* Ripoti - the chart. */
  .tabbar a[href="/owner/reports"] {
    --tab-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='2.1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20h16'/%3E%3Cpath d='M7.2 20v-5.6M12 20V9.6M16.8 20v-8'/%3E%3C/g%3E%3C/svg%3E");
  }
  /* Zaidi, both areas - the dots are already the default; named here so the
     mapping is complete on the page rather than implied. */
  .tabbar a[href="/more"], .tabbar a[href="/owner/more"] {
    --tab-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='%23000'%3E%3Ccircle cx='5' cy='12' r='2'/%3E%3Ccircle cx='12' cy='12' r='2'/%3E%3Ccircle cx='19' cy='12' r='2'/%3E%3C/g%3E%3C/svg%3E");
  }
}

/* ---------- cards ---------- */

.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 16px; margin: 0 0 14px;
  box-shadow: var(--shadow-1);
  animation: rise 0.4s var(--ease-spring) both;
}
/* A quiet stagger: each card on a page settles a beat after the one above,
   so a dashboard assembles instead of slamming. Capped at six - beyond that
   everything is already on screen and the page must simply be there. */
.narrow > :nth-child(2) { animation-delay: 0.04s; }
.narrow > :nth-child(3) { animation-delay: 0.08s; }
.narrow > :nth-child(4) { animation-delay: 0.12s; }
.narrow > :nth-child(5) { animation-delay: 0.16s; }
.narrow > :nth-child(6) { animation-delay: 0.2s; }

.card.list { padding: 0; }
.card.list .label { padding: 14px 16px 6px; margin: 0; }
.label {
  font-size: 11px; font-weight: 750; text-transform: uppercase;
  letter-spacing: 0.09em; color: var(--muted); margin: 0 0 8px;
}
.ok-card { border-color: var(--good-line); background: var(--good-bg); color: var(--good-fg); }
.bad-card { border-color: var(--bad-line); background: var(--bad-bg); color: var(--bad-fg); }

.listrow {
  display: flex; gap: 12px; align-items: center;
  padding: 14px 16px; min-height: var(--tap);
  border-top: 1px solid var(--line);
  color: inherit; text-decoration: none;
  transition: background-color var(--t-fast) var(--ease);
}
.listrow.column { flex-direction: column; align-items: stretch; }

/* `.stack` on a listrow means the same thing as `.column`, and `owner_audit`
   asks for it by that name.

   IT WAS NOT DEFINED, and the consequence was not cosmetic. `.listrow` is a
   non-wrapping flex ROW, so the audit trail's four spans — the action, the
   time, the reason and the identifier — were laid out side by side instead of
   stacked, and the row ran 616px wide inside a 390px phone. An owner
   investigating a cash difference on their phone had to drag the screen
   sideways to read the reference number, which is the one thing on the row
   they came for.

   Found by measuring `scrollWidth` against `clientWidth` in a real browser at
   the width the brief names. It cannot be found by reading the template: the
   class is there, it looks deliberate, and it silently does nothing.

   `.stack` and `.field` are used ~300 times between them across the templates
   and are otherwise SEMANTIC ONLY — they mark intent on elements that are
   already block-level, where normal flow does the job. That is fine, and it is
   fine precisely because those elements are block. The moment one lands on a
   flex container it stops being fine, which is what happened here.
   `tests/test_stylesheet.py` is the guard. */
.listrow.stack { flex-direction: column; align-items: stretch; }
.card.list .listrow:first-of-type { border-top: none; }
.listrow b { display: block; }
.listrow .muted { display: block; }
a.listrow:active { background: var(--brand-tint); }
@media (hover: hover) {
  a.listrow:hover { background: var(--surface-2); }
}
.chev {
  color: var(--line-strong); font-size: 20px;
  transition: transform var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
a.listrow:active .chev, .person:active .chev { transform: translateX(3px); color: var(--brand); }

/* ---------- buttons ---------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--tap); padding: 12px 18px; gap: 8px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text);
  font: inherit; font-weight: 650; cursor: pointer; text-decoration: none;
  box-shadow: var(--shadow-1);
  position: relative; overflow: hidden;
  transition: transform var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease),
              background-color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease),
              opacity var(--t-fast) var(--ease);
  -webkit-tap-highlight-color: transparent;
}
@media (hover: hover) {
  .btn:hover { transform: translateY(-1px); box-shadow: var(--shadow-2); }
}
.btn:active { transform: translateY(1px) scale(0.985); box-shadow: none; }
.btn.primary {
  background: var(--grad-brand); border-color: var(--brand-dark); color: #fff;
  box-shadow: 0 2px 8px rgba(9, 92, 71, 0.32), inset 0 1px 0 rgba(255, 255, 255, 0.18);
  text-shadow: 0 1px 1px rgba(7, 71, 58, 0.25);
}
/* A single sheen crosses the primary action as it appears: the eye lands on
   "Cash · 12,000" without a single word being added to the screen. Runs
   once - a button that keeps glinting is a button nobody trusts. */
.btn.primary::after {
  content: "";
  position: absolute; inset: 0; pointer-events: none;
  background: var(--grad-sheen);
  animation: sheen 1.1s var(--ease) 0.5s 1 both;
}
@media (hover: hover) {
  .btn.primary:hover { box-shadow: 0 4px 14px rgba(9, 92, 71, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.18); }
}
.btn.danger { background: var(--bad-bg); border-color: var(--bad-line); color: var(--bad-fg); }
.btn.ghost { background: transparent; box-shadow: none; }
.btn.block { display: flex; width: 100%; margin-bottom: 10px; }
.btn.lg { min-height: 56px; font-size: 17px; border-radius: 14px; }
.btn.small { padding: 8px 14px; font-size: 14px; }
.btn.tiny { min-height: 36px; padding: 6px 10px; box-shadow: none; }
.btn[disabled] {
  opacity: 0.45; cursor: not-allowed;
  transform: none; box-shadow: none;
}
.btn[disabled]::after { animation: none; content: none; }

.actions { display: flex; gap: 10px; margin: 0 0 14px; }
.actions form { flex: 1; display: flex; }
.actions .btn { flex: 1; }

/* ---------- forms ---------- */

input, textarea, select {
  font: inherit; color: var(--text); background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 12px 14px; min-height: var(--tap); width: 100%;
  caret-color: var(--brand);
  transition: border-color var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease);
}
input::placeholder, textarea::placeholder { color: #93a29a; }
input:focus, textarea:focus, select:focus {
  border-color: var(--brand); box-shadow: var(--ring); outline: none;
}
.btn:focus-visible, .chip:focus-visible, .key:focus-visible,
.person:focus-visible, .tabbar a:focus-visible, .lang a:focus-visible {
  outline: 3px solid var(--brand); outline-offset: 2px;
}
.big-input { font-size: 24px; font-weight: 700; text-align: right;
             font-variant-numeric: tabular-nums; }
.search { display: flex; gap: 8px; margin: 0 0 14px; }
.search input { flex: 1; border-radius: 999px; padding-left: 18px; }
.search .btn { border-radius: 999px; padding: 12px 20px; }

/* ---------- chips ---------- */

.chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 14px; }
.chip {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-height: var(--tap); min-width: 68px; padding: 8px 14px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text);
  font: inherit; font-weight: 650; cursor: pointer; text-decoration: none;
  box-shadow: var(--shadow-1);
  transition: transform var(--t-fast) var(--ease),
              background-color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.chip:active { transform: scale(0.96); }
.chip.big { min-width: 96px; min-height: 56px; font-size: 17px; }
.chip.on {
  background: var(--grad-brand); border-color: var(--brand); color: #fff;
  box-shadow: 0 2px 8px rgba(9, 92, 71, 0.3);
}
.chip[disabled] { opacity: 0.4; }
.filters { margin-bottom: 12px; }

/* A chip that is really a radio button.

   The input itself is hidden from sight but NOT from screen readers or the
   keyboard: it keeps focus, keeps its name, and still submits. Using
   display:none would take it out of the tab order and leave the group
   unusable without a mouse. */
.chip input[type="radio"],
.chip input[type="checkbox"] {
  position: absolute; opacity: 0; width: 0; height: 0; margin: 0;
  min-height: 0; padding: 0; border: none;
}
.chip:focus-within { outline: 3px solid var(--brand); outline-offset: 2px; }
.chip:has(input:checked) {
  background: var(--grad-brand); border-color: var(--brand); color: #fff;
  box-shadow: 0 2px 8px rgba(9, 92, 71, 0.3);
  animation: pop 0.3s var(--ease-spring);
}

/* ---------- tick lists (warning signs) ---------- */

.checks { list-style: none; margin: 8px 0 0; padding: 0; }
.checks li + li { border-top: 1px solid var(--line); }
.check {
  display: flex; align-items: center; gap: 12px;
  min-height: var(--tap); padding: 6px 2px; cursor: pointer;
  transition: background-color var(--t-fast) var(--ease);
}
/* Full size, not shrunk to look tidy: this is tapped with a thumb, often in a
   hurry, and a missed tap on a warning sign is the failure that matters. */
.check input[type="checkbox"] {
  width: 24px; height: 24px; flex: none; accent-color: var(--brand);
  min-height: 0; padding: 0;
}
/* Inside a tick row the name stands on its own line and a span marked
   `block` really breaks. The rows are flex CHILDREN, so nothing outside
   .check is touched - without this, `block` on a span here is the same
   written-but-undefined trap as `.listrow.stack` above: it reads as
   deliberate, does nothing, and the name only LOOKS stacked when the text
   happens to wrap. */
.check .grow b { display: block; }
.check .grow .block { display: block; }

/* ---------- the customer strip ---------- */

.mteja { padding-top: 10px; padding-bottom: 10px; }
.mteja .label { margin: 0; }

/* ---------- callouts ---------- */

/* Status arrives from the left, the direction the accent bar lives on, and
   each grade wears its own mark - a tick, a bell, a warning triangle, an i -
   so the colour is never the only signal. The mark is painted, not typed:
   an emoji here renders differently on every phone the brief names. */
.callout {
  border: 1px solid var(--line); border-left-width: 4px;
  border-radius: var(--radius-sm); padding: 12px 14px 12px 44px; margin: 0 0 12px;
  background: var(--surface-2);
  position: relative;
  box-shadow: var(--shadow-1);
  animation: slide-in 0.35s var(--ease-spring) both;
}
.callout::before {
  content: "";
  position: absolute; left: 13px; top: 13px; width: 21px; height: 21px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Ccircle cx='10' cy='10' r='9' fill='%235d6b62'/%3E%3Crect x='9' y='8.5' width='2' height='6.5' rx='1' fill='%23fff'/%3E%3Ccircle cx='10' cy='5.8' r='1.3' fill='%23fff'/%3E%3C/svg%3E") center / contain no-repeat;
}
.callout b { display: block; margin-bottom: 2px; }
.callout .btn { margin-top: 8px; }
.callout.good { background: var(--good-bg); border-color: var(--good-line); color: var(--good-fg); }
.callout.good::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Ccircle cx='10' cy='10' r='9' fill='%230a6b4a'/%3E%3Cpath d='M6 10.2l2.7 2.8L14 7.4' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  animation: pop 0.4s var(--ease-spring) 0.15s both;
}
.callout.warn { background: var(--warn-bg); border-color: var(--warn-line); color: var(--warn-fg); }
.callout.warn::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M10 1.8 19 17.2H1z' fill='%238a5a00'/%3E%3Crect x='9' y='7' width='2' height='5.4' rx='1' fill='%23fff'/%3E%3Ccircle cx='10' cy='14.6' r='1.2' fill='%23fff'/%3E%3C/svg%3E");
}
.callout.bad  { background: var(--bad-bg);  border-color: var(--bad-line);  color: var(--bad-fg); }
.callout.bad::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Ccircle cx='10' cy='10' r='9' fill='%23a52019'/%3E%3Cpath d='M7 7l6 6M13 7l-6 6' stroke='%23fff' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
}
.callout.info { background: var(--info-bg); border-color: var(--info-line); color: var(--info-fg); }
.callout.info::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Ccircle cx='10' cy='10' r='9' fill='%231a4d8f'/%3E%3Crect x='9' y='8.5' width='2' height='6.5' rx='1' fill='%23fff'/%3E%3Ccircle cx='10' cy='5.8' r='1.3' fill='%23fff'/%3E%3C/svg%3E");
}

.good-text { color: var(--good-fg); font-weight: 700; }
.warn-text { color: var(--warn-fg); font-weight: 700; }
.bad-text  { color: var(--bad-fg);  font-weight: 700; }

.pill {
  display: inline-block; padding: 4px 11px; border-radius: 999px;
  font-size: 12px; font-weight: 700; background: var(--surface-2);
  border: 1px solid var(--line); white-space: nowrap;
  letter-spacing: 0.01em;
}
.pill.good { background: var(--good-bg); color: var(--good-fg); border-color: var(--good-line); }
.pill.warn { background: var(--warn-bg); color: var(--warn-fg); border-color: var(--warn-line); }
.pill.bad  { background: var(--bad-bg);  color: var(--bad-fg);  border-color: var(--bad-line); }
/* "3 need a decision" breathes, slowly, the way a monitor does. It is the
   one standing animation on the owner's screen, and it marks the one thing
   the screen most wants them to open. */
.pill.bad { animation: pulse-ring 2.6s var(--ease) infinite; }

/* ---------- results and basket ---------- */

.results, .basket, .lines, .issues, .people { list-style: none; margin: 0 0 14px; padding: 0; }
.results li, .basket li, .lines li { border-bottom: 1px solid var(--line); }
.results li:last-child, .basket li:last-child, .lines li:last-child { border-bottom: none; }

.result, .basket li, .lines li {
  display: flex; gap: 12px; align-items: center;
  padding: 14px 4px; min-height: var(--tap);
  color: inherit; text-decoration: none;
}
.result { transition: background-color var(--t-fast) var(--ease); border-radius: 10px; }
a.result:active { background: var(--brand-tint); }
@media (hover: hover) {
  a.result:hover { background: var(--surface-2); }
}
.results { background: var(--surface); border: 1px solid var(--line);
           border-radius: var(--radius); padding: 0 12px;
           box-shadow: var(--shadow-1);
           animation: rise 0.4s var(--ease-spring) both; }
.name { display: block; font-weight: 650; }
.price { font-weight: 700; white-space: nowrap; font-variant-numeric: tabular-nums; }
.qty { font-weight: 700; font-size: 18px; font-variant-numeric: tabular-nums; }
.qty.out { color: var(--bad-fg); animation: pulse-soft 2.4s var(--ease) infinite; }
.qty.low { color: var(--warn-fg); }
.pom {
  display: inline-block; font-size: 10px; font-weight: 800; letter-spacing: 0.06em;
  background: var(--warn-bg); color: var(--warn-fg);
  border: 1px solid var(--warn-line); border-radius: 5px; padding: 1px 6px;
}

.total { display: flex; justify-content: space-between; align-items: baseline;
         margin: 6px 0; gap: 12px; }
.total b, .total .price { font-variant-numeric: tabular-nums; }
.total.big { font-size: 19px; }
.total.big b { color: var(--brand-dark); }

/* ---------- pay bar ---------- */

/*
  Fixed, not sticky. `position: sticky` as the last child of scrolling content
  has zero sticking range, so on a long ticket the pay button simply scrolls
  away — which is exactly when a pharmacist most needs it.
*/
/*
  The pay bar's own height, given back to the page.

  10px padding + a 56px `.btn.lg` + 10px padding + 1px border = 77px, plus a
  little breathing room so the last control is not flush against the bar.
*/
.paybar-space { height: 88px; }

.paybar {
  position: fixed; left: 0; right: 0;
  bottom: calc(72px + env(safe-area-inset-bottom));
  display: flex; gap: 10px; padding: 10px 16px;
  background: var(--surface); border-top: 1px solid var(--line);
  z-index: 25;
  box-shadow: 0 -10px 30px -14px rgba(10, 61, 46, 0.25);
  animation: rise 0.35s var(--ease-spring) both;
}
@supports (backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px)) {
  .paybar {
    background: rgba(255, 255, 255, 0.9);
    -webkit-backdrop-filter: blur(14px) saturate(160%);
    backdrop-filter: blur(14px) saturate(160%);
  }
}
.paybar .btn { margin: 0; }

/* ---------- pick mode ---------- */

/* Deliberately large. Read at arm's length, walking to a shelf. */
.pick { text-align: center; }
.pickname { font-family: var(--font-display); font-size: 23px; font-weight: 700;
            margin: 0 0 6px; letter-spacing: -0.01em; }
.pickshelf { font-size: 17px; color: var(--brand); font-weight: 650; margin: 0 0 14px; }
.pickqty { font-size: 46px; font-weight: 800; margin: 0; line-height: 1;
           font-variant-numeric: tabular-nums;
           animation: pop 0.45s var(--ease-spring) both; }
.pickqty span { font-size: 17px; font-weight: 600; color: var(--muted); }

/* ---------- sign in ---------- */

.people li { border-bottom: 1px solid var(--line); }
.people li:last-child { border-bottom: none; }
.person {
  display: flex; align-items: center; gap: 12px; width: 100%;
  min-height: 56px; padding: 12px 4px; background: none; border: none;
  font: inherit; color: inherit; text-align: left; cursor: pointer;
  border-radius: var(--radius-sm);
  transition: background-color var(--t-fast) var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.person:active { background: var(--brand-tint); }
@media (hover: hover) {
  .person:hover { background: var(--surface-2); }
}
.avatar {
  display: grid; place-items: center; width: 40px; height: 40px;
  border-radius: 50%;
  background: linear-gradient(145deg, var(--brand-tint), var(--brand-tint-2));
  color: var(--brand-dark);
  font-weight: 800; flex: none;
  border: 1px solid rgba(13, 122, 95, 0.15);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7), var(--shadow-1);
}
.avatar.big { width: 52px; height: 52px; font-size: 20px; }

.pips { display: flex; gap: 12px; justify-content: center; padding: 18px 0; }
.pip { width: 13px; height: 13px; border-radius: 50%; background: var(--line);
       transition: background-color var(--t-fast) var(--ease); }
.pip.on { background: var(--grad-brand); animation: pop 0.25s var(--ease-spring); }

.keypad { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.key {
  min-height: 62px; font-size: 24px; font-weight: 600;
  border: 1px solid var(--line); border-radius: 14px;
  background: var(--surface); color: var(--text); cursor: pointer;
  box-shadow: var(--shadow-1);
  font-variant-numeric: tabular-nums;
  transition: transform 0.08s var(--ease), background-color 0.08s var(--ease),
              box-shadow 0.08s var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.key:active { background: var(--brand-tint); transform: scale(0.94); box-shadow: none; }
.key.go {
  background: var(--grad-brand); border-color: var(--brand-dark); color: #fff;
  box-shadow: 0 2px 8px rgba(9, 92, 71, 0.32);
}
.key.go:active { transform: scale(0.94); box-shadow: none; }
.key.ghost { background: transparent; box-shadow: none; }

/* ---------- misc ---------- */

.empty { text-align: center; padding: 48px 16px; }
/* An empty state that looks intended rather than broken: a pale capsule,
   floating gently, above whatever the words say. */
.empty::before {
  content: "";
  display: block; width: 64px; height: 64px; margin: 0 auto 14px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='64'%3E%3Cg transform='rotate(-34 32 32)'%3E%3Crect x='10' y='21' width='44' height='22' rx='11' fill='%23d5ebe2'/%3E%3Cpath d='M32 21h11a11 11 0 0 1 0 22H32z' fill='%230d7a5f'/%3E%3Crect x='31' y='21' width='2' height='22' fill='%23ffffff' fill-opacity='.6'/%3E%3C/g%3E%3Ccircle cx='53' cy='13' r='2.4' fill='%239dd3bd'/%3E%3Ccircle cx='11' cy='51' r='1.8' fill='%239dd3bd'/%3E%3C/svg%3E") center / contain no-repeat;
  animation: float-y 3.4s var(--ease) infinite;
}
.branch .figures { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
.issues li { display: flex; gap: 10px; padding: 8px 0; align-items: baseline; }
.issues li.action { color: var(--bad-fg); font-weight: 600; }
.issues li.watch { color: var(--muted); }
.issues li a { color: inherit; text-decoration: none; }

@media print {
  .topbar, .tabbar, .paybar, .actions, .callout.info { display: none !important; }
  body { padding: 0; background: #fff; }
  body::before { display: none; }
  .card { border: none; box-shadow: none; }
  .card, .callout, .results, .main, .paybar { animation: none; }
}

.centre { text-align: center; }

/* --------------------------------------------------------------------------
   The queue bar

   Sits at the top of the counter, where the thumb already is. A pharmacist
   serving several people needs the way between them to be one tap; buried
   behind a menu it would be a feature nobody uses, and the other tickets would
   go back onto paper.
   -------------------------------------------------------------------------- */
.queuebar {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
  margin: 0 0 .75rem;
}
.queuebar form { margin: 0; }
.queuebar .pill {
  margin: 0;
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--brand-tint); border-color: var(--brand-tint-2);
  color: var(--brand-dark);
}
/* The ticket being served carries a live green dot: the same "this one is
   active" language a monitor uses, readable across a counter. */
.queuebar .pill::before {
  content: "";
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--brand);
  animation: pulse-soft 1.8s var(--ease) infinite;
}

/* The customer being served, in a list of customers who are not. */
.listrow.on { background: var(--good-bg); box-shadow: inset 3px 0 0 var(--brand); }

/* A ticket number, said out loud. Large enough to read at arm's length across
   a counter. */
.listrow .avatar { font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------------------------
   PHOTOGRAPHS

   A picture of the box, so somebody sent to the shelf recognises it. Optional
   everywhere: a medicine with none shows its initial in the same 40px circle
   the rest of the list uses, so the rows do not jump about depending on
   whether a photograph happens to exist.

   Scrolls sideways rather than wrapping. Three views of one box are one glance
   on a phone; a grid that reflows pushes the shelf location off the screen.
   -------------------------------------------------------------------------- */
.thumb {
  display: block; width: 40px; height: 40px; flex: none;
  border-radius: 10px; overflow: hidden; background: var(--surface-2);
  box-shadow: var(--shadow-1);
}
.thumb img { width: 100%; height: 100%; object-fit: cover; display: block;
             transition: transform var(--t-med) var(--ease-spring); }
@media (hover: hover) {
  a:hover .thumb img { transform: scale(1.08); }
}

.photostrip {
  display: flex; gap: .75rem; overflow-x: auto; padding-bottom: .25rem;
  /* So a thumb dragged with a thumb settles on a photograph rather than
     between two. */
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  /* A sideways drag stays a sideways drag: reaching the end of the strip must
     not hand the gesture to the page (or to the browser's back-swipe). */
  overscroll-behavior-x: contain;
}
.photo {
  margin: 0; flex: none; width: 132px; scroll-snap-align: start;
  display: flex; flex-direction: column; gap: .25rem;
}
.photo img {
  width: 132px; height: 132px; object-fit: cover; display: block;
  border-radius: var(--radius-sm); background: var(--surface-2);
  box-shadow: var(--shadow-1);
}
.photo figcaption { text-align: center; }
.photo form.tight { margin: 0; }
.photo form.tight .btn { width: 100%; }

/* A file input is the one control a browser styles its own way. Left mostly
   alone deliberately — the native one is the one a phone's camera button
   appears in, and replacing it with something prettier is how "take a photo"
   stops opening the camera. */
input[type="file"] {
  width: 100%; padding: 10px; border: 1px dashed var(--line-strong);
  border-radius: var(--radius-sm); background: var(--surface-2); font: inherit;
  transition: border-color var(--t-fast) var(--ease),
              background-color var(--t-fast) var(--ease);
}
input[type="file"]:focus { border-color: var(--brand); background: var(--brand-tint); }

/* Two buttons side by side, each taking half the width - Allow and Refuse on
   the approvals screen. Equal width on purpose: a wide "Allow" beside a narrow
   "Refuse" is a decision the layout has already made. */
.row.gap { gap: 10px; }
.row.gap .btn { flex: 1; }

/* --------------------------------------------------------------------------
   ANAHITAJI MSAADA

   Eight complaints as big taps, because the person using this is standing at a
   counter with somebody in front of them and is not going to read a list.
   -------------------------------------------------------------------------- */
.chip.big {
  padding: 14px 18px; font-size: 1.05rem; font-weight: 700;
  min-height: 48px; display: inline-flex; align-items: center;
}

/* The questions to ask. Numbered, because they are asked in order and the
   pharmacist needs to know where they got to when the customer interrupts. */
.asklist { margin: .5rem 0 0; padding-left: 1.4rem; }
.asklist li { margin: .4rem 0; line-height: 1.4; }
.asklist li::marker { color: var(--brand); font-weight: 700; }

/* A quantity box beside a unit selector. Narrow on purpose: the number is one
   or two digits, and a wide field beside a dropdown reads as the important
   half when the unit is what people actually get wrong. */
.qtybox {
  width: 5.5rem; flex: none; text-align: center;
  font-variant-numeric: tabular-nums;
}

/* The arithmetic before the customer hands money over. Right-aligned figures
   in a tabular font so the column reads down and the total is checkable at a
   glance - which is the whole point of showing it. */
.totals .price { font-variant-numeric: tabular-nums; }
.totals .listrow:last-child { border-top: 1px solid var(--line); }

/* A real break between two different decisions. The customer screen holds
   safety answers that belong to THIS SALE above it, and a record that outlives
   the sale below - running them together is how somebody types a phone number
   thinking they are answering a pregnancy question. */
hr.rule { border: none; border-top: 1px solid var(--line); margin: 1.5rem 0; }

/* What the doctor actually wrote, shown as evidence rather than as prose.
   Monospaced and boxed so a pharmacist can see it is a transcription and not
   somebody's summary of one. */
.written {
  font-family: var(--font-mono);
  background: var(--surface-2); border-radius: 10px; padding: 10px 12px;
  margin: 0; white-space: pre-wrap; word-break: break-word;
  border: 1px solid var(--line);
}

/* An identifier, shown so somebody can quote it down a phone line.
   `.mono` was USED and NEVER DEFINED — `owner_audit.html` and
   `owner_system.html` both ask for it and the stylesheet had no such rule. It
   rendered in the body font, which looked fine, and it had no wrapping rule at
   all, which did not: a 26-character ULID has no break opportunity in it, so
   the audit trail was 616px wide inside a 390px phone and an owner
   investigating a cash difference had to drag the screen sideways to read the
   reference. Found by measuring `scrollWidth` in a real browser at the width
   the brief names.

   `break-all` rather than `break-word`, because an identifier has no words in
   it — there is nowhere sensible to break, so anywhere is right. */
.mono {
  font-family: var(--font-mono);
  word-break: break-all;
  overflow-wrap: anywhere;
}

/* A prescription photograph, which has to be readable rather than decorative:
   full width, natural height, and a tap opens it properly. */
.photo.wide { width: 100%; }
.photo.wide img { width: 100%; height: auto; max-height: 60vh; object-fit: contain; }

/* Location-tree indent, one class per level.
   Classes rather than a `style` attribute: `style-src 'self'` blocks inline
   style attributes outright, and a nonce cannot rescue an attribute — so the
   alternative would have been allowing all inline style, which weakens the
   whole policy for a shelf indent. */
.depth-0 { padding-left: 0; }
.depth-1 { padding-left: 14px; }
.depth-2 { padding-left: 28px; }
.depth-3 { padding-left: 42px; }
.depth-4 { padding-left: 56px; }

/* --------------------------------------------------------------------------
   The period bar - Today / This week / This month on every report. A shelf
   of chips rather than a full card's worth of padding, and it was never
   styled by name before.
   -------------------------------------------------------------------------- */
.periodbar { padding: 10px 12px; }
.periodbar .row { row-gap: 8px; }

/* --------------------------------------------------------------------------
   THE MENUS, GIVEN FACES

   The owner's screens are menus - Reports, More - and every row of them was a
   line of text with a chevron. Each known destination now carries a small
   mint tile with its own drawn icon: the same 24-grid, the same rounded pen
   as the dock, inked in brand-dark on a soft gradient, so the list reads like
   a rack of keys rather than a page of prose.

   Keyed off the row's href, so the templates stay exactly as they are. A
   destination without a drawing simply keeps the old text-only row - the
   fallback is the previous design, not a hole. Every icon is vector, so it is
   pin-sharp at any screen density, 4K and retina included, for the cost of a
   few hundred bytes each.
   -------------------------------------------------------------------------- */
a.listrow[href="/owner/staff"]::before,
a.listrow[href="/owner/assistant"]::before,
a.listrow[href="/owner/search"]::before,
a.listrow[href="/assistant/help"]::before,
a.listrow[href="/owner/audit"]::before,
a.listrow[href="/owner/compliance-settings"]::before,
a.listrow[href="/supply/"]::before,
a.listrow[href="/owner/system"]::before,
a.listrow[href="/owner/requests"]::before,
a.listrow[href^="/owner/reports/products"]::before,
a.listrow[href^="/owner/reports/stock"]::before,
a.listrow[href^="/owner/reports/suppliers"]::before,
a.listrow[href^="/owner/reports/staff"]::before,
a.listrow[href="/shift"]::before,
a.listrow[href="/stock"]::before,
a.listrow[href="/counter"]::before {
  content: "";
  width: 42px; height: 42px; flex: none;
  border-radius: 13px;
  background-color: var(--brand-tint);
  background-image: var(--row-icon),
    linear-gradient(150deg, #f2faf6 8%, var(--brand-tint-2) 96%);
  background-repeat: no-repeat;
  background-position: center;
  background-size: 23px 23px, cover;
  border: 1px solid rgba(13, 122, 95, 0.14);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.85),
              0 1px 4px rgba(13, 122, 95, 0.14);
  transition: transform var(--t-fast) var(--ease-spring);
}
/* The tile answers the thumb the way the dock does. Rows without a tile have
   no ::before box, so the rule costs them nothing. */
a.listrow:active::before { transform: scale(0.92); }

/* Dawa - a capsule, the same one the empty state floats. */
a.listrow[href^="/owner/reports/products"] {
  --row-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23095c47' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round' transform='rotate(-35 12 12)'%3E%3Crect x='4.2' y='8.6' width='15.6' height='6.8' rx='3.4'/%3E%3Cpath d='M12 8.6v6.8'/%3E%3C/g%3E%3C/svg%3E");
}
/* Stoo - the shelf boxes the dock already wears. */
a.listrow[href^="/owner/reports/stock"],
a.listrow[href="/stock"] {
  --row-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23095c47' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='8.2' y='3.5' width='7.6' height='7' rx='1.2'/%3E%3Crect x='3.5' y='13.5' width='7.6' height='7' rx='1.2'/%3E%3Crect x='12.9' y='13.5' width='7.6' height='7' rx='1.2'/%3E%3Cpath d='M12 3.5v2.4M7.3 13.5v2.4M16.7 13.5v2.4'/%3E%3C/g%3E%3C/svg%3E");
}
/* Wasambazaji - the delivery truck. */
a.listrow[href^="/owner/reports/suppliers"] {
  --row-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23095c47' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.8 7h11.4v9.2H2.8z'/%3E%3Cpath d='M14.2 9.6h3.5l3.1 3.3v3.3h-6.6'/%3E%3Ccircle cx='7' cy='18.3' r='1.8'/%3E%3Ccircle cx='16.9' cy='18.3' r='1.8'/%3E%3C/g%3E%3C/svg%3E");
}
/* Walichoomba wateja - a question, asked across the counter. */
a.listrow[href="/owner/requests"] {
  --row-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23095c47' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 5.4h16v10.4h-8.6L7.2 19.2v-3.4H4z'/%3E%3Cpath d='M10.3 9.2a1.8 1.8 0 1 1 2.5 1.65c-.55.25-.8.55-.8 1.15'/%3E%3Cpath d='M12 13.9v.01'/%3E%3C/g%3E%3C/svg%3E");
}
/* Wafanyakazi, in both meanings - the report and the management screen. */
a.listrow[href^="/owner/reports/staff"],
a.listrow[href="/owner/staff"] {
  --row-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23095c47' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='8.4' r='3.2'/%3E%3Cpath d='M3.6 19.6c.5-3.3 2.7-5.2 5.4-5.2s4.9 1.9 5.4 5.2'/%3E%3Cpath d='M15.4 5.7a3.2 3.2 0 0 1 0 5.4'/%3E%3Cpath d='M17.3 14.6c1.8.7 3 2.4 3.3 5'/%3E%3C/g%3E%3C/svg%3E");
}
/* Kumbukumbu - the bound ledger. Reading only. */
a.listrow[href="/owner/audit"] {
  --row-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23095c47' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.4 3.6H19v16.8H6.4A2.4 2.4 0 0 1 4 18V6a2.4 2.4 0 0 1 2.4-2.4z'/%3E%3Cpath d='M4 18a2.4 2.4 0 0 1 2.4-2.4H19'/%3E%3Cpath d='M9 8h6M9 11.2h6'/%3E%3C/g%3E%3C/svg%3E");
}
/* Rafiki wa Biashara - the spark. */
a.listrow[href="/owner/assistant"] {
  --row-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23095c47' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M11 4.6 12.7 9l4.4 1.7-4.4 1.7L11 16.8l-1.7-4.4-4.4-1.7L9.3 9z'/%3E%3Cpath d='m18.2 14.8.9 2.2 2.2.9-2.2.9-.9 2.2-.9-2.2-2.2-.9 2.2-.9z'/%3E%3C/g%3E%3C/svg%3E");
}
/* Tafuta - the magnifier. */
a.listrow[href="/owner/search"] {
  --row-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23095c47' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='10.8' cy='10.8' r='6.3'/%3E%3Cpath d='m15.5 15.5 4.6 4.6'/%3E%3C/g%3E%3C/svg%3E");
}
/* Msaada - the lifebuoy. */
a.listrow[href="/assistant/help"] {
  --row-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23095c47' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.4'/%3E%3Ccircle cx='12' cy='12' r='3.4'/%3E%3Cpath d='m6.1 6.1 3.5 3.5M14.4 14.4l3.5 3.5M17.9 6.1l-3.5 3.5M9.6 14.4l-3.5 3.5'/%3E%3C/g%3E%3C/svg%3E");
}
/* Leseni, TRA na faragha - the shield, sealed. */
a.listrow[href="/owner/compliance-settings"] {
  --row-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23095c47' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.4 19 6v5.4c0 4.6-2.9 7.6-7 9.2-4.1-1.6-7-4.6-7-9.2V6z'/%3E%3Cpath d='m8.8 11.8 2.3 2.3 4.1-4.4'/%3E%3C/g%3E%3C/svg%3E");
}
/* Manunuzi - the cart. */
a.listrow[href="/supply/"] {
  --row-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23095c47' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 4.6h2.5l2.2 9.8h10.6l1.9-7.2H6.2'/%3E%3Ccircle cx='9.3' cy='18.8' r='1.7'/%3E%3Ccircle cx='16.5' cy='18.8' r='1.7'/%3E%3C/g%3E%3C/svg%3E");
}
/* Afya ya Mfumo - a pulse on a monitor. */
a.listrow[href="/owner/system"] {
  --row-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23095c47' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4.8' width='18' height='14.4' rx='3'/%3E%3Cpath d='M6.2 12h2.6l1.7-3.4 2.9 6.8 1.7-3.4h2.7'/%3E%3C/g%3E%3C/svg%3E");
}
/* Zamu yangu - the shift clock the dock wears. */
a.listrow[href="/shift"] {
  --row-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23095c47' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.6'/%3E%3Cpath d='M12 7.2V12l3.2 2.1'/%3E%3C/g%3E%3C/svg%3E");
}
/* Kaunta - the storefront the dock wears. */
a.listrow[href="/counter"] {
  --row-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23095c47' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 4h14l1.6 5H3.4z'/%3E%3Cpath d='M3.4 9a2.15 2.15 0 0 0 4.3 0 2.15 2.15 0 0 0 4.3 0 2.15 2.15 0 0 0 4.3 0 2.15 2.15 0 0 0 4.3 0'/%3E%3Cpath d='M5 12.6V20h14v-7.4'/%3E%3Cpath d='M9.8 20v-4.6h4.4V20'/%3E%3C/g%3E%3C/svg%3E");
}

/* --------------------------------------------------------------------------
   THE HEADLINE FIGURES

   The first card of a report holds the number the owner opened the page for.
   Where the browser understands :has() it gets a quiet mint wash and a
   brand-gradient headline figure; where it does not, the plain card and the
   plain dark-green figure remain, and both are the complete design. Screen
   only: a receipt's grand total must PRINT, and printers do not paint
   background gradients - clipped to one, the figure would print as nothing.
   -------------------------------------------------------------------------- */
@media screen {
  .card:has(> .total.big:first-child) {
    background: linear-gradient(165deg, #ffffff 45%, var(--brand-tint) 130%);
    border-color: var(--brand-tint-2);
    box-shadow: var(--shadow-2);
  }
  @supports (-webkit-background-clip: text) or (background-clip: text) {
    .total.big b {
      background: var(--grad-brand);
      -webkit-background-clip: text;
      background-clip: text;
      color: transparent;
    }
  }
}

/* The branch card on the owner's home wears a thin brand ribbon along its top
   edge - the one card on the screen that IS the business gets the flag. */
.card.branch { position: relative; overflow: hidden; }
.card.branch::before {
  content: "";
  position: absolute; top: 0; left: 0; right: 0; height: 3px;
  background: var(--grad-brand);
}

/* --------------------------------------------------------------------------
   STILLNESS

   One switch, at the end so it wins. Somebody who has asked their phone for
   less motion gets none: no entrances, no pulses, no floating capsule, no
   page transitions. The site is exactly as complete standing still - that is
   the test every animation above had to pass to be allowed in.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001s !important;
  }
  .empty::before, .queuebar .pill::before, .qty.out, .pill.bad {
    animation: none !important;
  }
}
