/* ==========================================================================
   owner.css — KleinVet pet-owner portal
   --------------------------------------------------------------------------
   Scope: /owner.html only. The clinical/staff app uses styles.css + motion.css
   and shares nothing with this file. Keep it that way: this surface has a
   consumer voice and a consumer layout, and coupling it to the staff shell is
   how it ended up looking like an internal tool.

   Structure
     1.  Design tokens (light) and dark-mode overrides
     2.  Reset + base typography
     3.  Layout primitives: shell, topbar, content, bottom tab bar
     4.  Building blocks: card, button, field, message, badge, chip
     5.  Pre-auth splash (no sign-in UI — index.html owns the front door)
     6.  Scan view (guided steps, photo capture, safety, consent)
     7.  Pets view (profiles + edit sheet)
     8.  Settings view (identity, availability, consultations)
     9.  Utilities, motion, RTL, print/reduced-motion

   Conventions
     - Mobile-first. Every media query is min-width; the phone layout is the
       base layout, not an override.
     - Logical properties (inline-start/end, margin-inline) everywhere so the
       Arabic RTL flip is free. Never use `left`/`right` for spacing.
     - Colour only via custom properties so dark mode is a token swap.
     - Tap targets are >= 44px. Primary actions sit low, in thumb reach.
   ========================================================================== */


/* ==========================================================================
   1. Design tokens
   ========================================================================== */

:root {
  /* --- Brand: mapped onto the shared ramp in tokens.css --------------------
     These were once independent hexes (#0a7d68 and friends), which is how this
     surface came to render a different teal from the rest of the product. They
     are now aliases by ROLE: the primary action, its pressed state, a subtle
     fill, and readable ink on that fill. Change the ramp in tokens.css, never
     here. ------------------------------------------------------------------ */
  --brand:            var(--accent-700);
  --brand-strong:     var(--accent-800);
  --brand-soft:       var(--accent-50);
  --brand-ink:        var(--accent-900);

  /* --- Surfaces: the shared cream/navy set from tokens.css, so this surface
        matches the staff app instead of inventing a green-tinted paper. ---- */
  --paper:            #f4f1e8;   /* app background (tokens --bg / --cream)    */
  --card:             #fffdf8;   /* tokens --surface                          */
  --card-sunken:      #f8f6ef;   /* tokens --surface-2 (inputs, panels)       */
  --line:             rgba(11, 34, 66, .15);   /* tokens --border-2           */
  /* Input boundaries must reach 3:1 against the card AND the sunken fill
     (WCAG 1.4.11). At .24 alpha this composited to 1.66:1; .52 gives 3.3:1. */
  --line-strong:      rgba(11, 34, 66, .52);

  /* --- Text: navy ink, not the old green ink -------------------------------- */
  --ink:              #10243d;   /* tokens --ink                              */
  --ink-soft:         #34475b;   /* tokens --ink-2                            */
  --muted:            #5d666b;   /* tokens --muted (4.5:1+ on every surface)  */

  /* --- Status ------------------------------------------------------------ */
  --ok:               #0a7d68;
  --ok-soft:          #e2f1eb;
  --warn:             #8a5314;
  --warn-soft:        #fbf0df;
  --danger:           #a83a2c;
  --danger-soft:      #fbe9e6;
  --info:             #2a5c86;
  --info-soft:        #e6f0f8;

  /* --- Elevation --------------------------------------------------------- */
  --shadow-sm:        0 1px 2px rgba(20, 45, 38, .06),
                      0 2px 6px rgba(20, 45, 38, .05);
  --shadow-md:        0 4px 12px rgba(20, 45, 38, .07),
                      0 12px 32px rgba(20, 45, 38, .06);
  --shadow-lg:        0 12px 28px rgba(20, 45, 38, .10),
                      0 32px 64px rgba(20, 45, 38, .10);

  /* --- Geometry ---------------------------------------------------------- */
  --r-sm: 10px;
  --r-md: 14px;
  --r-lg: 20px;
  --r-xl: 26px;
  --r-pill: 999px;

  /* --- Spacing scale (used verbatim, no ad-hoc pixel values) -------------- */
  --s-1: 4px;
  --s-2: 8px;
  --s-3: 12px;
  --s-4: 16px;
  --s-5: 22px;
  --s-6: 30px;
  --s-7: 40px;
  --s-8: 56px;

  /* Solid, not .28 alpha: the old ring composited to 1.48:1 and added
     nothing a screen could see. The :focus-visible outline remains the
     primary indicator; this ring now also clears 3:1 on its own. */
  --focus-ring: 0 0 0 3px var(--brand);

  color-scheme: light;
}

/* Dark mode is a pure token swap — no component rule below re-declares colour
   for dark. Contrast targets: body text >= 7:1, secondary >= 4.5:1 on --card.
   Gated on an explicit data-theme="dark" opt-in (never prefers-color-scheme),
   exactly like tokens.css and the staff app: the owner page has no theme
   toggle, so it must default to the cream light theme regardless of OS setting
   rather than silently follow a dark OS into a palette that clashes with the
   rest of the product. Values are the navy gray ramp from tokens.css. */
:root[data-theme="dark"] {
    /* Dark inverts the ramp: a 700 primary is unreadable on a dark ground,
       so the light end carries the action and the dark end the fill. */
    --brand:          var(--accent-400);
    --brand-strong:   var(--accent-300);
    --brand-soft:     var(--accent-900);
    --brand-ink:      var(--accent-200);

    --paper:          #06172f;   /* tokens --gray-950 */
    --card:           #0c2140;   /* tokens --gray-900 */
    --card-sunken:    #172d49;   /* tokens --gray-800 */
    --line:           rgba(255, 255, 255, .10);
    --line-strong:    rgba(255, 255, 255, .36);

    --ink:            #faf8f2;   /* tokens --gray-50  */
    --ink-soft:       #c7c1b7;   /* tokens --gray-300 */
    --muted:          #939a9e;   /* tokens --gray-450 */

    --ok:             #4fc4aa;
    --ok-soft:        #16332d;
    --warn:           #e8b775;
    --warn-soft:      #33280f;
    --danger:         #f09a8c;
    --danger-soft:    #38201c;
    --info:           #8ec2ec;
    --info-soft:      #16283a;

    --shadow-sm:      0 1px 2px rgba(0, 0, 0, .40);
    --shadow-md:      0 4px 14px rgba(0, 0, 0, .45);
    --shadow-lg:      0 16px 40px rgba(0, 0, 0, .55);

    --focus-ring:     0 0 0 3px var(--brand);

    color-scheme: dark;
}


/* ==========================================================================
   2. Reset + base typography
   ========================================================================== */

*,
*::before,
*::after { box-sizing: border-box; }

[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100dvh;
  background: var(--paper);
  color: var(--ink);
  font-family: "Inter", "Segoe UI", system-ui, -apple-system, "Noto Sans Arabic",
               "Segoe UI Arabic", sans-serif;
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

/* Typographic hierarchy. Sizes are fluid on the two display levels only —
   body copy stays at a fixed, comfortable reading size on every device. */
h1, h2, h3 {
  margin: 0;
  color: var(--ink);
  font-weight: 700;
  letter-spacing: -.02em;
  line-height: 1.15;
  text-wrap: balance;
}
h1 { font-size: clamp(28px, 6.5vw, 38px); }
h2 { font-size: 20px; }
h3 { font-size: 16px; letter-spacing: -.01em; }

p { margin: 0; }

.eyebrow {
  margin: 0 0 var(--s-2);
  color: var(--brand);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
}

.lead {
  color: var(--ink-soft);
  font-size: 16px;
  max-width: 46ch;
}

.muted { color: var(--muted); }

.fine {
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
}

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

/* One focus treatment for the whole portal. Visible, never removed. */
:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

/* Screen-reader-only text (used for live-region prefixes and icon labels). */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}


/* ==========================================================================
   3. Layout primitives
   ========================================================================== */

.shell {
  width: 100%;
  max-width: 720px;
  margin-inline: auto;
  min-height: 100dvh;
}

.wordmark {
  display: inline-flex;
  align-items: baseline;
  gap: 1px;
  color: var(--ink);
  font-size: 21px;
  font-weight: 800;
  letter-spacing: -.03em;
  text-decoration: none;
}
.wordmark span { color: var(--brand); }

/* --- Sticky top bar ------------------------------------------------------ */
.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  min-height: 64px;
  padding-inline: var(--s-5);
  padding-block: var(--s-2);
  padding-top: max(var(--s-2), env(safe-area-inset-top));
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  border-bottom: 1px solid var(--line);
  backdrop-filter: blur(14px);
}

.topbar-actions {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

/* --- Scrollable content region ------------------------------------------ */
.content {
  /* Bottom padding clears the fixed tab bar plus the home indicator. */
  padding: var(--s-6) var(--s-5) calc(var(--s-8) + 78px);
}

.view { display: none; }
.view.active {
  display: grid;
  gap: var(--s-5);
  animation: view-in .22s ease-out;
}

@keyframes view-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

.view-head { display: grid; gap: var(--s-2); }

.section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
}

/* --- Bottom tab bar ------------------------------------------------------ */
.tabs {
  position: fixed;
  inset-block-end: 0;
  inset-inline: 0;
  z-index: 30;
  width: min(720px, 100%);
  margin-inline: auto;
  display: grid;
  /* Size tracks from visible tabs: hardcoded counts break when tabs are added
     and when anonymous mode hides all but the front door. */
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: var(--s-1);
  padding: var(--s-2) var(--s-3);
  padding-bottom: calc(var(--s-2) + env(safe-area-inset-bottom));
  background: color-mix(in srgb, var(--card) 94%, transparent);
  border-top: 1px solid var(--line);
  backdrop-filter: blur(18px);
}

.tabs button {
  display: grid;
  place-items: center;
  gap: 3px;
  min-height: 54px;
  padding: var(--s-2) var(--s-1);
  border: 0;
  border-radius: var(--r-md);
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 11.5px;
  font-weight: 650;
  cursor: pointer;
}
.tabs button .tab-icon {
  display: block;
  width: 24px;
  height: 24px;
}
/* Five tabs leave ~64px per track at 360px. A two-word label ("Skin check")
   must not wrap to a second line there, or the bar grows and the tallest tab
   drags the rest with it. Shrink the type instead. */
.tabs button span {
  white-space: nowrap;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}
@media (max-width: 380px) {
  .tabs button { font-size: 10.5px; }
  .tabs button .tab-icon { width: 22px; height: 22px; }
}
.tabs button[aria-selected="true"] {
  background: var(--brand-soft);
  color: var(--brand-ink);
}
.tabs button:hover { color: var(--ink); }


/* ==========================================================================
   4. Building blocks
   ========================================================================== */

/* --- Card ---------------------------------------------------------------- */
.card {
  display: grid;
  gap: var(--s-4);
  padding: var(--s-5);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-sm);
}
.card.quiet { box-shadow: none; background: transparent; }

/* --- Buttons ------------------------------------------------------------- */
button { font: inherit; cursor: pointer; }
button[disabled] { cursor: not-allowed; opacity: .55; }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: 50px;
  padding: var(--s-3) var(--s-5);
  border: 1px solid transparent;
  border-radius: var(--r-md);
  font-weight: 700;
  text-decoration: none;
  transition: background-color .15s ease, transform .1s ease, border-color .15s ease;
}
.btn:active:not([disabled]) { transform: translateY(1px); }
.btn:focus-visible { box-shadow: var(--focus-ring); }

.btn-primary {
  background: var(--brand);
  color: #ffffff;
}
:root[data-theme="dark"] .btn-primary { color: #06231d; }
.btn-primary:hover:not([disabled]) { background: var(--brand-strong); }

.btn-secondary {
  background: var(--card);
  border-color: var(--line-strong);
  color: var(--ink);
}
.btn-secondary:hover:not([disabled]) { border-color: var(--brand); color: var(--brand); }

.btn-soft {
  background: var(--brand-soft);
  color: var(--brand-ink);
  min-height: 44px;
  padding-inline: var(--s-4);
  font-size: 14px;
}

.btn-ghost {
  background: transparent;
  color: var(--brand);
  min-height: 44px;
  padding-inline: var(--s-3);
}

.btn-danger-ghost {
  background: transparent;
  color: var(--danger);
  min-height: 48px;
  font-weight: 650;
}

.btn-block { width: 100%; }

/* Icon-only control (sheet close, avatar). Square, 44px, labelled by aria. */
.icon-btn {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--ink-soft);
}
.icon-btn:hover { background: var(--card-sunken); color: var(--ink); }
.icon-btn:focus-visible { box-shadow: var(--focus-ring); }

.avatar {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--brand-soft);
  color: var(--brand-ink);
  font-size: 14px;
  font-weight: 800;
  letter-spacing: .02em;
}
button.avatar:hover { background: color-mix(in srgb, var(--brand-soft) 70%, var(--brand)); }

/* --- Form fields --------------------------------------------------------- */
form { display: grid; gap: var(--s-4); }

.field {
  display: grid;
  gap: var(--s-2);
}
.field > .field-label {
  font-size: 14px;
  font-weight: 650;
  color: var(--ink);
}
.field > .field-hint {
  font-size: 13px;
  color: var(--muted);
  order: 3;              /* hint renders under the control                   */
}

input[type="email"],
input[type="password"],
input[type="text"],
input[type="date"],
select,
textarea {
  width: 100%;
  min-height: 50px;
  padding: var(--s-3) var(--s-4);
  font: inherit;
  font-size: 16px;        /* 16px prevents the iOS zoom-on-focus jump        */
  color: var(--ink);
  background: var(--card-sunken);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  outline: none;
  appearance: none;
}
textarea { min-height: 96px; resize: vertical; line-height: 1.5; }

select {
  /* Chevron drawn inline so no network asset is required. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='9' viewBox='0 0 14 9'%3E%3Cpath d='M1 1l6 6 6-6' fill='none' stroke='%236b7873' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--s-4) center;
  padding-inline-end: var(--s-7);
}
[dir="rtl"] select { background-position: left var(--s-4) center; }

input:focus,
select:focus,
textarea:focus {
  border-color: var(--brand);
  box-shadow: var(--focus-ring);
}

input::placeholder,
textarea::placeholder { color: var(--muted); opacity: 1; }

.grid-two {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s-4);
}

/* --- Checkbox rows ------------------------------------------------------- */
.check {
  display: grid;
  grid-template-columns: 22px 1fr;
  align-items: start;
  gap: var(--s-3);
  padding: var(--s-4);
  background: var(--card-sunken);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  font-size: 14.5px;
  font-weight: 400;
  line-height: 1.5;
  cursor: pointer;
}
.check:has(input:focus-visible) { border-color: var(--brand); box-shadow: var(--focus-ring); }
.check:has(input:checked) { border-color: var(--brand); background: var(--brand-soft); }
.check input[type="checkbox"] {
  width: 22px;
  height: 22px;
  margin: 0;
  accent-color: var(--brand);
  cursor: pointer;
}
.check .check-title { display: block; font-weight: 650; color: var(--ink); }
.check .check-body  { display: block; color: var(--ink-soft); }

/* --- Toggle row (settings) ----------------------------------------------- */
.toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding-block: var(--s-3);
  cursor: pointer;
}
.toggle > span { display: grid; gap: 2px; font-size: 15px; font-weight: 650; }
.toggle small { color: var(--muted); font-weight: 400; font-size: 13px; }
.toggle input[type="checkbox"] {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  accent-color: var(--brand);
}

/* --- Inline status message (aria-live target) ---------------------------- */
.message {
  margin: 0;
  font-size: 14px;
  line-height: 1.45;
  color: var(--ink-soft);
}
.message:empty { display: none; }
.message.error,
.message.ok,
.message.info {
  display: flex;
  align-items: flex-start;
  gap: var(--s-2);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  font-weight: 600;
}
.message.error { background: var(--danger-soft); color: var(--danger); }
.message.ok    { background: var(--ok-soft);     color: var(--brand-ink); }
.message.info  { background: var(--info-soft);   color: var(--info); }

/* --- Badge / chip -------------------------------------------------------- */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  padding: 5px var(--s-3);
  border-radius: var(--r-pill);
  font-size: 11.5px;
  font-weight: 750;
  letter-spacing: .02em;
  white-space: nowrap;
}
.badge-review { background: var(--info-soft);  color: var(--info); }
.badge-ok     { background: var(--ok-soft);    color: var(--brand-ink); }
.badge-warn   { background: var(--warn-soft);  color: var(--warn); }
.badge-muted  { background: var(--card-sunken); color: var(--muted); }

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  padding: 4px var(--s-3);
  border-radius: var(--r-pill);
  background: var(--card-sunken);
  border: 1px solid var(--line);
  color: var(--ink-soft);
  font-size: 12.5px;
  font-weight: 600;
}

/* --- Empty / loading / skeleton states ----------------------------------- */
.empty {
  display: grid;
  justify-items: center;
  gap: var(--s-3);
  padding: var(--s-7) var(--s-5);
  text-align: center;
  background: var(--card);
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-xl);
}
.empty-art {
  display: grid;
  place-items: center;
  width: 64px;
  height: 64px;
  border-radius: var(--r-pill);
  background: var(--brand-soft);
  color: var(--brand);
}
.empty h3 { font-size: 17px; }
.empty p { color: var(--muted); font-size: 14px; max-width: 34ch; }

.skeleton {
  border-radius: var(--r-md);
  background: linear-gradient(90deg,
              var(--card-sunken) 25%,
              color-mix(in srgb, var(--line) 60%, var(--card-sunken)) 37%,
              var(--card-sunken) 63%);
  background-size: 400% 100%;
  animation: shimmer 1.4s ease-in-out infinite;
}
.skeleton-row { height: 76px; margin-bottom: var(--s-3); }

@keyframes shimmer {
  from { background-position: 100% 0; }
  to   { background-position: 0 0; }
}

/* Button busy state: a spinner replaces nothing, it sits beside the label. */
.spinner {
  width: 17px;
  height: 17px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: var(--r-pill);
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }


/* ==========================================================================
   5. Pre-auth splash
   --------------------------------------------------------------------------
   This page has no sign-in UI — index.html #screen-role is the only front
   door. owner.js resolves the session first and redirects unauthenticated or
   gated visitors to "/". Until that resolves, this is all that paints: a
   wordmark and a spinner on the app background. Deliberately not portal
   chrome, so a redirect never flashes tabs or forms at someone who is about
   to be sent away.
   ========================================================================== */

.boot {
  display: grid;
  place-content: center;
  justify-items: center;
  gap: var(--s-5);
  min-height: 100dvh;
  padding: var(--s-6);
}
.boot .spinner { color: var(--brand); width: 22px; height: 22px; }

/* ==========================================================================
   6. Scan view
   ========================================================================== */

/* Numbered step cards. The flow stays one <form> (so a single submit and one
   native validation pass), but each stage reads as its own labelled step. */
.step {
  display: grid;
  gap: var(--s-4);
  padding: var(--s-5);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-sm);
}

.step-head {
  display: grid;
  grid-template-columns: 32px 1fr;
  align-items: center;
  gap: var(--s-3);
}
.step-num {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: var(--r-pill);
  background: var(--brand-soft);
  color: var(--brand-ink);
  font-size: 14px;
  font-weight: 800;
}
.step-head h2 { font-size: 17px; }
.step-head .step-sub {
  grid-column: 2;
  color: var(--muted);
  font-size: 13.5px;
}

/* --- Photo capture ------------------------------------------------------- */
.camera {
  display: grid;
  justify-items: center;
  gap: var(--s-2);
  min-height: 176px;
  padding: var(--s-6) var(--s-4);
  text-align: center;
  background: var(--card-sunken);
  border: 1.5px dashed var(--line-strong);
  border-radius: var(--r-lg);
  color: var(--brand-ink);
  cursor: pointer;
}
.camera:hover { border-color: var(--brand); background: var(--brand-soft); }
.camera:has(input:focus-visible) { border-color: var(--brand); box-shadow: var(--focus-ring); }
.camera input[type="file"] {
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  pointer-events: none;
}
.camera .camera-icon { color: var(--brand); }
.camera strong { font-size: 16px; }
.camera small { color: var(--muted); font-size: 13px; }

.preview-wrap { position: relative; }
.preview-wrap img {
  display: block;
  width: 100%;
  max-height: 320px;
  object-fit: cover;
  border-radius: var(--r-lg);
  background: var(--card-sunken);
}
.preview-wrap .preview-remove {
  position: absolute;
  inset-block-start: var(--s-3);
  inset-inline-end: var(--s-3);
  min-height: 40px;
  padding: var(--s-2) var(--s-4);
  border: 0;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .94);
  color: #1b2b26;
  font-size: 13px;
  font-weight: 700;
  box-shadow: var(--shadow-sm);
}

/* Photo guidance: four short do-this lines, shown before the picker so the
   owner reads them while deciding, not after a rejected upload. */
.photo-tips {
  display: grid;
  gap: var(--s-2);
  margin: 0;
  padding: var(--s-4);
  background: var(--brand-soft);
  border-radius: var(--r-md);
  list-style: none;
}
.photo-tips li {
  display: grid;
  grid-template-columns: 18px 1fr;
  align-items: start;
  gap: var(--s-3);
  color: var(--brand-ink);
  font-size: 13.5px;
  line-height: 1.45;
}
.photo-tips svg { margin-top: 2px; }

/* --- Urgent-signs safety block ------------------------------------------- */
.urgent {
  display: grid;
  gap: var(--s-3);
  margin: 0;
  padding: var(--s-4);
  border: 1px solid color-mix(in srgb, var(--danger) 35%, var(--line));
  border-radius: var(--r-lg);
  background: var(--danger-soft);
}
.urgent legend {
  padding-inline: var(--s-2);
  color: var(--danger);
  font-size: 13px;
  font-weight: 750;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.urgent .check {
  background: var(--card);
  border-color: color-mix(in srgb, var(--danger) 25%, var(--line));
}
.urgent .check:has(input:checked) {
  background: var(--card);
  border-color: var(--danger);
}
.urgent-callout {
  display: grid;
  gap: var(--s-2);
  padding: var(--s-4);
  border-radius: var(--r-md);
  background: var(--card);
  border: 1px solid var(--danger);
  color: var(--danger);
  font-weight: 650;
  font-size: 14px;
}

/* --- Submit dock: the primary action sits at the bottom, in thumb reach --- */
.submit-dock {
  display: grid;
  gap: var(--s-3);
}

/* --- Case / observation status cards ------------------------------------- */
.case-list { display: grid; gap: var(--s-3); }

.case-card {
  display: grid;
  gap: var(--s-3);
  padding: var(--s-5);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
}
.case-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
}
.case-card-head strong { font-size: 16px; }
.case-card p { color: var(--ink-soft); font-size: 14px; }
.case-card time { color: var(--muted); font-size: 13px; }

/* The vet-review timeline. Three fixed stages; the current one is filled.
   This is the whole result surface while AI output is gated — it tells the
   owner what a human is doing with their photo, and never guesses. */
.review-track {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s-2);
  margin: 0;
  padding: 0;
  list-style: none;
}
.review-track li {
  display: grid;
  gap: var(--s-2);
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
}
.review-track li::before {
  content: "";
  display: block;
  height: 5px;
  border-radius: var(--r-pill);
  background: var(--line);
}
.review-track li[data-state="done"],
.review-track li[data-state="current"] { color: var(--brand-ink); }
.review-track li[data-state="done"]::before { background: var(--brand); }
.review-track li[data-state="current"]::before {
  background: linear-gradient(90deg, var(--brand) 50%, var(--line) 50%);
}


/* ==========================================================================
   7. Pets view
   ========================================================================== */

.pets-list { display: grid; gap: var(--s-3); }

/* A pet is a profile: portrait glyph, name, a line of identity facts, and an
   edit affordance. Not a table row. */
.pet-card {
  display: grid;
  grid-template-columns: 56px 1fr auto;
  align-items: center;
  gap: var(--s-4);
  padding: var(--s-4);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  text-align: start;
}
.pet-glyph {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: var(--r-lg);
  background: var(--brand-soft);
  color: var(--brand);
}
.pet-identity { display: grid; gap: var(--s-1); min-width: 0; }
.pet-identity strong { font-size: 16.5px; font-weight: 700; }
.pet-facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  color: var(--muted);
  font-size: 13px;
}
.pet-facts .dot { color: var(--line-strong); }
.pet-note {
  color: var(--muted);
  font-size: 13px;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

/* --- Edit sheet (native <dialog>) ---------------------------------------- */
.sheet {
  width: min(560px, 100%);
  max-height: 92dvh;
  margin: auto;
  margin-block-end: 0;
  padding: 0;
  border: 0;
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  background: var(--card);
  color: var(--ink);
  overflow: hidden;
  box-shadow: var(--shadow-lg);
}
.sheet::backdrop { background: rgba(12, 22, 19, .5); backdrop-filter: blur(2px); }
.sheet[open] { animation: sheet-in .24s cubic-bezier(.2, .8, .3, 1); }

@keyframes sheet-in {
  from { transform: translateY(24px); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

.sheet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--line);
}
.sheet-body {
  padding: var(--s-5);
  padding-bottom: calc(var(--s-5) + env(safe-area-inset-bottom));
  overflow-y: auto;
  max-height: calc(92dvh - 70px);
}


/* ==========================================================================
   8. Settings view
   ========================================================================== */

.identity {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  padding-bottom: var(--s-4);
  border-bottom: 1px solid var(--line);
}
.identity .avatar { width: 52px; height: 52px; font-size: 16px; }
.identity strong { display: block; font-size: 16px; }
.identity small { display: block; color: var(--muted); font-size: 13.5px; }

/* Service availability. Honest, plain-language rows — "not available yet" is
   a product state we show on purpose, not an error to hide. */
.availability-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding-block: var(--s-4);
  border-bottom: 1px solid var(--line);
}
.availability-row:last-child { border-bottom: 0; padding-bottom: 0; }
.availability-row > div { display: grid; gap: 2px; }
.availability-row strong { font-size: 14.5px; font-weight: 650; }
.availability-row small { color: var(--muted); font-size: 13px; }

/* --- Consultation panel (hidden unless the video gate is open) ----------- */
.consultation-panel { display: grid; gap: var(--s-4); }

.consultation-tags { display: flex; flex-wrap: wrap; gap: var(--s-2); }

/* What a video visit actually delivers. Deliberately concrete, and deliberately
   silent on medication: remote prescribing is unresolved in Egyptian law, so the
   promised outcome is the consultation plus a signed written clinical summary —
   never a prescription, a drug, or a pharmacy hand-off. */
.deliverable-list {
  display: grid;
  gap: var(--s-3);
  margin: 0;
  padding: var(--s-4);
  background: var(--card-sunken);
  border-radius: var(--r-md);
  list-style: none;
}
.deliverable-list li {
  display: grid;
  grid-template-columns: 18px 1fr;
  align-items: start;
  gap: var(--s-3);
  color: var(--ink-soft);
  font-size: 13.5px;
  line-height: 1.45;
}
.deliverable-list svg { color: var(--brand); margin-top: 2px; }

.consultation-list { display: grid; gap: var(--s-3); }

/* ---------------------------------------------------------------------------
   History — one timeline per pet.
   The rail is a single border on the <ol>, with each entry's marker painted as
   a dot on the inline-start edge. Using the border rather than a pseudo-element
   spine means it stops exactly at the last entry instead of overshooting, and
   it mirrors correctly under dir="rtl" because it is a logical property.
   ------------------------------------------------------------------------- */
/* Retake advice under a refused photo. A list, not a paragraph: each line is a
   separate thing to fix, and the owner is going to act on them one at a time. */
.quality-hints {
  display: grid;
  gap: var(--s-2);
  margin: var(--s-2) 0 0;
  padding-inline-start: 1.15em;
}
.quality-hints li { font-weight: 500; }

/* "Is this Luna?" — inside the pet sheet, below the form. */
.pet-duplicate {
  display: grid;
  gap: var(--s-3);
  margin-top: var(--s-4);
  padding: var(--s-4);
  background: var(--card-sunken);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-lg);
}
.pet-duplicate .dup-title { margin: 0; font-weight: 700; color: var(--ink); }
.pet-duplicate .dup-body { margin: 0; color: var(--ink-soft); }
.dup-actions { display: grid; gap: var(--s-2); }

.history-list { display: grid; gap: var(--s-6); }

.history-group { display: grid; gap: var(--s-3); }

.history-group-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
}
.history-group-head h2 {
  margin: 0;
  font-size: 1.05rem;
  color: var(--ink);
}

.history-timeline {
  display: grid;
  gap: var(--s-4);
  margin: 0;
  padding: 0 0 0 var(--s-4);
  padding-inline-start: var(--s-4);
  list-style: none;
  border-inline-start: 2px solid var(--line);
}

.history-entry {
  position: relative;
  display: grid;
  gap: var(--s-2);
}
.history-entry::before {
  content: "";
  position: absolute;
  inset-block-start: 6px;
  inset-inline-start: calc(-1 * var(--s-4) - 5px);
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--brand);
}

.history-when {
  font-size: .8rem;
  font-weight: 650;
  color: var(--muted);
}

.history-entry-body {
  display: grid;
  gap: var(--s-2);
  justify-items: start;
  padding: var(--s-4);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}
.history-entry-body p { margin: 0; color: var(--ink-soft); }

/* A fixed box with object-fit, so a portrait phone photo and a landscape one
   line up down the timeline instead of making every row a different height. */
.history-thumb {
  justify-self: stretch;
  width: 100%;
  height: 160px;
  object-fit: cover;
  border-radius: var(--r-md);
  background: var(--card-sunken);
}

.consultation-card {
  display: grid;
  gap: var(--s-3);
  padding: var(--s-4);
  background: var(--card-sunken);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}
.consultation-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
}
.consultation-card time { color: var(--muted); font-size: 13px; }
.consultation-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  align-items: center;
}


/* ==========================================================================
   9. Responsive, RTL, motion
   ========================================================================== */

/* --- Small phones: tighten the card padding rather than the type size ---- */
@media (max-width: 380px) {
  .card, .step { padding: var(--s-4); border-radius: var(--r-lg); }
  .content { padding-inline: var(--s-4); }
}

/* --- Large phone / small tablet: two-up field pairs ---------------------- */
@media (min-width: 520px) {
  .grid-two { grid-template-columns: 1fr 1fr; }
}

/* --- Desktop: the phone canvas becomes a centred, framed app ------------- */
@media (min-width: 860px) {
  body { padding: var(--s-6) var(--s-4); }

  .shell {
    min-height: calc(100dvh - var(--s-7));
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-xl);
    box-shadow: var(--shadow-lg);
    overflow: clip;
  }

  .content { padding-inline: var(--s-7); }

  .tabs {
    inset-block-end: var(--s-6);
    border-radius: 0 0 var(--r-xl) var(--r-xl);
  }

  .sheet {
    margin-block-end: auto;
    border-radius: var(--r-xl);
  }
}

/* --- RTL --------------------------------------------------------------- */
/* Layout flips come free from logical properties. Only genuinely directional
   glyphs need a manual mirror. */
[dir="rtl"] .wordmark { letter-spacing: 0; }
[dir="rtl"] .eyebrow  { letter-spacing: .04em; }
[dir="rtl"] .badge    { letter-spacing: 0; }
[dir="rtl"] .mirror   { transform: scaleX(-1); }

/* --- Reduced motion ----------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

/* --- High contrast ------------------------------------------------------ */
@media (prefers-contrast: more) {
  :root { --line: var(--line-strong); --muted: var(--ink-soft); }
  .card, .step, .pet-card, .case-card { border-width: 2px; }
}

/* ── The Flow — owner-facing triage (advisory) ───────────────────────────── */
.flow-card { display: grid; gap: var(--s-3); }
.flow-species { display: inline-flex; gap: 6px; border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 4px; background: var(--card); width: max-content; }
.flow-seg { border: 0; background: transparent; color: var(--ink-soft);
  font-weight: 600; padding: 8px 18px; border-radius: var(--r-sm); }
.flow-seg.is-on { background: var(--brand); color: #fff; }
.flow-board { display: grid; gap: 8px; margin-bottom: var(--s-3); }
.flow-cond { background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 10px 12px; }
.flow-cond.lead { border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand); }
.flow-cond-top { display: flex; justify-content: space-between; align-items: baseline;
  gap: 8px; margin-bottom: 7px; }
.flow-cond-name { font-weight: 700; color: var(--ink); }
.flow-pct { font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ink); }
.flow-delta { font-size: 12px; font-weight: 800; margin-left: 6px;
  font-variant-numeric: tabular-nums; }
.flow-delta.up { color: #1a7d4b; } .flow-delta.dn { color: var(--danger); }
.flow-bar { height: 7px; border-radius: 6px; overflow: hidden;
  background: color-mix(in srgb, var(--ink) 12%, transparent); }
.flow-bar i { display: block; height: 100%; border-radius: 6px; background: var(--brand); }
.flow-cond.lead .flow-bar i { background: var(--brand-strong); }
.flow-badge { font-size: 10px; font-weight: 800; letter-spacing: .04em;
  padding: 2px 6px; border-radius: 5px; margin-left: 6px; }
.flow-badge-zoo { background: var(--warn-soft); color: var(--warn); }
.flow-badge-urgent { background: var(--danger-soft); color: var(--danger); }
.flow-badge-gate { background: var(--brand-soft); color: var(--brand-strong); }
.flow-new { font-size: 10px; font-weight: 800; margin-left: 6px; padding: 2px 6px;
  border-radius: 5px; background: var(--warn-soft); color: var(--warn); }
.flow-q { font-weight: 700; font-size: 18px; color: var(--ink); margin-bottom: var(--s-3); }
/* The "everything else" row. Muted and dashed so it reads as the remainder of
   the distribution rather than as a fifth candidate condition — early in the
   Flow it is the largest bar on the screen, and that is the honest picture. */
.flow-other {
  border-top: 1px dashed var(--line-strong);
  margin-top: var(--s-3);
  padding-top: var(--s-3);
  opacity: .78;
}
.flow-other .flow-bar i { background: var(--muted); }
.flow-other-note {
  margin: var(--s-2) 0 0;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--muted);
}
/* Shown under every row tied for the top percentage, so a 13/13/9/9 board
   doesn't let the first-listed row alone read as "the" leader. */
.flow-tied-note {
  margin: 6px 0 0;
  font-size: 11.5px;
  line-height: 1.4;
  color: var(--brand-strong);
  font-weight: 600;
}

/* Sits under a multi-select question. The weights sheet used to say "(multi)"
   in the question itself; this says it in the owner's language instead. */
.flow-q-hint {
  margin: calc(-1 * var(--s-2)) 0 var(--s-3);
  font-size: 13px;
  color: var(--muted);
}
.flow-opts { display: grid; gap: 9px; }
.flow-opt { display: flex; align-items: center; gap: 11px; text-align: start;
  border: 1.5px solid var(--line); border-radius: var(--r-md); padding: 12px 14px;
  font-weight: 600; background: var(--card); color: var(--ink); }
.flow-opt:hover { border-color: var(--brand); }
.flow-opt.is-on { border-color: var(--brand); background: var(--brand-soft); }
.flow-ck { width: 18px; height: 18px; border-radius: 5px; flex: none;
  border: 2px solid var(--muted); }
.flow-opt.is-on .flow-ck { background: var(--brand); border-color: var(--brand); }
.flow-apply { margin-top: var(--s-3); }
.flow-verdict { border-radius: var(--r-md); padding: var(--s-4); margin-bottom: var(--s-3);
  background: var(--brand-soft); }
.flow-verdict.urgent { background: var(--danger-soft); }
.flow-verdict-lab { font-size: 11px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--muted); font-weight: 700; margin: 0 0 5px; }
.flow-verdict.urgent .flow-verdict-lab { color: var(--danger); }
.flow-verdict-big { font-weight: 800; font-size: 21px; color: var(--ink); margin: 0; }
.flow-verdict-big span { font-size: 15px; color: var(--brand-strong); font-weight: 700; }
.flow-why { font-size: 14px; color: var(--ink-soft); margin: 8px 0 0; }
.flow-banner { border-radius: var(--r-md); padding: 11px 13px; font-size: 14px;
  margin-bottom: var(--s-3); background: var(--warn-soft); color: var(--warn); }
.flow-runners-lab { font-size: 11px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--muted); font-weight: 700; margin: var(--s-3) 0 6px; }
.flow-cta { display: flex; gap: 10px; flex-wrap: wrap; margin-top: var(--s-4); }
.flow-note { font-size: 12.5px; color: var(--muted); margin-top: var(--s-3); }
.flow-score-meaning { font-size: 14px; line-height: 1.5; color: var(--ink); }
.flow-err { color: var(--danger); font-weight: 600; }
.flow-photo-label { display: flex; flex-direction: column; gap: 6px;
  font-size: 13px; color: var(--ink-soft); }
.flow-photo-label input { font: inherit; color: var(--ink); }

/* Scan is an app-sized wizard: the fixed appointment action and exactly one
   compact step share the viewport above the fixed tab bar. */
.content:has(#view-scan.active) {
  height: calc(100dvh - 64px - 78px);
  padding-block: var(--s-3);
  overflow: hidden;
}
#view-scan.active {
  height: 100%;
  min-height: 0;
  gap: var(--s-2);
  overflow: hidden;
  grid-template-rows: auto 1fr;
}
.scan-book { min-height: 44px; align-self: start; }
.scan-wizard, .scan-screen {
  min-height: 0;
  height: 100%;
}
.scan-wizard { display: block; }
.wizard-step {
  display: flex;
  flex-direction: column;
  align-content: start;
  gap: var(--s-3);
  overflow-y: auto;
}
/* Only the capture step pins its last child (the Scan button) to the bottom
   of the viewport — that's a fixed call-to-action, not scoreboard content.
   The answer/questions/result steps used to inherit the same push, which left
   a large empty gap between the scoreboard and the card below it whenever
   the board was short; those steps now stack from the top like a normal
   page and scroll if their content runs long. */
[data-wizard-step="capture"] > :last-child { margin-top: auto; }
.compact-head { gap: 2px; }
.compact-head h1 { font-size: clamp(1.35rem, 6vw, 1.8rem); }
.photo-help {
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--card-sunken);
  color: var(--ink-soft);
  font-size: 12px;
}
.photo-help summary { color: var(--ink); font-weight: 700; cursor: pointer; }
.photo-help p { margin: 6px 0 0; }
.camera-compact { min-height: 112px; padding: var(--s-3); }
.preview-compact img { max-height: 118px; }
.improve-card { gap: var(--s-2); padding: var(--s-4); }
.wizard-actions { display: grid; gap: var(--s-2); }
.wizard-step .flow-board { gap: 5px; margin-bottom: 0; }
.wizard-step .flow-cond { padding: 6px 9px; }
.wizard-step .flow-cond-top { margin-bottom: 4px; }
.wizard-step .flow-bar { height: 5px; }
.wizard-step .flow-q { font-size: 16px; margin-bottom: var(--s-2); }
.wizard-step .flow-opts { gap: 6px; }
.wizard-step .flow-opt { min-height: 44px; padding: 8px 10px; }
.wizard-step .flow-card { padding: var(--s-3); gap: var(--s-2); }
.consent-dialog { max-height: min(720px, calc(100dvh - var(--s-6))); }
.consent-dialog .sheet-body { overflow-y: auto; }

/* ── Checkout: the 200 EGP paid vet visit (Paymob / Fawry) ─────────────────── */
.checkout-card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: var(--s-6); box-shadow: var(--shadow-sm);
  display: grid; gap: var(--s-4);
}
.checkout-price {
  display: flex; align-items: baseline; justify-content: space-between;
  padding-bottom: var(--s-4); border-bottom: 1px solid var(--line);
}
.checkout-price strong { font-size: 1.9rem; color: var(--brand); letter-spacing: -.02em; }
.checkout-benefits { margin: 0; padding-inline-start: 1.1em; color: var(--ink-soft); display: grid; gap: 6px; }
.checkout-choose { margin: 0; font-weight: 700; color: var(--ink); }
.checkout-rails { display: grid; gap: var(--s-3); }
.checkout-rail {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-3); text-align: start; min-height: 56px;
}
.checkout-rail-method { font-weight: 600; }
.checkout-rail-action { opacity: .95; font-size: .92em; }
.checkout-status { margin: 0; color: var(--brand-ink); min-height: 1.2em; font-weight: 600; }
.checkout-sandbox {
  margin: 0; font-size: .85rem; color: var(--warn);
  background: var(--warn-soft); border-radius: var(--r-sm); padding: 8px 12px;
}

/* --- Out-of-band payment (transfer + receipt on WhatsApp) -----------------
   Rendered only when the server sends a destination AND a receipt channel.
   Ground on --card-sunken so it reads as a distinct panel inside the checkout
   card without introducing a colour: every value here is a tokens.css var. */
.checkout-offline {
  display: grid; gap: var(--s-3);
  background: var(--card-sunken);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: var(--s-4);
}
.offline-title { margin: 0; font-size: 1.02rem; color: var(--ink); }
.offline-lead { margin: 0; color: var(--ink-soft); font-size: .94rem; line-height: 1.55; }
.offline-dest {
  display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: 10px 12px;
}
.offline-dest-kind {
  font-size: .78rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--brand-ink);
}
/* The number is the thing being copied by hand off a phone screen: give it
   room, a tabular face, and free selection even where text-select is damped. */
.offline-dest-value {
  flex: 1 1 auto; min-width: 8ch;
  font-variant-numeric: tabular-nums;
  font-weight: 600; color: var(--ink); word-break: break-all;
  user-select: all; -webkit-user-select: all;
}
.offline-copy { flex: 0 0 auto; padding: 6px 12px; font-size: .85rem; }
.offline-wa { margin: 0; text-decoration: none; text-align: center; }
.offline-note { margin: 0; font-size: .82rem; color: var(--muted); line-height: 1.5; }

/* ---- consultation channel picker ---------------------------------------
   Two stacked radio cards reusing .check, so a tier choice looks and behaves
   exactly like every other consent-shaped choice in this portal. */
.channel-choice { border: 0; margin: 0; padding: 0; }
.channel-options { display: grid; gap: 8px; }
.channel-options .check { margin: 0; }

/* --- Home visits, prescriptions, the pharmacy ------------------------------

   Every colour here is a token from the shared palette. Nothing in this block
   introduces a new one: a second teal that is almost the first teal is how a
   design system dies.
   ------------------------------------------------------------------------- */

.homevisit-block {
  display: grid;
  gap: var(--s-3);
  padding: var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--card-sunken);
}
.homevisit-block > legend {
  padding: 0 var(--s-2);
}

/* --- Prescriptions --------------------------------------------------------- */

.prescription-list {
  display: grid;
  gap: var(--s-4);
}

.prescription-card {
  display: grid;
  gap: var(--s-3);
  padding: var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--card);
}

.prescription-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-2);
}
.prescription-head h3 { font-size: 16px; margin: 0; }
.prescription-head .muted { font-size: 13px; margin: 0; }

.prescription-diagnosis {
  margin: 0;
  font-weight: 650;
  color: var(--ink);
}

.prescription-items {
  display: grid;
  gap: var(--s-3);
  margin: 0;
  padding: 0;
  list-style: none;
}
.prescription-items li {
  display: grid;
  gap: 2px;
  padding-inline-start: var(--s-4);
  border-inline-start: 3px solid var(--brand-soft);
}
/* A medicine we cannot dispense is still part of the vet's instruction, so it
   is shown — muted rather than hidden, and never with an order button. */
.prescription-items li.not-dispensable {
  border-inline-start-color: var(--line-strong);
  opacity: .75;
}
.rx-drug { font-weight: 700; }
.rx-how, .rx-note { font-size: 13.5px; color: var(--muted); }

.prescription-note {
  margin: 0;
  padding: var(--s-3);
  border-radius: var(--r-md);
  background: var(--brand-soft);
  color: var(--brand-ink);
  font-size: 14px;
}

/* --- Pharmacy entry -------------------------------------------------------- */

.pharmacy-entry .entry-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
}

/* --- Catalogue ------------------------------------------------------------- */

.medicine-list {
  display: grid;
  gap: var(--s-3);
}

.medicine-card {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--card);
}
.medicine-body { flex: 1 1 60%; min-width: 0; }
.medicine-body h3 { font-size: 15.5px; margin: 0 0 2px; }
.medicine-body .muted { font-size: 13px; margin: 0; }
.medicine-blurb {
  margin: var(--s-2) 0 0;
  font-size: 13.5px;
  color: var(--muted);
}

.medicine-side {
  display: grid;
  gap: var(--s-2);
  justify-items: end;
  text-align: end;
}
.medicine-price { margin: 0; font-weight: 750; white-space: nowrap; }

.qty-holder { display: grid; gap: 4px; justify-items: end; }
.qty-holder .fine { margin: 0; max-width: 22ch; text-align: end; }

.qty-control {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
}
.qty-step {
  min-width: 38px;
  min-height: 38px;   /* a real touch target, not a 24px chevron */
  padding: 0;
  font-size: 18px;
  line-height: 1;
}
.qty-count {
  min-width: 2ch;
  text-align: center;
  font-weight: 750;
  font-variant-numeric: tabular-nums;
}

/* --- Basket ---------------------------------------------------------------- */

.cart-panel { position: sticky; bottom: var(--s-3); z-index: 2; }

.cart-lines { display: grid; gap: var(--s-2); }
.cart-line {
  display: flex;
  justify-content: space-between;
  gap: var(--s-3);
  font-size: 14px;
}
.cart-line-name { min-width: 0; }
.cart-line-total { white-space: nowrap; font-variant-numeric: tabular-nums; }

.cart-totals { display: grid; gap: var(--s-2); margin: 0; }
.cart-totals > div {
  display: flex;
  justify-content: space-between;
  gap: var(--s-3);
}
.cart-totals dt, .cart-totals dd { margin: 0; }
.cart-totals dd { font-variant-numeric: tabular-nums; }
.cart-totals .cart-total {
  padding-top: var(--s-2);
  border-top: 1px solid var(--line);
  font-weight: 800;
  font-size: 16px;
}

/* --- Orders ---------------------------------------------------------------- */

.order-list { display: grid; gap: var(--s-4); }

.order-card {
  display: grid;
  gap: var(--s-3);
  padding: var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--card);
}

.order-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-2);
}
.order-head h3 { font-size: 15.5px; margin: 0; font-variant-numeric: tabular-nums; }
.order-head .muted { font-size: 13px; margin: 0; }

/* The delivery steps. Horizontal and scrollable rather than wrapped: five
   labels wrapping to three ragged lines reads as a mess on a narrow phone,
   which is the only screen most of these owners will ever use. */
.order-progress {
  display: flex;
  gap: var(--s-2);
  overflow-x: auto;
  padding-bottom: var(--s-2);
  scrollbar-width: thin;
}
.order-step {
  display: grid;
  gap: 4px;
  justify-items: center;
  flex: 1 0 auto;
  min-width: 72px;
  text-align: center;
}
.order-step-dot {
  width: 12px;
  height: 12px;
  border-radius: var(--r-pill);
  background: var(--line-strong);
  box-shadow: 0 0 0 3px var(--card);
}
.order-step.done .order-step-dot { background: var(--brand); }
.order-step-label {
  font-size: 11.5px;
  color: var(--muted);
  line-height: 1.3;
}
.order-step.done .order-step-label { color: var(--ink); font-weight: 650; }

.order-lines {
  display: grid;
  gap: var(--s-2);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 14px;
}
.order-lines li {
  display: flex;
  justify-content: space-between;
  gap: var(--s-3);
}
.order-lines li span:last-child {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.order-total {
  margin: 0;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.order-whatsapp { text-decoration: none; }
.order-card .fine { margin: 0; }

@media (min-width: 640px) {
  .medicine-card { flex-wrap: nowrap; }
  .order-step { min-width: 88px; }
}
