/* YesPac design system, direction "Kraft" - shared by the three PWAs.
 *
 * Warm packaging-stock paper, brown-black ink, soft rounded surfaces, pill
 * buttons, one friendly grotesk (Hanken Grotesk, self-hosted via fonts.css).
 * Red is a signal, not decoration: the single main action on a screen and
 * lateness/danger. Everything else is ink.
 *
 * CONTRAST (WCAG 2.x, checked by the script that lives with the design work;
 * final ratios recorded at the bottom of this comment; tests/test_design_tokens.py
 * guards that every token exists):
 *   LIGHT:
     ink        #2a2320 on bg         #e9e2d4  11.98  (>=4.5)
     ink        #2a2320 on surface    #f6f2ea  13.83  (>=4.5)
     ink        #2a2320 on surface2   #fbf9f4  14.68  (>=4.5)
     ink        #2a2320 on sunk       #e1d8c6  10.91  (>=4.5)
     ink2       #685d55 on bg         #e9e2d4   4.96  (>=4.5)
     ink2       #685d55 on surface    #f6f2ea   5.72  (>=4.5)
     ink2       #685d55 on surface2   #fbf9f4   6.07  (>=4.5)
     ink2       #685d55 on sunk       #e1d8c6   4.52  (>=4.5)
     ink        #2a2320 on inputbg    #fbf9f4  14.68  (>=4.5)
     ink2       #685d55 on inputbg    #fbf9f4   6.07  (>=4.5)
     onprimary  #fbf9f4 on primary    #2a2320  14.68  (>=4.5)
     onaccent   #ffffff on accent     #b3261e   6.54  (>=4.5)
     accent     #b3261e on surface    #f6f2ea   5.85  (>=4.5)
     accent     #b3261e on bg         #e9e2d4   5.07  (>=4.5)
     accent     #b3261e on dangerbg   #f6dcd8   5.03  (>=4.5)
     danger     #9c1f18 on surface    #f6f2ea   7.17  (>=4.5)
     danger     #9c1f18 on bg         #e9e2d4   6.21  (>=4.5)
     danger     #9c1f18 on dangerbg   #f6dcd8   6.16  (>=4.5)
     danger     #9c1f18 on surface2   #fbf9f4   7.61  (>=4.5)
     good       #3b763d on surface    #f6f2ea   4.89  (>=4.5)
     good       #3b763d on goodbg     #e1eed9   4.53  (>=4.5)
     warn       #9b5600 on surface    #f6f2ea   5.05  (>=4.5)
     warn       #9b5600 on warnbg     #f5e4c8   4.51  (>=4.5)
     info       #2f5f8a on surface    #f6f2ea   6.02  (>=4.5)
     info       #2f5f8a on infobg     #dde8f1   5.40  (>=4.5)
     neutral    #6e655d on neutralbg  #ebe4d8   4.51  (>=4.5)
     neutral    #6e655d on surface    #f6f2ea   5.11  (>=4.5)
     ink        #2a2320 on goodbg     #e1eed9  12.82  (>=4.5)
     ink        #2a2320 on warnbg     #f5e4c8  12.37  (>=4.5)
     ink        #2a2320 on infobg     #dde8f1  12.42  (>=4.5)
     ink        #2a2320 on neutralbg  #ebe4d8  12.22  (>=4.5)
     focus      #2f5f8a on surface    #f6f2ea   6.02  (>=3.0)
     focus      #2f5f8a on bg         #e9e2d4   5.21  (>=3.0)
     inputborder #948b7e on inputbg    #fbf9f4   3.19  (>=3.0)
     inputborder #948b7e on surface    #f6f2ea   3.01  (>=3.0)
     neutral    #6e655d on surface    #f6f2ea   5.11  (>=3.0)
     accent     #b3261e on surface    #f6f2ea   5.85  (>=3.0)
     good       #3b763d on surface    #f6f2ea   4.89  (>=3.0)
     warn       #9b5600 on surface    #f6f2ea   5.05  (>=3.0)
     info       #2f5f8a on surface    #f6f2ea   6.02  (>=3.0)
     danger     #9c1f18 on surface    #f6f2ea   7.17  (>=3.0)
     ink3       #8c8278 on inputbg    #fbf9f4   3.58  (>=3.0)
     onaccent   #ffffff on danger     #9c1f18   8.01  (>=4.5)
     surface2   #fbf9f4 on danger     #9c1f18   7.61  (>=4.5)
DARK:
     ink        #f1ebe1 on bg         #1c1916  14.76  (>=4.5)
     ink        #f1ebe1 on surface    #25211d  13.48  (>=4.5)
     ink        #f1ebe1 on surface2   #2d2824  12.29  (>=4.5)
     ink        #f1ebe1 on sunk       #171411  15.47  (>=4.5)
     ink2       #b9ada0 on bg         #1c1916   7.96  (>=4.5)
     ink2       #b9ada0 on surface    #25211d   7.27  (>=4.5)
     ink2       #b9ada0 on surface2   #2d2824   6.63  (>=4.5)
     ink2       #b9ada0 on sunk       #171411   8.34  (>=4.5)
     ink        #f1ebe1 on inputbg    #2d2824  12.29  (>=4.5)
     ink2       #b9ada0 on inputbg    #2d2824   6.63  (>=4.5)
     onprimary  #1c1916 on primary    #f1ebe1  14.76  (>=4.5)
     onaccent   #1f0a08 on accent     #ef6b5f   6.28  (>=4.5)
     accent     #ef6b5f on surface    #25211d   5.28  (>=4.5)
     accent     #ef6b5f on bg         #1c1916   5.78  (>=4.5)
     accent     #ef6b5f on dangerbg   #3d1c18   5.04  (>=4.5)
     danger     #ff9d92 on surface    #25211d   7.98  (>=4.5)
     danger     #ff9d92 on bg         #1c1916   8.74  (>=4.5)
     danger     #ff9d92 on dangerbg   #3d1c18   7.61  (>=4.5)
     danger     #ff9d92 on surface2   #2d2824   7.28  (>=4.5)
     good       #8fd19a on surface    #25211d   8.95  (>=4.5)
     good       #8fd19a on goodbg     #1f3322   7.56  (>=4.5)
     warn       #f0b86a on surface    #25211d   8.96  (>=4.5)
     warn       #f0b86a on warnbg     #3a2b14   7.66  (>=4.5)
     info       #93bde6 on surface    #25211d   8.11  (>=4.5)
     info       #93bde6 on infobg     #1b2b3a   7.34  (>=4.5)
     neutral    #a39686 on neutralbg  #2d2824   5.04  (>=4.5)
     neutral    #a39686 on surface    #25211d   5.53  (>=4.5)
     ink        #f1ebe1 on goodbg     #1f3322  11.39  (>=4.5)
     ink        #f1ebe1 on warnbg     #3a2b14  11.53  (>=4.5)
     ink        #f1ebe1 on infobg     #1b2b3a  12.19  (>=4.5)
     ink        #f1ebe1 on neutralbg  #2d2824  12.29  (>=4.5)
     focus      #93bde6 on surface    #25211d   8.11  (>=3.0)
     focus      #93bde6 on bg         #1c1916   8.89  (>=3.0)
     inputborder #797169 on inputbg    #2d2824   3.04  (>=3.0)
     inputborder #797169 on surface    #25211d   3.33  (>=3.0)
     neutral    #a39686 on surface    #25211d   5.53  (>=3.0)
     accent     #ef6b5f on surface    #25211d   5.28  (>=3.0)
     good       #8fd19a on surface    #25211d   8.95  (>=3.0)
     warn       #f0b86a on surface    #25211d   8.96  (>=3.0)
     info       #93bde6 on surface    #25211d   8.11  (>=3.0)
     danger     #ff9d92 on surface    #25211d   7.98  (>=3.0)
     ink3       #8f8378 on inputbg    #2d2824   3.95  (>=3.0)
     onaccent   #1f0a08 on danger     #ff9d92   9.49  (>=4.5)
   Adjusted from the brief (needed to pass): light ink-2 #6b6058>#685d55, good #3d7a3f>#3b763d,
   warn #a35a00>#9b5600, neutral #8c8278>#6e655d (ink-3 keeps #8c8278: placeholders only),
   input-border #d3c8b5>#948b7e (3:1 for input edges); dark input-border #4a423a>#797169.
   Known exception: --ink-3 placeholders are ~3.4:1 (light) by design, never body text.
 *
 * HOW TO USE
 *   - Colours come only from the tokens below. No hex literals in pages.
 *   - Components (.btn, .chip, .card, .field, .table, .side-nav, .tabbar,
 *     .summary-bar, .modal/.sheet/.scrim, .yp-toast, .status-*) live in this
 *     file. Pages use them; they do not re-declare them.
 *   - Dark mode is the same tokens under :root[data-theme="dark"], set by
 *     theme.js from Appearance. Never a media query: light stays the default.
 *   - Tones for status are: good | warn | info | danger | neutral.
 */

/* Hanken Grotesk lives here so a page needs one stylesheet, not two (fonts.css
   carries the same rules for pages that do not load this file, e.g. the landing
   page; tests/test_design_tokens.py keeps the two in step). */
@font-face{font-family:'Hanken Grotesk';font-style:normal;font-weight:100 900;font-display:swap;src:url('/fonts/hanken-grotesk-latin-var.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:'Hanken Grotesk';font-style:normal;font-weight:100 900;font-display:swap;src:url('/fonts/hanken-grotesk-latin-ext-var.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 {
  color-scheme: light;

  /* Typeface. Hanken Grotesk is declared in fonts.css. */
  --font: "Hanken Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

  /* Surfaces and ink. */
  --bg: #e9e2d4;
  --surface: #f6f2ea;
  --surface-2: #fbf9f4;
  --surface-sunk: #e1d8c6;
  --ink: #2a2320;
  --ink-2: #685d55;
  --ink-3: #8c8278;            /* placeholders / disabled only, never body text */
  --line: #ddd3c2;
  --line-strong: #c9bda8;
  --input-bg: #fbf9f4;
  --input-border: #948b7e;

  /* Filled buttons and selected chips. */
  --primary: #2a2320;
  --on-primary: #fbf9f4;
  /* The ONE main action per view + brand signal. */
  --accent: #b3261e;
  --accent-press: #941f18;
  --on-accent: #ffffff;
  /* Destructive text / tinted background. */
  --danger: #9c1f18;
  --danger-bg: #f6dcd8;

  /* Status tones. */
  --info: #2f5f8a;    --info-bg: #dde8f1;
  --warn: #9b5600;    --warn-bg: #f5e4c8;
  --good: #3b763d;    --good-bg: #e1eed9;
  --neutral: #6e655d; --neutral-bg: #ebe4d8;

  --focus: #2f5f8a;           /* 2px outline, 2px offset */
  --scrim: rgba(42, 35, 32, 0.45);
  --shadow-pop: 0 10px 30px rgba(42, 35, 32, 0.16);   /* overlays only; cards are flat */

  /* Stock catalogue tabs, matching the price sheet's tab colours. Text on each
     is --ink unless a --sheet-*-ink is given. */
  --sheet-hot: #f6c9cd;
  --sheet-cold: #dbe2f1;
  --sheet-soup: #dcb894;
  --sheet-pet-cups: #3fb6ec;
  --sheet-pet-cont: #fbe39a;
  --sheet-lids: #c9e0b6;
  --sheet-compost: #375623;  --sheet-compost-ink: #ffffff;
  --sheet-pp: #1f1b19;       --sheet-pp-ink: #ffffff;

  /* Radii. Buttons and chips are pills; cards 12; sheets/modals 16; inputs 10. */
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-pill: 999px;
  --r-input: 10px;

  /* Spacing scale. */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px;
  --s-5: 20px; --s-6: 24px; --s-7: 32px; --s-8: 48px;

  /* Type scale (px): 12 13 14 16 18 22 28 36 48. */
  --fs-1: 12px; --fs-2: 13px; --fs-3: 14px; --fs-4: 16px; --fs-5: 18px;
  --fs-6: 22px; --fs-7: 28px; --fs-8: 36px; --fs-9: 48px;

  /* Stacking scale: the single source. Page-local z-index values should use
     these names, not numbers. */
  --z-sticky: 10;
  --z-nav: 50;
  --z-sheet: 300;
  --z-viewer: 400;
  --z-chat: 420;
  --z-modal: 500;
  --z-toast: 600;
  --z-update: 2000;

  --ease: cubic-bezier(0.32, 0.72, 0, 1);
  --dur: 0.24s;            /* sheets slide */
  --dur-fast: 0.18s;       /* hover / press */
  --motion-enter: cubic-bezier(0.16, 1, 0.3, 1);

  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
}

/* Opt-in only, via Appearance (theme.js sets data-theme). Never a media query. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --bg: #1c1916;
  --surface: #25211d;
  --surface-2: #2d2824;
  --surface-sunk: #171411;
  --ink: #f1ebe1;
  --ink-2: #b9ada0;
  --ink-3: #8f8378;
  --line: #3a332d;
  --line-strong: #4a423a;
  --input-bg: #2d2824;
  --input-border: #797169;

  --primary: #f1ebe1;
  --on-primary: #1c1916;
  --accent: #ef6b5f;
  --accent-press: #f38a80;
  --on-accent: #1f0a08;
  --danger: #ff9d92;
  --danger-bg: #3d1c18;

  --info: #93bde6;    --info-bg: #1b2b3a;
  --warn: #f0b86a;    --warn-bg: #3a2b14;
  --good: #8fd19a;    --good-bg: #1f3322;
  --neutral: #a39686; --neutral-bg: #2d2824;

  --focus: #93bde6;
  --scrim: rgba(0, 0, 0, 0.6);
  --shadow-pop: 0 10px 30px rgba(0, 0, 0, 0.5);

  --sheet-hot: #5a3236;
  --sheet-cold: #333b4d;
  --sheet-soup: #5a4430;
  --sheet-pet-cups: #1d5470;
  --sheet-pet-cont: #574a1f;
  --sheet-lids: #364a2b;
  --sheet-compost: #2f4a1e;  --sheet-compost-ink: #f1ebe1;
  --sheet-pp: #0e0c0b;       --sheet-pp-ink: #f1ebe1;
}

/* ── base ─────────────────────────────────────────────────────────────── */

* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; }

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  font-family: var(--font);
}

body {
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.5;
  color: var(--ink);
  background-color: var(--bg);
  -webkit-font-smoothing: antialiased;
}

button, input, select, textarea { font-family: inherit; font-size: inherit; color: inherit; }
button, a, label, select, summary, [role=button], [onclick] { touch-action: manipulation; }
img, svg { max-width: 100%; }
[hidden] { display: none !important; }

/* Headings: heavy, tight, sentence case, balanced. Use the classes on any tag. */
h1, h2, h3, .h-display, .h1, .h2, .h3 { font-weight: 800; text-wrap: balance; }
.h-display { font-size: clamp(36px, 7vw, 60px); line-height: 1.05; letter-spacing: -0.03em; }
h1, .h1 { font-size: var(--fs-7); line-height: 1.15; letter-spacing: -0.03em; }
h2, .h2 { font-size: var(--fs-6); line-height: 1.2; letter-spacing: -0.03em; }
h3, .h3 { font-size: var(--fs-5); line-height: 1.3; letter-spacing: -0.01em; }
.label { font-size: var(--fs-2); font-weight: 600; color: var(--ink-2); }   /* small label above a value */
.text-2 { color: var(--ink-2); }                                            /* secondary text */
.text-sm { font-size: var(--fs-3); }
.text-xs { font-size: var(--fs-1); }
.num { font-variant-numeric: tabular-nums; }                                /* money, counts, dates */
.text-danger { color: var(--danger); font-weight: 600; }                    /* late / overdue text */
.ios-numeric { font-variant-numeric: tabular-nums; }                        /* still emitted by ui.js */

/* Keyboard focus: one ring everywhere. Inputs use the same ring on :focus. */
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

/* Shared motion primitives. A page adds these only where an incoming state
   communicates hierarchy or a completed action, rather than for decoration. */
@keyframes yp-rise-in {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}
@keyframes yp-scale-in {
  from { opacity: 0; transform: scale(0.97); }
  to { opacity: 1; transform: scale(1); }
}
.yp-enter { animation: yp-rise-in var(--dur) var(--motion-enter) both; }
.yp-enter-scale { animation: yp-scale-in var(--dur) var(--motion-enter) both; }
.yp-enter-stagger > * {
  animation: yp-rise-in var(--dur) var(--motion-enter) both;
  animation-delay: calc(min(var(--enter-index, 0), 8) * 45ms);
}
.yp-enter-stagger > :nth-child(1) { --enter-index: 0; }
.yp-enter-stagger > :nth-child(2) { --enter-index: 1; }
.yp-enter-stagger > :nth-child(3) { --enter-index: 2; }
.yp-enter-stagger > :nth-child(4) { --enter-index: 3; }
.yp-enter-stagger > :nth-child(5) { --enter-index: 4; }
.yp-enter-stagger > :nth-child(6) { --enter-index: 5; }
.yp-enter-stagger > :nth-child(7) { --enter-index: 6; }
.yp-enter-stagger > :nth-child(8) { --enter-index: 7; }
.yp-enter-stagger > :nth-child(n + 9) { --enter-index: 8; }

/* Trip is optional; destination is not. Spinners for unknown-duration waits
   keep turning under reduced motion - freezing them claims the wait is over.
   Decorative pulses (skeletons) may freeze. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .spinner, .btn-spinner,
  .spinner::before, .btn-spinner::before,
  .spinner::after, .btn-spinner::after {
    animation-duration: 0.6s !important;
    animation-iteration-count: infinite !important;
  }
  .btn:active:not(:disabled), .chip:active { transform: none; }
  .value-flash-up, .value-flash-down { animation: none !important; }
  .yp-enter, .yp-enter-scale, .yp-enter-stagger > * { animation: none !important; }
}

/* ── buttons ──────────────────────────────────────────────────────────── */

/* Base pill button, 44px. Combine with exactly one variant. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 44px;
  padding: 0 20px;
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--ink);
  font-size: 15px;
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease),
              background-color var(--dur-fast) var(--ease);
}
.btn:active:not(:disabled) { transform: scale(0.98); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; }
.btn svg { width: 18px; height: 18px; flex-shrink: 0; stroke: currentColor; stroke-width: 1.8; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.btn-block { display: flex; width: 100%; }
/* Regular filled action and selected state (ink fill). */
.btn-primary { background: var(--primary); color: var(--on-primary); }
@media (hover: hover) { .btn-primary:hover:not(:disabled) { opacity: 0.9; } }
/* The ONE main action of a view (red). Never more than one per screen. */
.btn-accent { background: var(--accent); color: var(--on-accent); }
@media (hover: hover) { .btn-accent:hover:not(:disabled) { background: var(--accent-press); } }
/* Quiet outlined action. */
.btn-secondary { border-color: var(--line-strong); color: var(--ink); }
@media (hover: hover) { .btn-secondary:hover:not(:disabled) { background: var(--surface-sunk); } }
/* Destructive entry point: red text, outlined. A FILLED danger button is only
   for the confirm button inside a confirm dialog (.btn-danger.is-filled). */
.btn-danger { border-color: var(--line-strong); color: var(--danger); }
@media (hover: hover) { .btn-danger:hover:not(:disabled) { background: var(--danger-bg); } }
.btn-danger.is-filled { background: var(--danger); border-color: var(--danger); color: var(--surface-2); }
:root[data-theme="dark"] .btn-danger.is-filled { color: var(--on-accent); }
@media (hover: hover) { .btn-danger.is-filled:hover:not(:disabled) { opacity: 0.9; background: var(--danger); } }
/* Text-only action. */
.btn-ghost { color: var(--ink); padding: 0 12px; }
@media (hover: hover) { .btn-ghost:hover:not(:disabled) { background: var(--surface-sunk); } }
/* Compact: 40px for desktop tables and toolbars (44px again on touch). */
.btn-sm { height: 40px; padding: 0 16px; font-size: 14px; }
@media (pointer: coarse) { .btn-sm { height: 44px; } }

/* In-flight lock: immediate acknowledgement after a tap. Spinners stay hidden
   until .is-busy / [aria-busy] so they never linger past settle. */
@keyframes ios-spin { to { transform: rotate(360deg); } }
.btn-spinner {
  display: none;
  width: 14px;
  height: 14px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: ios-spin 0.6s linear infinite;
  flex-shrink: 0;
  vertical-align: middle;
}
.btn-spinner[hidden] { display: none !important; }
button.is-busy .btn-spinner,
button[aria-busy="true"] .btn-spinner { display: inline-block; }
button.is-busy,
button[aria-busy="true"] { opacity: 0.72; cursor: wait; pointer-events: none; }
.btn-label { display: inline-block; }
/* Outcome faces after an action settles; colour carries the result. */
button.is-success:not(.btn-primary):not(.btn-accent) { color: var(--good); }
button.is-error:not(.btn-primary):not(.btn-accent) { color: var(--danger); }
button.btn-primary.is-success, button.btn-accent.is-success { background: var(--good); color: var(--surface-2); }
button.btn-primary.is-error, button.btn-accent.is-error { background: var(--danger); color: var(--surface-2); }

/* Money / count that just changed: direction, not decoration. */
.value-flash-up, .value-flash-down {
  border-radius: 6px;
  animation: valueFlashSettle 0.9s var(--ease) forwards;
}
.value-flash-up { background: var(--good-bg); color: var(--good); }
.value-flash-down { background: var(--danger-bg); color: var(--danger); }
@keyframes valueFlashSettle {
  0% { transform: scale(1.04); }
  100% { transform: scale(1); }
}

/* Skeleton placeholder while loading. */
.ios-skeleton {
  background: linear-gradient(90deg, var(--surface-sunk) 25%, var(--surface-2) 50%, var(--surface-sunk) 75%);
  background-size: 200% 100%;
  animation: ios-skeleton-pulse 1.5s var(--ease) infinite;
  border-radius: var(--r-sm);
  color: transparent !important;
  user-select: none;
  pointer-events: none;
}
@keyframes ios-skeleton-pulse {
  0%, 100% { opacity: 1; background-position: 100% 0; }
  50% { opacity: 0.55; background-position: 0 0; }
}

/* ── chips ────────────────────────────────────────────────────────────── */

/* Pill toggle, 34px (size pickers, filters). .is-on or aria-pressed="true" = selected. */
.chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 34px;
  padding: 0 14px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--ink);
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
@media (hover: hover) { .chip:hover { background: var(--surface-sunk); } }
.chip.is-on, .chip[aria-pressed="true"] { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.chip:disabled { opacity: 0.45; cursor: not-allowed; }
@media (pointer: coarse) { .chip { min-height: 44px; } }

/* ── surfaces ─────────────────────────────────────────────────────────── */

/* Flat paper card: surface + 1px line + 12px radius. No shadow. */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: var(--s-4);
}
/* Inset block inside a card. */
.card-sub {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: var(--s-3);
}

/* ── forms ────────────────────────────────────────────────────────────── */

/* Label above control. Structure: <div class="field"><label for=x>Name</label><input id=x>
   <div class="field-error" id=x-err>Message</div></div>. Add .has-error to the field, or
   aria-invalid="true" / .is-invalid on the control, for the error look. */
.field { display: grid; gap: 6px; }
.field > label, .field-label { font-size: var(--fs-2); font-weight: 600; color: var(--ink-2); }
.field input, .field select, .field textarea, .input {
  width: 100%;
  height: 46px;
  padding: 0 14px;
  border: 1px solid var(--input-border);
  border-radius: var(--r-input);
  background: var(--input-bg);
  color: var(--ink);
  font-size: 16px;           /* under 16 and iOS zooms the page on focus */
  -webkit-appearance: none;
  appearance: none;
}
.field textarea, textarea.input { height: auto; min-height: 96px; padding: 12px 14px; line-height: 1.5; resize: vertical; }
.field select, select.input {
  padding-right: 36px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' fill='none' stroke='%236b6058' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1.5l5 5 5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
}
.field input::placeholder, .field textarea::placeholder, .input::placeholder { color: var(--ink-3); }
.field input:focus, .field select:focus, .field textarea:focus, .input:focus {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
}
.field input:disabled, .field select:disabled, .field textarea:disabled, .input:disabled { opacity: 0.6; cursor: not-allowed; }
/* Inline error text, tied to the control with aria-describedby. */
.field-error { margin-top: 2px; font-size: var(--fs-2); font-weight: 600; line-height: 1.3; color: var(--danger); }
.field.has-error input, .field.has-error select, .field.has-error textarea,
input.is-invalid, select.is-invalid, textarea.is-invalid, .input.is-invalid,
input[aria-invalid="true"], select[aria-invalid="true"], textarea[aria-invalid="true"] {
  border-color: var(--danger);
  outline: 2px solid var(--danger);
  outline-offset: 0;
}
input[type="checkbox"], input[type="radio"] { accent-color: var(--primary); }

/* ── status ───────────────────────────────────────────────────────────── */

/* Tone comes from data-tone (good | warn | info | danger | neutral). ui.js
   statusTag()/statusDot() emit these; legacy tones map to the same colours.
   Preferred display: dot + ink text (.status). Pills for compact tables. */
.status { display: inline-flex; align-items: center; gap: 8px; color: var(--ink); font-size: var(--fs-3); }
.status-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; background: var(--neutral); }
.status.is-late, .is-late { color: var(--danger); font-weight: 600; }   /* late / overdue */
.status-pill {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  font-size: var(--fs-1);
  font-weight: 600;
  line-height: 1.4;
  white-space: nowrap;
  background: var(--neutral-bg);
  color: var(--neutral);
}
.status-dot[data-tone="good"] { background: var(--good); }
.status-dot[data-tone="warn"], .status-dot[data-tone="attention"] { background: var(--warn); }
.status-dot[data-tone="info"] { background: var(--info); }
.status-dot[data-tone="danger"], .status-dot[data-tone="bad"] { background: var(--danger); }
.status-pill[data-tone="good"] { background: var(--good-bg); color: var(--good); }
.status-pill[data-tone="warn"], .status-pill[data-tone="attention"] { background: var(--warn-bg); color: var(--warn); }
.status-pill[data-tone="info"] { background: var(--info-bg); color: var(--info); }
.status-pill[data-tone="danger"], .status-pill[data-tone="bad"] { background: var(--danger-bg); color: var(--danger); }

/* ── tables ───────────────────────────────────────────────────────────── */

/* Wrap wide tables so they scroll sideways instead of the page. */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* Header 13/600 ink-2 sentence case; rows 52px with 1px separators. Money cells:
   add .num (tabular) and .right. Selected row: tr.is-selected. */
.table { width: 100%; border-collapse: collapse; font-size: var(--fs-3); }
.table th {
  padding: 10px 12px;
  text-align: left;
  font-size: var(--fs-2);
  font-weight: 600;
  color: var(--ink-2);
  border-bottom: 1px solid var(--line-strong);
  white-space: nowrap;
}
.table td { height: 52px; padding: 8px 12px; border-bottom: 1px solid var(--line); vertical-align: middle; }
.table .right, .table th.right { text-align: right; }
.table td.num, .table th.num { text-align: right; font-variant-numeric: tabular-nums; }
.table tbody tr.is-selected { background: var(--surface-2); }
.table tbody tr.is-clickable { cursor: pointer; }
@media (hover: hover) { .table tbody tr.is-clickable:hover { background: var(--surface-2); } }

/* ── navigation ───────────────────────────────────────────────────────── */

/* Ops desktop sidebar: transparent on --bg, 40px pill items. Put it in an
   <aside>/<nav>; items are <a> or <button>; the current one gets .is-active. */
.side-nav { display: flex; flex-direction: column; gap: 4px; background: transparent; }
.side-nav a, .side-nav button {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 40px;
  padding: 0 14px;
  border: none;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--ink);
  font-size: 15px;
  font-weight: 600;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease);
}
.side-nav a svg, .side-nav button svg { width: 18px; height: 18px; flex-shrink: 0; stroke: currentColor; stroke-width: 1.8; fill: none; stroke-linecap: round; stroke-linejoin: round; }
@media (hover: hover) { .side-nav a:hover, .side-nav button:hover { background: var(--surface-sunk); } }
.side-nav a.is-active, .side-nav button.is-active { background: var(--primary); color: var(--on-primary); }

/* Mobile Ops bottom tab bar: surface, top border, max 5 items (a/button with
   an svg icon and a 12px label). Add padding-bottom to the page for its height. */
.tabbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: var(--z-nav);
  display: flex;
  background: var(--surface);
  border-top: 1px solid var(--line);
  padding-bottom: var(--safe-bottom);
}
.tabbar a, .tabbar button {
  flex: 1;
  min-width: 0;
  min-height: 56px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  border: none;
  background: transparent;
  color: var(--ink-2);
  font-size: var(--fs-1);
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}
@media (pointer: coarse) { :root { --tap-min: 44px; } }
/* m13: at 200% zoom five tabs share ~195px: icons only (the label stays for
   screen readers) instead of five clipped words. */
@media (max-width: 260px) {
  .tabbar a > span, .tabbar button > span:not(.ok-tab-new-dot) { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}
.tabbar svg { width: 22px; height: 22px; stroke: currentColor; stroke-width: 1.8; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.tabbar a.is-active, .tabbar button.is-active { color: var(--ink); font-weight: 800; }

/* ── pressed states ───────────────────────────────────────────────────── */

/* Touch has no hover, so the press itself has to answer: every tappable
   surface dims or sinks the moment a finger lands (no delay, no layout). */
.chip:active { background: var(--surface-sunk); transform: scale(0.97); }
.chip.is-on:active, .chip[aria-pressed="true"]:active { background: var(--primary); opacity: 0.85; }
.side-nav a:active, .side-nav button:active { background: var(--surface-sunk); }
.side-nav a.is-active:active, .side-nav button.is-active:active { background: var(--primary); opacity: 0.85; }
.tabbar a:active, .tabbar button:active { background: var(--surface-sunk); }
.table tbody tr.is-clickable:active { background: var(--surface-sunk); }
.btn-primary:active:not(:disabled) { opacity: 0.85; }
.btn-secondary:active:not(:disabled), .btn-ghost:active:not(:disabled) { background: var(--surface-sunk); }
.btn-danger:active:not(:disabled) { background: var(--danger-bg); }
.clickable-card:active { background: var(--surface-2); transform: scale(0.99); }
.chip, .side-nav a, .side-nav button, .tabbar a, .tabbar button { -webkit-tap-highlight-color: transparent; }

/* Long lists: skip layout and paint for cards that are off screen. Put
   .cv-auto on a card or block in a long stack (not on table rows: layout
   containment does not apply to them). The intrinsic size keeps the scrollbar
   steady; "auto" remembers the real height once it has been on screen. */
.cv-auto { content-visibility: auto; contain-intrinsic-size: auto 240px; }
.cv-row { content-visibility: auto; contain-intrinsic-size: auto 76px; }

/* View transitions (yespacUI.transition): a short cross-fade between screens.
   While one runs, entrance animations stand down so the two never stack. */
::view-transition-old(root), ::view-transition-new(root) {
  animation-duration: 0.14s;
  animation-timing-function: ease-out;
}
html.vt-run .yp-enter, html.vt-run .yp-enter-scale, html.vt-run .yp-enter-stagger > * { animation: none; }

/* ── quote builder summary bar ────────────────────────────────────────── */

/* Floating rounded bar pinned to the bottom of the builder: total on the left
   (.summary-total, 22/800), the accent "Review" pill on the right. */
.summary-bar {
  position: sticky;
  bottom: calc(var(--safe-bottom) + var(--s-3));
  z-index: var(--z-sticky);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  background: var(--surface);
  border: 1px solid var(--ink);
  border-radius: var(--r-lg);
  color: var(--ink);
}
.summary-total { font-size: var(--fs-6); font-weight: 800; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }

/* ── modals and sheets ────────────────────────────────────────────────── */

/* Full-screen dim layer. Add .is-open to show. Modal content is a child
   (.modal) centred inside it; a .sheet is a sibling (or child) panel. */
.scrim {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s-4);
  background: var(--scrim);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-fast) var(--ease), visibility var(--dur-fast) var(--ease);
}
.scrim.is-open { opacity: 1; visibility: visible; }

/* Centred dialog. Confirm dialogs name the record and use verb buttons
   ("Keep order" .btn-secondary / "Cancel order" .btn-danger.is-filled) in
   .modal-actions. */
.modal {
  width: 100%;
  max-width: 440px;
  max-height: calc(100vh - 32px);
  max-height: calc(100dvh - 32px);
  overflow-y: auto;
  padding: var(--s-6);
  background: var(--surface);
  color: var(--ink);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-pop);
}
.modal-title { font-size: var(--fs-5); font-weight: 800; letter-spacing: -0.01em; margin-bottom: var(--s-2); }
.modal-body { font-size: 15px; color: var(--ink-2); margin-bottom: var(--s-5); }
.modal-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--s-2); }

/* Bottom sheet on mobile (top corners rounded). Add .is-open to slide up.
   .sheet-side turns it into a right-hand panel on desktop. */
.sheet {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: var(--z-sheet);
  max-height: 92vh;
  max-height: 92dvh;
  padding-left: var(--safe-left);
  padding-right: var(--safe-right);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  color: var(--ink);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  box-shadow: var(--shadow-pop);
  padding-bottom: var(--safe-bottom);
  transform: translateY(100%);
  visibility: hidden;
  transition: transform var(--dur) var(--ease), visibility var(--dur) var(--ease);
}
.sheet.is-open { transform: translateY(0); visibility: visible; }
@media (min-width: 900px) {
  .sheet.sheet-side {
    left: auto; top: 0;
    width: 480px;
    max-height: none;
    border-radius: var(--r-lg) 0 0 var(--r-lg);
    transform: translateX(100%);
  }
  .sheet.sheet-side.is-open { transform: translateX(0); }
}

/* ── toasts ───────────────────────────────────────────────────────────── */

/* Pill toast, bottom centre. Rendered by yespacUI.toast(); kind adds
   .yp-toast-error / .yp-toast-success (tinted, not saturated). */
.yp-toast-stack {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(var(--safe-bottom) + 16px);
  z-index: var(--z-toast);
  display: grid;
  justify-items: center;
  gap: 8px;
  width: max-content;
  max-width: min(420px, calc(100vw - 32px));
  /* Never stretch, even if a page pins both top and bottom. */
  height: max-content;
  pointer-events: none;
}
@media (max-width: 767px), (max-height: 500px) and (pointer: coarse) {
  .yp-toast-stack { bottom: auto; top: calc(var(--safe-top) + 12px); }
}
.yp-toast {
  padding: 11px 20px;
  border-radius: var(--r-pill);
  background: var(--primary);
  color: var(--on-primary);
  font: 600 14px/1.35 var(--font);
  box-shadow: var(--shadow-pop);
}
.yp-toast-error { background: var(--danger-bg); color: var(--danger); border: 1px solid var(--danger); }
.yp-toast-success { background: var(--good-bg); color: var(--good); border: 1px solid var(--good); }

/* ── logo ─────────────────────────────────────────────────────────────── */

/* The red/black wordmark sits straight on light surfaces. In dark mode wrap
   it in .logo-plate so the black "PAC" stays legible. */
.logo-plate { display: inline-flex; align-items: center; }
:root[data-theme="dark"] .logo-plate {
  background: #f6f2ea;   /* fixed light plate; the one allowed hex outside tokens */
  border-radius: 6px;
  padding: 4px 8px;
}

/* ── misc ─────────────────────────────────────────────────────────────── */

/* Touch: 44px floor for anything tappable. */
@media (pointer: coarse) {
  .btn, .side-nav a, .side-nav button { min-height: 44px; }
}

/* ── file viewer ──────────────────────────────────────────────────────── */

.fv-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-viewer);
  background: rgba(0, 0, 0, 0.72);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur) var(--ease), visibility var(--dur) var(--ease);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}
.fv-overlay.open { opacity: 1; visibility: visible; }

.fv-sheet {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  background: var(--bg);
  transform: translateY(12px);
  transition: transform var(--dur) var(--ease);
}
.fv-overlay.open .fv-sheet { transform: translateY(0); }

.fv-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: calc(var(--safe-top) + 8px) 12px 8px;
  background: var(--surface);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid var(--line);
  flex-shrink: 0;
}
.fv-title {
  flex: 1;
  min-width: 0;
  text-align: center;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fv-close, .fv-dl {
  flex-shrink: 0;
  min-height: 44px;
  padding: 0 10px;
  border: none;
  background: none;
  color: var(--ink);
  font-size: 15px;
  font-weight: 700;
  border-radius: var(--r-pill);
  cursor: pointer;
}

/* Scrollable so a large scan can be panned; pinch-zoom is the browser's. */
.fv-body {
  flex: 1;
  overflow: auto;
  -webkit-overflow-scrolling: touch;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  padding-bottom: calc(var(--safe-bottom) + 16px);
}
.fv-img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: var(--r-sm);
  background: #fff;   /* transparent artwork needs a ground to read against */
}
.fv-msg { text-align: center; color: var(--ink-2); font-size: 15px; line-height: 1.5; }
.fv-icon { font-size: 44px; margin-bottom: 10px; }
.fv-hint { font-size: 13px; color: var(--ink-2); margin-top: 6px; max-width: 260px; }

/* ── appearance control ───────────────────────────────────────────────── */

.appearance-row {
  display: flex;
  gap: 2px;
  padding: 2px;
  background: var(--surface-sunk);
  border-radius: 9px;
}
.appearance-opt {
  flex: 1;
  min-height: 44px;    /* the floor every other control here is held to */
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--ink);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -0.01em;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease);
}
.appearance-opt.selected {
  background: var(--surface);
  font-weight: 600;
  box-shadow: none;
}

/* ── support chat ─────────────────────────────────────────────────────── */

.chat-fab {
  position: relative;
  background: none;
  border: none;
  cursor: pointer;
  padding: 8px;
  display: inline-flex;
  min-height: 44px;
  min-width: 44px;
  align-items: center;
  justify-content: center;
}
.chat-fab svg { width: 24px; height: 24px; stroke: var(--ink); stroke-width: 2; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.chat-badge {
  position: absolute;
  top: 0;
  right: 0;
  min-width: 18px;
  height: 18px;
  border-radius: 100px;
  background: var(--accent);
  color: var(--on-accent);
  font-size: 12px;
  font-weight: 600;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 0 5px;
  border: 2px solid var(--surface);
}
.chat-badge.show { display: inline-flex; }

/* Full-screen sheet on a phone; a right-hand panel on anything wider, so the
   ops hub on a desktop is not one enormous white page of chat. */
.chat-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-chat);
  background: var(--bg);
  display: flex;
  flex-direction: column;
  transform: translateY(100%);
  visibility: hidden;
  transition: transform var(--dur) var(--ease), visibility var(--dur) var(--ease);
}
.chat-overlay.open { transform: translateY(0); visibility: visible; }
@media (min-width: 768px) {
  .chat-overlay {
    left: auto;
    width: 420px;
    border-left: 1px solid var(--line);
    box-shadow: var(--shadow-pop);
    transform: translateX(100%);
  }
  .chat-overlay.open { transform: translateX(0); }
}
@media (min-width: 1100px) {
  .chat-overlay { width: 440px; }
}

.chat-bar {
  display: flex;
  align-items: center;
  padding: calc(var(--safe-top) + 6px) 6px 6px;
  background: var(--surface);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid var(--line);
  flex-shrink: 0;
}
/* Equal-width side slots keep the title truly centred. */
.chat-bar-side { min-width: 76px; display: flex; }
.chat-bar-side.right { justify-content: flex-end; }
.chat-bar-title {
  flex: 1;
  min-width: 0;
  text-align: center;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.chat-bar button {
  min-height: 44px;
  padding: 0 12px;
  border: none;
  background: none;
  color: var(--ink);
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
}

.chat-msgs {
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  padding: 12px 14px 10px;
  display: flex;
  flex-direction: column;
}
.chat-bubble {
  max-width: 78%;
  padding: 8px 13px;
  border-radius: 18px;
  font-size: 15px;
  line-height: 1.35;
  word-wrap: break-word;
  white-space: pre-wrap;
  margin-top: 2px;
}
.chat-bubble.chat-enter { animation: yp-rise-in var(--dur-fast) var(--motion-enter) both; }
.chat-bubble.first { margin-top: 12px; }
.chat-bubble.me { align-self: flex-end; background: var(--primary); color: var(--on-primary); border-bottom-right-radius: 5px; }
.chat-bubble.them {
  align-self: flex-start;
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--line);
  border-bottom-left-radius: 5px;
}
.chat-time { font-size: 12px; color: var(--ink-2); margin: 3px 6px 0; }
.chat-time.me { align-self: flex-end; }
.chat-time.them { align-self: flex-start; }
.chat-day {
  align-self: center;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-2);
  margin: 14px 0 2px;
}
.chat-empty { align-self: center; text-align: center; color: var(--ink-2); font-size: 14px; margin-top: 48px; max-width: 250px; line-height: 1.5; }
.chat-empty .chat-empty-title {
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin-bottom: 6px;
}
.chat-msg-pending { opacity: 0.62; }
.chat-msg-failed { opacity: 1; outline: 1.5px solid var(--accent); outline-offset: 2px; }
.chat-send-err {
  font-size: 12px;
  color: var(--accent);
  padding: 4px 14px 0;
  text-align: center;
}

.chat-input-row {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  padding: 8px 12px calc(var(--safe-bottom) + 8px);
  background: var(--surface);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  border-top: 1px solid var(--line);
  flex-shrink: 0;
}
.chat-input {
  flex: 1;
  min-height: 36px;
  min-height: max(36px, var(--tap-min, 0px));
  max-height: 110px;
  padding: 7px 14px;
  border: 1px solid var(--line);
  border-radius: 18px;
  background: var(--surface);
  color: var(--ink);
  font-size: 16px;   /* under 16 and iOS zooms the page on focus */
  font-family: inherit;
  resize: none;
}
/* The global focus ring is for keyboard users finding their place; a chat
   input you are already typing in does not need a 2px halo. */
.chat-input:focus-visible { outline: none; border-color: var(--ink-2); }

/* Round send button, arrow only — lit when there is something to send. */
.chat-send {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border: none;
  border-radius: 50%;
  background: var(--surface-sunk);
  color: var(--ink-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.chat-send svg { width: 18px; height: 18px; stroke: currentColor; stroke-width: 2.5; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.chat-send.ready { background: var(--accent); color: var(--on-accent); }

/* staff: the thread list shown before a conversation is opened */
.chat-thread {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  text-align: left;
  padding: 11px 14px;
  border: none;
  background: none;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
  min-height: 44px;
}
.chat-thread.chat-enter { animation: yp-rise-in var(--dur-fast) var(--motion-enter) both; }
.chat-thread:active { background: var(--surface-sunk); }
@media (hover: hover) { .chat-thread:hover { background: var(--surface-sunk); } }
.chat-avatar {
  flex-shrink: 0;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: var(--surface-sunk);
  color: var(--ink);
  font-size: 16px;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.chat-thread-main { flex: 1; min-width: 0; }
.chat-thread-top { display: flex; align-items: baseline; gap: 8px; }
.chat-thread-name { flex: 1; min-width: 0; font-size: 15px; font-weight: 600; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-thread-when { flex-shrink: 0; font-size: 12px; color: var(--ink-2); }
.chat-thread-last { font-size: 13px; color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 1px; }
.chat-thread.unread .chat-thread-last { color: var(--ink); font-weight: 500; }
.chat-thread-unread {
  flex-shrink: 0;
  min-width: 20px;
  height: 20px;
  border-radius: 100px;
  background: var(--accent);
  color: var(--on-accent);
  font-size: 12px;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 6px;
}

/* ── PWA update prompt ────────────────────────────────────────────────── */

#yp-update-prompt {
  position: fixed;
  inset: 0;
  z-index: var(--z-update);
  display: flex;
  justify-content: center;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 24px;
  padding-top: max(24px, env(safe-area-inset-top));
  padding-bottom: max(24px, env(safe-area-inset-bottom));
  background: var(--scrim);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}

.yp-update-sheet {
  /* margin:auto centres it when it fits and lets it start at the top when it doesn't. */
  margin: auto;
  background: var(--surface);
  border-radius: var(--r-lg);
  padding: 28px 24px;
  text-align: center;
  box-shadow: var(--shadow-pop);
  max-width: 340px;
  width: 100%;
}

.yp-update-title {
  font-family: var(--font);
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0 0 8px;
  color: var(--ink);
}

.yp-update-body {
  color: var(--ink-2);
  font-size: 15px;
  line-height: 1.35;
  margin: 0 0 18px;
}

.yp-update-notes {
  list-style: none;
  text-align: left;
  margin: 0 0 18px;
  padding: 12px 14px;
  border-radius: var(--r-md);
  background: var(--surface-sunk);
}

.yp-update-notes li {
  position: relative;
  padding: 6px 0 6px 14px;
  font-size: 14px;
  line-height: 1.35;
  color: var(--ink);
}

.yp-update-notes li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 12px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
}

.yp-update-primary {
  width: 100%;
  min-height: 50px;
  padding: 14px;
  border: none;
  border-radius: var(--r-md);
  background: var(--accent);
  color: var(--on-accent);
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
  cursor: pointer;
}

.yp-update-primary:active {
  background: var(--accent-press);
}

.yp-update-secondary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 44px;
  margin-top: 6px;
  padding: 8px;
  border: none;
  border-radius: var(--r-md);
  background: none;
  color: var(--accent);
  font-size: 16px;
  font-weight: 500;
  cursor: pointer;
}

.yp-update-secondary[hidden] {
  display: none !important;
}
