@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800&family=Inter:wght@400;500;600;700&display=swap');

/* =====================================================================
   Polka design tokens.

   The palette is built on what colour research in food service actually
   supports, rather than on taste:

   - Warm hues (red / orange / yellow) are the ones consistently linked to
     appetite, and they dominate food branding for that reason. Polka's
     accent is a saffron gold - warm and food-associated (honey, turmeric,
     baked crust) without being the same electric orange as every other
     delivery app.
   - Green reads as fresh, natural and safe-to-eat, so it carries the
     "available / done / fresh" meaning rather than being decoration.
   - Red-orange (tomato) carries failure and urgency - still warm, so an
     error state never feels cold next to everything else.
   - Cool blues are appetite-suppressing next to food, so exactly one
     desaturated blue exists, and only on the "accepted" status chip where
     no food is depicted. It is never a surface, never a fill, never large.
   - Surfaces are warm espresso neutrals, not blue-black, so the whole
     panel reads as kitchen rather than server rack. Each surface step is a
     deliberately large jump (~10-14 per channel) so cards, headers, inputs
     and the page behind them stay visually distinct.

   Light mode redefines only these tokens further down - every rule in this
   file reads from the variables, never from a literal colour.
   ===================================================================== */

:root {
  color-scheme: dark;

  --bg: #100c09;
  --surface-1: #1b1512;
  --surface-2: #251d18;
  --surface-3: #33281f;

  --accent: #f2a71b;          /* saffron */
  --accent-hover: #ffbb3c;
  --accent-ink: #241703;      /* text/icons that sit ON the accent fill */
  --accent-wash: rgba(242, 167, 27, 0.12);
  --accent-ring: rgba(242, 167, 27, 0.28);

  --text: #f7f2ea;            /* warm off-white, not clinical #fff */
  --text-secondary: #b8ab9b;
  --text-tertiary: #857a6d;

  --border: rgba(255, 236, 210, 0.14);
  --border-strong: rgba(255, 236, 210, 0.24);

  --danger: #f2554d;          /* tomato */
  --danger-wash: rgba(242, 85, 77, 0.12);
  --success: #4cb96b;         /* basil */
  --success-wash: rgba(76, 185, 107, 0.12);
  --warn: #f0912e;
  --warn-wash: rgba(240, 145, 46, 0.13);
  --info: #6fa8c9;            /* the one cool hue - status chips only */
  --info-wash: rgba(111, 168, 201, 0.13);
  --muted-wash: rgba(255, 236, 210, 0.07);

  /* Golden-ratio-derived spacing scale (Fibonacci approximation of phi) */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 13px;
  --space-4: 21px;
  --space-5: 34px;
  --space-6: 55px;
  --space-7: 89px;

  /* Type scale */
  --text-xs: 0.75rem;
  --text-sm: 0.8125rem;
  --text-base: 1rem;
  --text-lg: 1.125rem;
  --text-xl: 1.25rem;
  --text-2xl: 1.5rem;
  --text-3xl: 1.875rem;

  /* Radius scale */
  --radius-sm: 10px;
  --radius-md: 16px;
  --radius-lg: 24px;
  --radius-full: 999px;

  --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.24);
  --shadow-md: 0 12px 32px -8px rgba(0, 0, 0, 0.5);
  --shadow-accent: 0 10px 28px -8px rgba(242, 167, 27, 0.4);

  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  --sidebar-width: 248px;
}

/* Light mode. Only the colour tokens change - every size, radius, weight
   and timing above is shared, so the two themes are the same product. The
   accent darkens because saffron on white fails contrast for text and for
   white-on-accent buttons; --accent-ink flips to white to match. */
:root[data-theme="light"] {
  color-scheme: light;

  --bg: #faf6f0;
  --surface-1: #ffffff;
  --surface-2: #f5efe6;
  --surface-3: #ece2d4;

  --accent: #a8620a;
  --accent-hover: #8d5108;
  --accent-ink: #ffffff;
  --accent-wash: rgba(168, 98, 10, 0.09);
  --accent-ring: rgba(168, 98, 10, 0.22);

  --text: #1c1714;
  --text-secondary: #6b6055;
  --text-tertiary: #938779;

  --border: rgba(28, 23, 20, 0.13);
  --border-strong: rgba(28, 23, 20, 0.24);

  --danger: #c0392f;
  --danger-wash: rgba(192, 57, 47, 0.09);
  --success: #2f7d47;
  --success-wash: rgba(47, 125, 71, 0.1);
  --warn: #a8620a;
  --warn-wash: rgba(168, 98, 10, 0.11);
  --info: #2b6d8a;
  --info-wash: rgba(43, 109, 138, 0.1);
  --muted-wash: rgba(28, 23, 20, 0.06);

  --shadow-sm: 0 1px 3px rgba(60, 40, 20, 0.09);
  --shadow-md: 0 12px 32px -12px rgba(60, 40, 20, 0.22);
  --shadow-accent: 0 8px 22px -10px rgba(168, 98, 10, 0.4);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  min-height: 100vh; /* fallback for browsers without dvh support */
  min-height: 100dvh;
  background: var(--bg);
  color: var(--text);
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
  /* Feels like an app, not a webpage - no text-selection I-beam cursor or accidental
     highlight when tapping headings, labels, buttons, etc. Re-enabled below for anything
     you'd actually want to select or copy (form fields, generated codes/IDs). */
  -webkit-user-select: none;
  user-select: none;
}

input, textarea, .selectable {
  -webkit-user-select: text;
  user-select: text;
}

/* Settings (and every other admin/config page sharing .settings-wrap) is a text-heavy config
   surface, not the tap-and-go operational screens - headings, hints, labels, and especially error/status
   messages need to be selectable so they can be copied for support, unlike the rest of the app's
   deliberate no-select "native app" feel above. */
.settings-wrap, .settings-wrap * {
  -webkit-user-select: text;
  user-select: text;
}

body {
  background-image: radial-gradient(circle at 20% -10%, var(--accent-wash), transparent 45%);
  background-attachment: fixed;
}

h1, h2, h3, .brand {
  font-family: 'Outfit', 'Inter', sans-serif;
  letter-spacing: -0.015em;
  color: var(--text);
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hover); }

code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  background: var(--surface-3);
  padding: 2px 7px;
  border-radius: 6px;
  font-size: 0.9em;
}

svg.icon {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
}

/* Accent-themed scrollbars everywhere - checkbox lists, textareas, the page itself */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--accent) var(--surface-2);
}
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-track { background: var(--surface-2); border-radius: 8px; }
*::-webkit-scrollbar-thumb { background: var(--accent); border-radius: 8px; }
*::-webkit-scrollbar-thumb:hover { background: var(--accent-hover); }

select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23b8ab9b' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") !important;
  background-repeat: no-repeat !important;
  background-position: right 14px center !important;
  background-size: 16px !important;
  padding-right: 42px !important;
}
select::-ms-expand { display: none; }

/* ---------- App shell (narrow, single-column pages) ---------- */

.app {
  max-width: 480px;
  margin: 0 auto;
  min-height: 100vh; /* fallback for browsers without dvh support */
  min-height: 100dvh;
  padding: var(--space-5) var(--space-4) calc(var(--space-6) + 84px);
}
/* On the home page, header + main + footer share the viewport. The generic .app min-height used
   to claim a whole viewport by itself, forcing the footer below the fold behind empty space. */
.home-page {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
}
.home-page .app {
  width: 100%;
  min-height: 0;
  flex: 1 0 auto;
  padding-bottom: var(--space-5);
}
.home-page .app-footer {
  flex-shrink: 0;
  padding-top: var(--space-4);
  padding-bottom: var(--space-4);
}
@media (max-width: 420px) {
  .app { padding-left: 14px; padding-right: 14px; }
}

/* Sticky top bar: the bar itself spans the full viewport (background/blur/border reach both
   edges), but the hamburger | centered title | gear row inside is capped to the same 480px
   column as the app content, so those controls line up with the content below them instead of
   floating out at the far edges of a wide screen. */
.app-header {
  position: sticky;
  top: 0;
  z-index: 30;
  background: var(--surface-1);
  background: color-mix(in srgb, var(--surface-1) 92%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--border);
}
.app-header-inner {
  display: grid;
  grid-template-columns: 44px 1fr 44px;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  max-width: 480px;
  margin: 0 auto;
}
.header-gear-btn {
  grid-column: 3;
  justify-self: end;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text);
}
.header-gear-btn:hover { background: var(--surface-2); color: var(--accent); }

.app-footer {
  max-width: 480px;
  margin: 0 auto;
  padding: var(--space-5) var(--space-4) var(--space-6);
  text-align: center;
  border-top: 1px solid var(--border);
}
.app-footer-links { display: flex; gap: var(--space-4); justify-content: center; margin-bottom: var(--space-2); flex-wrap: wrap; }
.app-footer-links a { color: var(--text-tertiary); font-size: var(--text-sm); }
.app-footer-links a:hover { color: var(--accent); }
.app-footer-copy { color: var(--text-tertiary); font-size: var(--text-xs); margin: 0; }
.app-header h1 {
  font-size: var(--text-xl);
  font-weight: 700;
  margin: 0;
  white-space: nowrap;
}
.brand-link {
  grid-column: 2;
  justify-self: center;
  color: var(--text);
}
.brand-link:hover { color: var(--accent); }
.app-header-spacer { grid-column: 3; }

.menu-toggle {
  grid-column: 1;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-sm);
  border: none;
  background: transparent;
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.menu-toggle:hover { background: var(--surface-2); color: var(--accent); }

.app-menu-overlay {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(0, 0, 0, 0.55);
}
.app-menu {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  z-index: 41;
  width: min(78vw, 300px);
  background: var(--surface-1);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  padding: 0;
  transform: translateX(-100%);
  transition: transform 0.25s var(--ease-out);
  overflow-y: auto;
}
.app-menu.is-open { transform: translateX(0); }
.app-menu[hidden] { display: none; } /* same hidden-attribute-vs-class-display fix as the page viewer */
.app-menu-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-4);
  border-bottom: 1px solid var(--border);
}
.app-menu-brand {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
  color: var(--text);
}
.app-menu-brand:hover { color: var(--text); }
.app-menu-brand img { width: 40px; height: 40px; flex-shrink: 0; }
.app-menu-brand-copy { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.app-menu-brand-copy strong {
  font-family: 'Outfit', 'Inter', sans-serif;
  font-size: var(--text-base);
  line-height: 1.2;
}
.app-menu-brand-copy small {
  color: var(--text-tertiary);
  font-size: var(--text-xs);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 150px;
}
.app-menu-close {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: none;
  background: var(--surface-2);
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.app-menu-close:hover { color: var(--accent); }
.app-menu-list {
  margin: var(--space-3) var(--space-4) 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--surface-2);
}
.app-menu-list-footer { margin-top: auto; margin-bottom: var(--space-4); }
.app-menu-item {
  min-height: 48px;
  padding: 0 12px;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  color: var(--text);
  font-size: var(--text-sm);
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.app-menu-item:last-child { border-bottom: 0; }
.app-menu-item::after {
  content: "›";
  color: var(--text-tertiary);
  font-size: var(--text-lg);
  font-weight: 400;
}
.app-menu-item:hover { background: var(--surface-3); color: var(--accent); }
.app-menu-item:hover::after { color: currentColor; }
.app-menu-item-danger { color: var(--danger); }
.app-menu-item-danger:hover { color: var(--danger); background: var(--danger-wash); }
.app-menu-footlinks {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 12px;
  font-size: var(--text-xs);
  color: var(--text-tertiary);
  border-bottom: 1px solid var(--border);
}
.app-menu-footlinks a { color: var(--text-tertiary); font-weight: 600; text-decoration: none; }
.app-menu-footlinks a:hover { color: var(--accent); }

.spinner {
  width: 36px;
  height: 36px;
  border: 3px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
  margin-top: 90px;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Sticky action bar at the bottom of the viewport - only one .screen is ever active at a time, so
   there's never more than one of these visible despite every screen defining its own. */
.button-row {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 20;
  display: flex;
  gap: var(--space-3);
  max-width: 480px;
  margin: 0 auto;
  padding: var(--space-3) var(--space-4);
  padding-bottom: calc(var(--space-3) + env(safe-area-inset-bottom, 0px));
  background: var(--surface-1);
  background: color-mix(in srgb, var(--surface-1) 92%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-top: 1px solid var(--border);
  box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.35);
}
@media (max-width: 420px) {
  .button-row { padding-left: 14px; padding-right: 14px; }
}

.btn-primary, .btn-secondary {
  flex: 1;
  text-align: center;
  padding: 14px 16px;
  border-radius: var(--radius-sm);
  border: none;
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: inherit;
  min-height: 48px;
  transition: transform 0.15s var(--ease-out), box-shadow 0.15s var(--ease-out), opacity 0.15s var(--ease-out), background 0.15s var(--ease-out);
}
.btn-primary {
  background: var(--accent);
  color: var(--accent-ink);
  box-shadow: var(--shadow-accent);
}
.btn-primary:hover { background: var(--accent-hover); transform: translateY(-1px); }
.btn-primary:active { transform: translateY(0) scale(0.98); }
.btn-primary:disabled { opacity: 0.55; cursor: default; transform: none; box-shadow: none; }
.btn-secondary {
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
}
.btn-secondary:hover { border-color: var(--accent); color: var(--accent); }
.btn-secondary:active { transform: scale(0.98); }
.btn-full { width: 100%; }
.btn-chatgpt-setup {
  width: fit-content;
  max-width: 100%;
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  margin-bottom: var(--space-4);
}
.btn-chatgpt-setup svg { flex-shrink: 0; }

.success-icon, .error-icon {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  margin-top: var(--space-6);
}
.success-icon { background: var(--success); }
.error-icon { background: var(--danger); }
.success-icon svg, .error-icon svg { width: 28px; height: 28px; }

#screen-success, #screen-error { text-align: center; }
#success-fileLink { width: 100%; }

/* ---------- Auth pages (login / setup / reset) ---------- */

.auth-shell {
  min-height: 100vh; /* fallback for browsers without dvh support */
  min-height: 100dvh;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 10px;
  padding-top: max(var(--space-6), 8vh);
}
.auth-card {
  width: 100%;
  max-width: 400px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: 40px 18px;
}
.brand {
  font-size: var(--text-2xl);
  font-weight: 800;
  text-align: center;
  margin: 0;
  color: var(--accent);
}
.auth-subtitle {
  text-align: center;
  color: var(--text-secondary);
  font-size: var(--text-sm);
  margin: var(--space-2) 0 var(--space-5);
}
.auth-form { display: flex; flex-direction: column; gap: var(--space-4); }
.auth-form label { display: flex; flex-direction: column; gap: var(--space-2); font-size: var(--text-sm); color: var(--text-secondary); font-weight: 500; }
.auth-form .checkbox-inline {
  flex-direction: row !important;
  align-items: center;
  gap: 8px !important;
}
.auth-form .checkbox-inline input { width: 16px; height: 16px; accent-color: var(--accent); flex-shrink: 0; }
.auth-form input, .auth-form select, .auth-form textarea {
  font-size: var(--text-base);
  padding: 13px 15px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text);
  font-family: inherit;
  transition: border-color 0.2s var(--ease-out), box-shadow 0.2s var(--ease-out);
}
.auth-form input:focus, .auth-form select:focus, .auth-form textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 4px var(--accent-ring);
}
.auth-form textarea {
  width: 100%;
  resize: vertical;
  line-height: 1.55;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--text-sm);
}

.password-field { position: relative; }
.password-field input { width: 100%; padding-right: 44px; }
.password-toggle {
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  color: var(--text-tertiary);
  cursor: pointer;
  padding: 8px;
  display: flex;
  border-radius: var(--radius-sm);
}
.password-toggle:hover { color: var(--text); }
.auth-footer-link { text-align: center; margin-top: var(--space-4); font-size: var(--text-sm); }
.optional { font-weight: 400; opacity: 0.7; }

/* ---------- Settings / admin pages ---------- */

.settings-wrap { max-width: 560px; margin: 0 auto; padding: var(--space-6) var(--space-5) calc(var(--space-6) + 76px); }
@media (max-width: 420px) {
  .settings-wrap { padding-left: 14px; padding-right: 14px; }
}
.settings-wrap h1 { font-size: var(--text-2xl); font-weight: 700; margin: 0 0 var(--space-2); }
.settings-wrap h2 { font-size: var(--text-lg); font-weight: 600; margin: 0 0 var(--space-1); }

/* Settings is a dense reference/configuration surface. Keep its prose compact while preserving
   44px controls and 16px mobile inputs (the latter prevents iOS from zooming on focus). */
.settings-wrap {
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}

.topbar { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--space-5); }
.topbar-link { font-size: var(--text-sm); color: var(--text-secondary); display: inline-flex; align-items: center; gap: 6px; }
.topbar-link:hover { color: var(--accent); }

.card {
  --card-pad: var(--space-5);
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--card-pad);
  margin-bottom: var(--space-4);
}
.card h2 { margin-bottom: var(--space-3); }
/* A plain (non-accordion) card can still get the same "header strip sitting on top of the body"
   look as an accordion card's summary - same negative-margin trick, just not collapsible. Gives
   flat single-surface boxes (device lists, etc.) proper visual hierarchy instead of the title
   blending into the same surface as everything below it. */
.card-header-band {
  margin: calc(-1 * var(--card-pad)) calc(-1 * var(--card-pad)) 0;
  padding: var(--card-pad);
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
.card-header-band h2 { margin: 0; }
.card-body-pad { padding-top: var(--card-pad); }
/* On phones, the card's own fixed 34px padding was stacking on top of .settings-wrap's page
   margin and each nested section's own padding, eating a big chunk of an already-narrow screen.
   Shrinking it here (everything below derives its spacing from this one custom property) gets
   real content back to something closer to full width without touching desktop at all. */
@media (max-width: 480px) {
  /* Scoped to accordion cards specifically, not every .card - a plain standalone card (device
     list, user list) only ever has one padding level and looked cramped when this also shrank
     it; accordion cards are the ones where padding compounds across several nested sections. */
  .card.accordion-item { --card-pad: var(--space-3); }
}

.accordion-item summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.accordion-item summary::-webkit-details-marker { display: none; }
.accordion-item > summary h2 {
  margin: 0;
  font-size: var(--text-xl);
  font-weight: 700;
  letter-spacing: -0.01em;
}
.accordion-item[open] > summary { margin-bottom: var(--space-3); }

/* Top-level section headers read as their own header "tab" - a distinct strip sitting on top of
   the card, not just larger text blended into the same body. overflow:hidden on the card clips
   the tab's square bottom corners to the card's own rounded ones when collapsed. */
.card.accordion-item { overflow: hidden; }
.card.accordion-item > summary {
  margin: calc(-1 * var(--card-pad)) calc(-1 * var(--card-pad)) 0;
  padding: var(--card-pad);
  background: var(--surface-2);
  transition: background 0.15s var(--ease-out);
}
.card.accordion-item > summary:hover { background: var(--surface-3); }
.card.accordion-item:not([open]) > summary {
  /* Cancel the card's retained bottom padding so a closed accordion is one clean header row. */
  margin-bottom: calc(-1 * var(--card-pad));
}
.card.accordion-item[open] > summary {
  margin-bottom: 0;
  border-bottom: 1px solid var(--border);
}
.card.accordion-item > .accordion-body { padding-top: var(--card-pad); }
.accordion-chevron { color: var(--text-tertiary); flex-shrink: 0; transition: transform 0.2s var(--ease-out); }
/* Scoped to > summary > chevron so an open outer accordion never rotates an inner, still-closed
   subsection's own arrow - a plain descendant selector here previously matched every nested
   chevron the moment any ancestor was open. */
.accordion-item[open] > summary > .accordion-chevron { transform: rotate(180deg); }
/* The single source of vertical rhythm for every settings section: headings, hint paragraphs,
   labels, buttons, and nested accordions all get consistent breathing room from this one gap
   instead of relying on each child's own (previously inconsistent, sometimes negative) margins. */
.accordion-body { display: flex; flex-direction: column; gap: var(--space-4); }

.accordion-item.nested {
  background: transparent;
  border: none;
  border-radius: 0;
  border-top: 1px solid transparent;
  border-image: linear-gradient(90deg, transparent, var(--border-strong) 8%, var(--border-strong) 92%, transparent) 1;
  padding: var(--space-5) 0 0;
  margin: var(--space-5) 0 0;
}
/* Each subsection can sit inside its own <form> (independent save per subsection), so sibling
   selectors like :first-of-type see only one child per form and never match correctly - the
   first subsection in a group is marked explicitly instead. */
.accordion-item.nested.no-divider {
  border-top: none;
  border-image: none;
  padding-top: 0;
  margin-top: 0;
}
.accordion-item.nested summary h3 {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-size: var(--text-base);
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--text-secondary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.accordion-item.nested[open] summary h3 { color: var(--text); }
.accordion-item.nested[open] summary { margin-bottom: var(--space-3); }

/* Section rails use a spice-rack palette - saffron, basil, tomato, berry.
   All four stay in the warm/fresh family the rest of the app lives in, and
   colour is limited to 2px rails, markers and chevrons; text stays neutral. */
.tone-saffron { --section-tone: #f2a71b; --section-wash: rgba(242, 167, 27, 0.05); }
.tone-basil   { --section-tone: #57b96f; --section-wash: rgba(87, 185, 111, 0.045); }
.tone-tomato  { --section-tone: #ef6a4d; --section-wash: rgba(239, 106, 77, 0.05); }
.tone-berry   { --section-tone: #c0578f; --section-wash: rgba(192, 87, 143, 0.045); }

.accordion-item.nested.section-panel,
.accordion-item.nested.section-panel.no-divider {
  border: 1px solid var(--border);
  border-left: 2px solid var(--section-tone);
  border-image: none;
  border-radius: var(--radius-sm);
  padding: 0;
  margin: 0;
  overflow: hidden;
  background: var(--surface-2);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
}
.accordion-item.nested.section-panel > summary {
  min-height: 48px;
  padding: 11px 13px;
  margin: 0;
  background: linear-gradient(90deg, var(--section-wash), rgba(255, 255, 255, 0.012) 56%, transparent);
  transition: background 0.18s var(--ease-out);
}
.accordion-item.nested.section-panel > summary:hover {
  background: linear-gradient(90deg, color-mix(in srgb, var(--section-tone) 8%, transparent), rgba(255, 255, 255, 0.018) 60%, transparent);
}
.accordion-item.nested.section-panel > summary::before {
  content: "";
  width: 12px;
  height: 2px;
  border-radius: 1px;
  flex-shrink: 0;
  background: var(--section-tone);
  box-shadow: 0 0 9px color-mix(in srgb, var(--section-tone) 45%, transparent);
}
.accordion-item.nested.section-panel > summary > .accordion-chevron {
  color: var(--section-tone);
  opacity: 0.82;
}
.accordion-item.nested.section-panel > summary h3,
.accordion-item.nested.section-panel[open] > summary h3,
.accordion-item.nested.section-panel > summary h3.step-title,
.accordion-item.nested.section-panel[open] > summary h3.step-title {
  color: var(--text);
}
.accordion-item.nested.section-panel[open] > summary {
  margin-bottom: 0;
  border-bottom: 1px solid var(--border);
}
.accordion-item.nested.section-panel > .accordion-body {
  padding: var(--space-3);
}

/* Notification channels reuse the same harmonized palette, kept to narrow rails and headings. */
.channel-panel {
  --channel-tone: var(--accent);
  --channel-wash: rgba(255, 255, 255, 0.014);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  min-width: 0;
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-left: 2px solid var(--channel-tone);
  border-radius: var(--radius-sm);
  background: linear-gradient(145deg, var(--channel-wash), rgba(0, 0, 0, 0.08));
}
.channel-telegram { --channel-tone: #57b96f; }
.channel-email { --channel-tone: #6fa8c9; }
.channel-templates { --channel-tone: #c0578f; }
.channel-routing { --channel-tone: #ef6a4d; }
.channel-panel-heading {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--border);
}
.channel-panel-heading h4,
.channel-template h4 {
  margin: 0;
  color: var(--text);
  font-family: 'Outfit', 'Inter', sans-serif;
  font-size: var(--text-sm);
  font-weight: 700;
}
.channel-panel-heading h4 { color: var(--channel-tone); }
.channel-template > h4 { color: var(--channel-tone); }
.channel-panel-heading span {
  color: var(--text-tertiary);
  font-size: 11px;
  text-align: right;
}
.channel-panel > label,
.channel-template > label { margin-bottom: 0; }
.channel-template {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-left: 2px solid var(--channel-tone);
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.018);
}
.channel-template-email { --channel-tone: #6fa8c9; }
.channel-template-telegram { --channel-tone: #57b96f; }
@media (max-width: 420px) {
  .channel-panel-heading { align-items: flex-start; flex-direction: column; }
  .channel-panel-heading span { text-align: left; }
}

.step-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--text-xs);
  font-weight: 700;
  padding: 3px 9px;
  border-radius: var(--radius-full);
  flex-shrink: 0;
  white-space: nowrap;
}
.step-badge-done { color: var(--success); background: var(--success-wash); }
.step-badge-pending { color: var(--text-tertiary); background: var(--surface-3); }

/* Getting Started step numbers get the brand accent so they stand out from every other nested
   accordion heading on this page - specificity matches .accordion-item.nested[open] summary h3
   (3 classes/attrs + 2 types either way), so this only wins because it's declared later. */
.accordion-item.nested summary h3.step-title,
.accordion-item.nested[open] summary h3.step-title {
  color: var(--accent);
}

.settings-form label,
.settings-wrap label {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--text-secondary);
  font-weight: 500;
  margin-bottom: var(--space-3);
}
.settings-form input,
.settings-form select,
.settings-form textarea,
.settings-wrap input,
.settings-wrap select,
.settings-wrap textarea {
  font-size: var(--text-base);
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text);
  font-family: inherit;
  width: 100%;
  min-width: 0;
  transition: border-color 0.2s var(--ease-out), box-shadow 0.2s var(--ease-out);
}
.settings-form .password-field input,
.settings-wrap .password-field input {
  padding-right: 44px;
}
.settings-form textarea { resize: vertical; min-height: 120px; }
.settings-wrap textarea,
.settings-wrap .copy-box-textarea {
  font-size: var(--text-xs);
  line-height: 1.55;
  font-variant-numeric: tabular-nums;
}
@media (max-width: 600px) {
  .settings-form input,
  .settings-form select,
  .settings-wrap input,
  .settings-wrap select { font-size: 16px; }
  .settings-wrap textarea,
  .settings-wrap .copy-box-textarea { font-size: 13px; }
}
.settings-form input:focus,
.settings-form select:focus,
.settings-form textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 4px var(--accent-ring);
}

.hint { font-size: var(--text-xs); color: var(--text-tertiary); margin: 0 0 var(--space-3); line-height: 1.6; }

.subhead { font-size: var(--text-sm); font-weight: 600; color: var(--text); margin: var(--space-5) 0 var(--space-2); }

/* One sticky bar for the whole Settings page, replacing a save button per subsection - fixed to
   the viewport bottom, hidden until something is actually unsaved. */
.global-save-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-5);
  padding-bottom: calc(var(--space-3) + env(safe-area-inset-bottom, 0px));
  background: var(--surface-1);
  background: color-mix(in srgb, var(--surface-1) 88%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-top: 1px solid var(--border);
  box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.35);
  transform: translateY(100%);
  opacity: 0;
  transition: transform 0.25s var(--ease-out), opacity 0.25s var(--ease-out);
  pointer-events: none;
}
.global-save-bar.is-visible {
  transform: translateY(0);
  opacity: 1;
  pointer-events: auto;
}
.global-save-status { font-size: var(--text-sm); color: var(--text-tertiary); }
.global-save-status.is-ok { color: var(--success); }
.global-save-status.is-error { color: var(--danger); }
.global-save-btn { min-width: 200px; }
/* Smart nudge, reused anywhere a button is the obvious next step (unsaved changes, a code just
   finished typing): a gentle pulse instead of a static disabled/enabled flip, so the eye finds it
   without having to hunt. Stops the moment it's clicked or the triggering condition clears. */
.btn-pulse-ready { animation: save-pulse 1.8s ease-in-out infinite; }
@keyframes save-pulse {
  0%, 100% { box-shadow: var(--shadow-accent), 0 0 0 0 var(--accent-ring); }
  50% { box-shadow: var(--shadow-accent), 0 0 0 8px var(--accent-ring); }
}
@media (prefers-reduced-motion: reduce) {
  .btn-pulse-ready { animation: none; }
}
@media (max-width: 560px) {
  .global-save-bar { justify-content: space-between; }
  .global-save-btn { min-width: 0; flex: 1 1 auto; }
}

.icon-input { flex: 0 0 64px !important; text-align: center; font-size: 1.1rem !important; }

.banner {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: 13px 16px;
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  margin-bottom: var(--space-4);
  line-height: 1.5;
}
.banner svg { flex-shrink: 0; margin-top: 1px; }
.banner.error { background: var(--danger-wash); color: var(--danger); }
.banner.success { background: var(--success-wash); color: var(--success); }
.banner.warning { background: var(--accent-wash); color: var(--accent); }
.banner a { color: inherit; text-decoration: underline; }

.seg-tabs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}
.seg-tab {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 13px 10px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  font-size: var(--text-sm);
  font-weight: 600;
  cursor: pointer;
  text-align: center;
  transition: border-color 0.2s var(--ease-out), background 0.2s var(--ease-out), color 0.2s var(--ease-out);
  min-height: 44px;
}
.seg-tab input { position: absolute; opacity: 0; pointer-events: none; }
.seg-tab:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-wash);
  color: var(--accent);
}

.seg-panel { display: none; margin-top: var(--space-2); }
.seg-panel.active { display: block; }

.model-row { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: stretch; }
.model-row select, .model-row input, .model-row .password-field { flex: 1; min-width: 0; }
.model-row .password-field input { width: 100%; height: 100%; }
.model-row button { white-space: nowrap; padding: 12px 16px; font-size: var(--text-sm); min-height: 44px; }
@media (max-width: 480px) {
  .model-row { flex-direction: column; }
  .model-row select, .model-row input, .model-row .password-field, .model-row button { width: 100%; }
}

.model-status { font-size: var(--text-xs); color: var(--text-tertiary); margin: 6px 0 0; min-height: 16px; line-height: 1.6; }
.model-status.is-error { color: var(--danger); }
.model-status.is-ok { color: var(--success); }

/* Wraps any .model-status that needs a one-click copy button - see settings.php for which ones.
   The button only appears once there's an actual error to copy (:has() keeps this CSS-only, no
   JS needed to toggle visibility whenever a status message changes). */
.status-line { display: flex; align-items: flex-start; gap: 8px; margin-top: 6px; }
.status-line .model-status { margin: 0; flex: 1; }
.status-copy-btn {
  display: none; flex-shrink: 0; align-items: center; justify-content: center;
  width: 26px; height: 26px; margin-top: 1px; border-radius: var(--radius-sm);
  border: 1px solid var(--border); background: none; color: var(--text-tertiary); cursor: pointer;
}
.status-copy-btn:hover { color: var(--accent); border-color: var(--accent-ring); background: var(--accent-wash); }
.status-line:has(.model-status.is-error:not(:empty)) .status-copy-btn { display: inline-flex; }

.price-row { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-3); }
.price-row label { flex: 1; min-width: 160px; }
@media (max-width: 480px) {
  .price-row { flex-direction: column; }
}

.guide {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0;
  margin: -4px 0 var(--space-4);
  font-size: var(--text-xs);
  color: var(--text-secondary);
  overflow: hidden;
}
.guide > summary {
  cursor: pointer; color: var(--accent); font-weight: 600; list-style: none;
  display: flex; align-items: center; gap: 10px;
  min-height: 52px;
  padding: 0 var(--space-4);
  margin: 0 !important;
}
.guide summary::-webkit-details-marker { display: none; }
.guide-q {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.guide-title { flex: 1; min-width: 0; text-align: left; }
.guide[open] > summary > .accordion-chevron { transform: rotate(180deg); }
.card-title { display: flex; align-items: center; gap: var(--space-3); min-width: 0; flex: 1; }
.card-title h2, .card-title h3 {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.card-icon {
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 34px; height: 34px; border-radius: var(--radius-sm);
  background: var(--accent-wash); color: var(--accent);
}
.card-icon svg { width: 18px; height: 18px; }
.guide summary::before {
  content: "?";
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 22px; height: 22px; border-radius: 50%;
  background: linear-gradient(135deg, var(--accent), var(--accent-hover));
  color: var(--accent-ink); font-family: 'Outfit', sans-serif; font-weight: 800; font-size: 13px;
  box-shadow: 0 3px 10px -3px var(--accent-ring);
}
.guide[open] > summary { border-bottom: 1px solid var(--border); }
.guide > form { padding: var(--space-3); }

/* Numbered setup instructions use compact zebra rows instead of large uninterrupted prose.
   The explicit number column keeps multi-line steps aligned and easy to scan. */
.settings-wrap .accordion-body > ol,
.settings-wrap .guide > ol {
  counter-reset: settings-step;
  list-style: none;
  margin: 0;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--surface-1);
}
.settings-wrap .guide > ol {
  margin: var(--space-3);
  border-color: var(--border-strong);
}
.settings-wrap .accordion-body > ol > li,
.settings-wrap .guide > ol > li {
  counter-increment: settings-step;
  position: relative;
  display: block;
  min-width: 0;
  min-height: 38px;
  padding: 9px 11px 9px 50px;
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--text-secondary);
  overflow-wrap: anywhere;
  word-break: normal;
}
.settings-wrap .accordion-body > ol > li:nth-child(odd),
.settings-wrap .guide > ol > li:nth-child(odd) { background: var(--surface-2); }
.settings-wrap .accordion-body > ol > li:nth-child(even),
.settings-wrap .guide > ol > li:nth-child(even) { background: var(--surface-3); }
.settings-wrap .accordion-body > ol > li + li,
.settings-wrap .guide > ol > li + li { border-top: 1px solid var(--border); }
.settings-wrap .accordion-body > ol > li::before,
.settings-wrap .guide > ol > li::before {
  content: counter(settings-step, decimal-leading-zero);
  position: absolute;
  top: 9px;
  left: 11px;
  width: 26px;
  color: var(--accent);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  font-weight: 700;
  line-height: 1.65;
  font-variant-numeric: tabular-nums;
}

.qr-box {
  display: flex;
  justify-content: center;
  padding: var(--space-4);
  background: white;
  border-radius: var(--radius-lg);
  width: fit-content;
  margin: 0 auto var(--space-4);
}

.totp-setup-flow { display: flex; flex-direction: column; gap: var(--space-4); }
.totp-setup-flow .hint { margin: 0; line-height: 1.6; }
.manual-key-block { display: flex; flex-direction: column; gap: var(--space-2); }

.key-copy-field {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 40px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0 38px 0 12px;
}
#manual-key {
  flex: 1;
  min-width: 0;
  font-size: 0.7rem;
  letter-spacing: 0.02em;
  white-space: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
}
#manual-key::-webkit-scrollbar { display: none; }
.key-copy-btn {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  color: var(--text-tertiary);
  cursor: pointer;
  padding: 8px;
  display: flex;
  border-radius: var(--radius-sm);
}
.key-copy-btn:hover { color: var(--accent); }

/* A copy-able multi-line textarea (setup prompt, Code.gs) - button lives in its own toolbar row
   above the text instead of absolutely-positioned over it, so a tall/resized textarea can never
   visually collide with whatever comes after it in the page. */
.copy-box { display: flex; flex-direction: column; gap: 8px; }
.copy-box-toolbar { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.copy-box-label { font-size: var(--text-xs); font-weight: 600; color: var(--text-secondary); }
.copy-box-btn { font-size: var(--text-xs); padding: 7px 12px; min-height: 32px; }
.copy-box-textarea {
  width: 100%;
  font-size: var(--text-xs);
  resize: vertical;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  padding: 12px;
  min-height: 160px;
}
.copy-box-textarea-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

.error-message-box {
  position: relative;
  width: 100%;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--space-3) 44px var(--space-3) var(--space-4);
}
.error-message-box #error-message {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--text-secondary);
  line-height: 1.6;
  word-break: break-word;
}
.error-message-box .key-copy-btn { top: var(--space-3); transform: none; }

/* ---------- Reorderable / expandable configuration lists ---------- */

.sort-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  min-height: 48px;
}
/* Each document type is one of these - icon/name/hint/fields all live inside it, collapsed to
   just the summary row (icon, name, delete, drag handle) until tapped open. */
.sort-item {
  border-radius: var(--radius-sm);
  background: var(--surface-3);
  border: 1px solid var(--border);
  touch-action: none;
  will-change: transform;
  overflow: hidden;
  /* Settles into its new slot with a soft decelerate - the "other rows sliding out of the way"
     half of the physical feel. The dragged row overrides this to 0s so it tracks the finger
     with zero lag instead of chasing it. */
  transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1);
}
.sort-item.is-dragging {
  transition: none;
  transform-origin: center;
  box-shadow: 0 14px 28px -8px rgba(0, 0, 0, 0.5), var(--shadow-accent);
  border-color: var(--accent);
  background: var(--surface-2);
  position: relative;
  z-index: 2;
  scale: 1.03;
  cursor: grabbing;
}
.sort-item-summary {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 10px;
}
.drag-handle {
  background: none;
  border: none;
  color: var(--text-tertiary);
  cursor: grab;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px;
  min-width: 32px;
  min-height: 32px;
  flex-shrink: 0;
  touch-action: none;
}
.drag-handle:active { cursor: grabbing; }
.sort-item-name-btn {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 6px 4px;
  text-align: left;
  border-radius: var(--radius-sm);
}
.sort-item-name-btn:hover { background: rgba(255, 255, 255, 0.04); }
.sort-item-name { flex: 1; min-width: 0; font-size: var(--text-sm); font-weight: 600; color: var(--text); overflow-wrap: break-word; }
.sort-item-name-btn .accordion-chevron { flex-shrink: 0; }
.sort-item-name-btn.is-open .accordion-chevron { transform: rotate(180deg); }
.sort-item-delete {
  background: none;
  border: none;
  color: var(--text-tertiary);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px;
  border-radius: 50%;
  min-width: 32px;
  min-height: 32px;
  flex-shrink: 0;
}
.sort-item-delete:hover { color: var(--danger); background: var(--danger-wash); }
/* Animated expand/collapse via max-height (an inert, non-animatable `hidden` attribute swap read
   as "the accordion doesn't do anything"). The grid-template-rows 0fr->1fr trick was tried first
   but left a visible sliver of every collapsed row's content peeking through in practice - min-height:0
   didn't fully collapse the row track in this nested grid/flex layout. max-height is the more
   battle-tested technique: true 0 while collapsed since overflow:hidden lives on this element
   itself, not a row track that can silently refuse to shrink. The fixed cap is generous enough for
   this section's content (name/hint/fields/field-builder) to never actually get clipped. */
.sort-item-body {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s var(--ease-out);
}
.sort-item.is-expanded .sort-item-body { max-height: 700px; }
.sort-item-body-inner {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-3) var(--space-3);
  border-top: 1px solid var(--border);
}
.sort-item-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: var(--text-xs);
  color: var(--text-secondary);
  font-weight: 500;
}
/* Overrides the generic .settings-form textarea's 120px min-height - this one just needs to hold
   a short comma-separated list (2 rows), a 120px box would look oversized for that. Wrapping
   instead of a single horizontally-scrolling line is the actual point of it being a textarea. */
.chip-add-row { display: flex; gap: var(--space-2); margin-top: var(--space-3); }
.chip-add-row input { flex: 1; min-width: 0; }
.chip-add-row button { white-space: nowrap; flex-shrink: 0; }

/* ---------- Person rows (staff, employees, devices) ---------- */

.user-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-3) 0; border-bottom: 1px solid var(--border); }
.user-row:last-child { border-bottom: none; }
.user-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 200px; }
.user-name { font-weight: 600; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.user-sub { font-size: var(--text-xs); color: var(--text-tertiary); overflow-wrap: break-word; }
.user-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.user-actions button { font-size: var(--text-xs); padding: 8px 12px; min-height: 36px; border-radius: var(--radius-sm); white-space: nowrap; }
.badge { font-size: 11px; font-weight: 600; padding: 3px 9px; border-radius: var(--radius-full); background: var(--accent-wash); color: var(--accent); }

/* ---------- Repeatable rows (add / remove a row at a time) ---------- */

#recipients-list { display: flex; flex-direction: column; gap: var(--space-3); margin-bottom: var(--space-3); }
.repeat-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.repeat-row-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); align-items: center; }
@media (max-width: 480px) {
  .repeat-row-grid { grid-template-columns: 1fr; }
}
.checkbox-inline { display: flex; align-items: center; gap: 8px; font-size: var(--text-sm); color: var(--text-secondary); font-weight: 500; cursor: pointer; }
.checkbox-inline input { width: 16px; height: 16px; accent-color: var(--accent); flex-shrink: 0; }
/* .settings-form label / .settings-wrap label (above) sets flex-direction:column at higher
   specificity (class+type beats a single class), which stacked every checkbox above its own
   label text instead of beside it. Re-assert row layout at matching specificity so it wins. */
.settings-form label.checkbox-inline,
.settings-wrap label.checkbox-inline {
  flex-direction: row;
  align-items: center;
  margin-bottom: 0;
}
.repeat-row-test {
  font-size: var(--text-xs);
  padding: 8px 12px;
  min-height: 36px;
}
.repeat-row-remove {
  background: none;
  border: 1px solid var(--border);
  color: var(--text-tertiary);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px;
  border-radius: var(--radius-sm);
  min-height: 36px;
}
.repeat-row-remove:hover { color: var(--danger); background: var(--danger-wash); border-color: var(--danger); }
.repeat-row-status { margin: 0; }
.checkbox-group { display: flex; flex-direction: column; gap: 8px; }
.checkbox-list {
  display: flex; flex-direction: column; gap: 10px;
  padding: var(--space-3); width: 100%;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-3);
}
.checkbox-list .checkbox-inline { align-items: flex-start; width: 100%; }
.checkbox-list .checkbox-inline input { margin-top: 2px; flex-shrink: 0; }
.checkbox-list .checkbox-inline { font-size: var(--text-xs); font-weight: 400; }

/* =====================================================================
   POLKA COMPONENTS
   Everything above is the shared design system - the same 480/560px
   columns, the same 48px controls, the same card, accordion, drawer and
   sticky-save-bar behaviour. Everything below is what Polka adds on top:
   the operational screens (live board, lunch, kitchen) and the small
   pieces they need. Nothing here introduces a new radius, spacing step,
   font or timing - it all reads from the tokens at the top of the file.
   ===================================================================== */

/* ---------- Page column ---------------------------------------------
   Config pages keep the 560px column. Operational screens that show two
   things side by side (the request board, reports) may widen to 880px on
   a desktop, and collapse back to the same single column on a phone. */
.settings-wrap.is-wide { max-width: 880px; }

.page-sub {
  margin: calc(-1 * var(--space-4)) 0 var(--space-5);
  color: var(--text-tertiary);
  font-size: var(--text-sm);
}
.topbar-actions { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.topbar-actions .btn-primary,
.topbar-actions .btn-secondary { flex: 0 0 auto; min-height: 38px; padding: 9px 14px; font-size: var(--text-sm); }

/* ---------- Status chips --------------------------------------------
   The only place small semantic colour is used. One shape, six meanings. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex-shrink: 0;
  padding: 3px 9px;
  border-radius: var(--radius-full);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.02em;
  white-space: nowrap;
  background: var(--muted-wash);
  color: var(--text-secondary);
}
.chip::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}
.chip-plain::before { display: none; }
.chip-ok      { background: var(--success-wash); color: var(--success); }
.chip-warn    { background: var(--warn-wash);    color: var(--warn); }
.chip-accent  { background: var(--accent-wash);  color: var(--accent); }
.chip-info    { background: var(--info-wash);    color: var(--info); }
.chip-danger  { background: var(--danger-wash);  color: var(--danger); }
.chip-muted   { background: var(--muted-wash);   color: var(--text-tertiary); }

/* ---------- "What is happening right now" panel (dashboard) ----------
   One panel of labelled rows rather than a dozen equal boxes, so the eye
   reads it top to bottom instead of hunting across a grid. */
.today-panel {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface-1);
  overflow: hidden;
  margin-bottom: var(--space-4);
}
.today-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4);
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.today-head h2 { margin: 0; font-size: var(--text-lg); font-weight: 700; }
.today-date { color: var(--text-tertiary); font-size: var(--text-xs); }
.today-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  min-height: 52px;
  padding: 10px var(--space-4);
  border-bottom: 1px solid var(--border);
}
.today-row:last-child { border-bottom: none; }
.today-row-label { color: var(--text-secondary); font-size: var(--text-sm); font-weight: 500; }
.today-row-value {
  display: flex; align-items: center; gap: var(--space-2);
  color: var(--text);
  font-size: var(--text-base);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: right;
  min-width: 0;
}
.today-row-value .chip { font-weight: 700; }
.today-row a.today-row-value:hover { color: var(--accent); }
/* The one number that deserves to be big: whatever needs attention now. */
.today-row-hero .today-row-value { font-size: var(--text-2xl); font-family: 'Outfit', sans-serif; }

/* ---------- Live request board --------------------------------------
   Grouped sections rather than side-by-side kanban columns: at 560px on a
   phone a four-column board is unreadable, and grouping keeps the same
   "what needs me / what is moving / what is finished" reading order. */
.board-groups { display: flex; flex-direction: column; gap: var(--space-4); }
@media (min-width: 760px) {
  .board-groups { display: grid; grid-template-columns: 1fr 1fr; align-items: start; gap: var(--space-4); }
}
.board-group {
  border: 1px solid var(--border);
  border-left: 2px solid var(--section-tone, var(--border-strong));
  border-radius: var(--radius-sm);
  background: var(--surface-1);
  overflow: hidden;
}
.board-group-new         { --section-tone: var(--warn); }
.board-group-accepted    { --section-tone: var(--info); }
.board-group-in_progress { --section-tone: var(--accent); }
.board-group-completed   { --section-tone: var(--success); }
.board-group-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: 11px 13px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.board-group-head h3 {
  margin: 0;
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.pill-count {
  min-width: 24px;
  padding: 2px 8px;
  border-radius: var(--radius-full);
  background: var(--surface-3);
  color: var(--text);
  font-size: var(--text-xs);
  font-weight: 700;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.board-group-body { display: flex; flex-direction: column; }

.req-card {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: var(--space-3);
  border-bottom: 1px solid var(--border);
  transition: background 0.15s var(--ease-out);
}
.req-card:last-child { border-bottom: none; }
.req-card:hover { background: var(--surface-2); }
.req-card-top { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.req-card-icon { font-size: 1.15rem; line-height: 1; flex-shrink: 0; }
.req-card-title {
  flex: 1; min-width: 0;
  font-size: var(--text-sm);
  font-weight: 700;
  color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.req-card-id { color: var(--text-tertiary); font-size: 11px; font-variant-numeric: tabular-nums; flex-shrink: 0; }
.req-card-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 5px 10px;
  color: var(--text-secondary);
  font-size: var(--text-xs);
  min-width: 0;
}
.req-card-meta span { display: inline-flex; align-items: center; gap: 4px; min-width: 0; }
.req-card-meta .dot { color: var(--text-tertiary); }
.req-card-foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.req-clock { font-variant-numeric: tabular-nums; font-weight: 700; font-size: var(--text-xs); color: var(--text-tertiary); }
/* Past its SLA: the card itself flags, not just a chip, so a long queue is
   scannable at arm's length without reading any of the text. */
.req-card.is-breached { background: var(--danger-wash); }
.req-card.is-breached .req-clock { color: var(--danger); }
.req-card.is-urgent .req-card-title::after {
  content: "URGENT";
  margin-left: 7px;
  padding: 1px 6px;
  border-radius: var(--radius-full);
  background: var(--danger-wash);
  color: var(--danger);
  font-size: 10px;
  letter-spacing: 0.04em;
}
.req-actions { display: flex; gap: 6px; flex-wrap: wrap; }
.req-actions .btn-mini { flex: 0 0 auto; }

/* Small button used inside dense rows - same shape family, smaller frame. */
.btn-mini {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 32px;
  padding: 6px 11px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-secondary);
  font-family: inherit;
  font-size: var(--text-xs);
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: color 0.15s var(--ease-out), border-color 0.15s var(--ease-out), background 0.15s var(--ease-out);
}
.btn-mini:hover { color: var(--accent); border-color: var(--accent); }
.btn-mini:active { transform: scale(0.97); }
.btn-mini:disabled { opacity: 0.5; cursor: default; }
.btn-mini-accent { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn-mini-accent:hover { background: var(--accent-hover); border-color: var(--accent-hover); color: var(--accent-ink); }
.btn-mini-danger:hover { color: var(--danger); border-color: var(--danger); background: var(--danger-wash); }

/* ---------- Empty states --------------------------------------------
   Never a blank table: say what is true and what happens next. */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: var(--space-5) var(--space-4);
  text-align: center;
}
.empty-state svg { color: var(--text-tertiary); opacity: 0.6; margin-bottom: var(--space-1); }
.empty-state strong { font-family: 'Outfit', sans-serif; font-size: var(--text-base); color: var(--text); }
.empty-state span { font-size: var(--text-xs); color: var(--text-tertiary); line-height: 1.6; max-width: 42ch; }

/* ---------- Data rows ------------------------------------------------
   A list row on a desktop, a card on a phone - never a table that has to
   be scrolled sideways. Built on the same .user-row frame as the device
   and account lists so every list in the app matches. */
.data-list { display: flex; flex-direction: column; }
.data-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--border);
  min-width: 0;
}
.data-row:last-child { border-bottom: none; }
.data-row-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.data-row-title {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: var(--text-sm); font-weight: 600; color: var(--text);
}
.data-row-sub { font-size: var(--text-xs); color: var(--text-tertiary); overflow-wrap: anywhere; line-height: 1.5; }
.data-row-actions { display: flex; align-items: center; gap: 6px; flex-shrink: 0; flex-wrap: wrap; }
.data-row-value { font-variant-numeric: tabular-nums; font-weight: 700; font-size: var(--text-sm); flex-shrink: 0; }
@media (max-width: 520px) {
  .data-row {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-2);
    padding: var(--space-3);
    margin-bottom: var(--space-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
  }
  .data-row:last-child { border-bottom: 1px solid var(--border); }
  .data-row-actions { justify-content: flex-start; }
}

/* ---------- Toggle switch -------------------------------------------- */
.switch { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; font-size: var(--text-sm); color: var(--text-secondary); }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch-track {
  position: relative;
  width: 44px; height: 26px;
  flex-shrink: 0;
  border-radius: var(--radius-full);
  background: var(--surface-3);
  border: 1px solid var(--border);
  transition: background 0.18s var(--ease-out), border-color 0.18s var(--ease-out);
}
.switch-track::after {
  content: "";
  position: absolute;
  top: 2px; left: 2px;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--text-secondary);
  transition: transform 0.18s var(--ease-out), background 0.18s var(--ease-out);
}
.switch input:checked + .switch-track { background: var(--accent); border-color: var(--accent); }
.switch input:checked + .switch-track::after { transform: translateX(18px); background: var(--accent-ink); }
.switch input:focus-visible + .switch-track { box-shadow: 0 0 0 4px var(--accent-ring); }

/* ---------- Toasts ---------------------------------------------------- */
.toast-stack {
  position: fixed;
  left: 50%;
  bottom: calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: min(92vw, 420px);
  pointer-events: none;
}
.toast {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 15px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong);
  background: var(--surface-3);
  color: var(--text);
  font-size: var(--text-sm);
  font-weight: 500;
  box-shadow: var(--shadow-md);
  animation: toast-in 0.22s var(--ease-out);
}
.toast-ok    { border-color: var(--success); }
.toast-error { border-color: var(--danger); }
.toast svg { flex-shrink: 0; }
.toast.is-leaving { opacity: 0; transform: translateY(8px); transition: opacity 0.2s, transform 0.2s; }
@keyframes toast-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .toast { animation: none; } }

/* ---------- Lunch: dish options and voting ---------------------------- */
.dish-list { display: flex; flex-direction: column; gap: var(--space-3); }
.dish-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface-2);
  overflow: hidden;
  transition: border-color 0.18s var(--ease-out);
}
.dish-card.is-winner { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
.dish-photo { width: 100%; height: 148px; object-fit: cover; display: block; background: var(--surface-3); }
.dish-body { display: flex; flex-direction: column; gap: 8px; padding: var(--space-3); }
.dish-title {
  display: flex; align-items: baseline; gap: 8px;
  margin: 0;
  font-family: 'Outfit', 'Inter', sans-serif;
  font-size: var(--text-base);
  font-weight: 700;
  color: var(--text);
}
.dish-title .dish-pos { color: var(--accent); font-variant-numeric: tabular-nums; flex-shrink: 0; }
.dish-desc { font-size: var(--text-xs); color: var(--text-secondary); line-height: 1.6; margin: 0; }
.dish-facts { display: flex; flex-wrap: wrap; gap: 5px 8px; }
.dish-why {
  margin: 0;
  padding: 8px 10px;
  border-left: 2px solid var(--accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: var(--accent-wash);
  font-size: var(--text-xs);
  color: var(--text-secondary);
  line-height: 1.55;
}
.vote-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: var(--text-xs);
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
.vote-bar-track {
  flex: 1;
  height: 8px;
  border-radius: var(--radius-full);
  background: var(--surface-3);
  overflow: hidden;
}
.vote-bar-fill {
  display: block;
  height: 100%;
  border-radius: var(--radius-full);
  background: var(--accent);
  transition: width 0.4s var(--ease-out);
}
.dish-card.is-winner .vote-bar-fill { background: var(--success); }

/* ---------- Kitchen recipe mode ---------------------------------------
   Full-attention screen: one stage at a time, big numbers, thumb-sized
   Done button. Read at arm's length next to a hot pan, not held. */
.recipe-shell {
  max-width: 520px;
  margin: 0 auto;
  padding: var(--space-4) var(--space-4) calc(var(--space-6) + 90px);
}
.recipe-topline {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  margin-bottom: var(--space-3);
}
.recipe-dish { font-family: 'Outfit', sans-serif; font-size: var(--text-lg); font-weight: 700; margin: 0; min-width: 0; }
.recipe-progress {
  height: 6px;
  border-radius: var(--radius-full);
  background: var(--surface-3);
  overflow: hidden;
  margin-bottom: var(--space-4);
}
.recipe-progress-fill { display: block; height: 100%; background: var(--accent); transition: width 0.3s var(--ease-out); }
.rstep {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface-1);
  padding: var(--space-5) var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.rstep-counter {
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
}
.rstep-title { margin: 0; font-size: var(--text-2xl); font-weight: 700; line-height: 1.2; }
.rstep-lines { display: flex; flex-direction: column; gap: 0; border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; }
.rstep-line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 11px 13px;
  border-bottom: 1px solid var(--border);
  font-size: var(--text-base);
}
.rstep-line:last-child { border-bottom: none; }
.rstep-line:nth-child(odd) { background: var(--surface-2); }
.rstep-line-label { color: var(--text-secondary); font-size: var(--text-sm); font-weight: 600; flex-shrink: 0; }
.rstep-line-value { color: var(--text); font-weight: 700; text-align: right; font-variant-numeric: tabular-nums; }
.rstep-cue {
  margin: 0;
  font-size: var(--text-sm);
  line-height: 1.6;
  color: var(--text-secondary);
}
.rstep-done-list { display: flex; flex-wrap: wrap; gap: 6px; }
.rstep-dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--surface-3);
  border: 1px solid var(--border);
}
.rstep-dot.is-done { background: var(--success); border-color: var(--success); }
.rstep-dot.is-current { background: var(--accent); border-color: var(--accent); }

.timer {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-left: 2px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.timer-display {
  font-family: 'Outfit', ui-monospace, monospace;
  font-size: var(--text-2xl);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  min-width: 92px;
}
.timer.is-done .timer-display { color: var(--success); }
.timer.is-running .timer-display { color: var(--accent); }
.timer-label { flex: 1; min-width: 0; font-size: var(--text-sm); color: var(--text-secondary); }

/* Language switcher reuses the segmented control shape. */
.lang-switch { display: inline-flex; gap: 4px; }
.lang-switch a {
  min-height: 34px;
  padding: 6px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-secondary);
  font-size: var(--text-xs);
  font-weight: 700;
  display: inline-flex;
  align-items: center;
}
.lang-switch a.is-active { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }

/* ---------- Shopping list --------------------------------------------- */
.shop-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 48px;
  padding: 9px var(--space-3);
  border-bottom: 1px solid var(--border);
}
.shop-item:last-child { border-bottom: none; }
.shop-item.is-bought { opacity: 0.5; }
.shop-item.is-bought .shop-item-name { text-decoration: line-through; }
.shop-item-name { flex: 1; min-width: 0; font-size: var(--text-sm); font-weight: 600; color: var(--text); }
.shop-item-qty { font-variant-numeric: tabular-nums; font-weight: 700; font-size: var(--text-sm); color: var(--accent); flex-shrink: 0; }
.shop-item-sub { display: block; font-size: 11px; font-weight: 400; color: var(--text-tertiary); }
.shop-total {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--space-3);
  border-top: 1px solid var(--border-strong);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* ---------- Reports: bars and metrics ---------------------------------
   A bar per row, drawn in CSS. No chart library, nothing to load, and it
   stays readable at 320px where a canvas chart would not. */
.metric-list { display: flex; flex-direction: column; gap: 11px; }
.metric {
  display: grid;
  grid-template-columns: minmax(84px, 34%) 1fr auto;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--text-xs);
}
.metric-label { color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.metric-track { height: 10px; border-radius: var(--radius-full); background: var(--surface-3); overflow: hidden; }
.metric-fill { display: block; height: 100%; border-radius: var(--radius-full); background: var(--accent); }
.metric-fill.is-alt { background: var(--success); }
.metric-value { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--text); }

.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: var(--space-3); }
.kpi {
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.kpi-value { font-family: 'Outfit', sans-serif; font-size: var(--text-2xl); font-weight: 700; font-variant-numeric: tabular-nums; }
.kpi-label { font-size: var(--text-xs); color: var(--text-tertiary); margin-top: 2px; }

/* ---------- Weekday grid (office hours, shifts, item schedules) -------- */
.weekday-row {
  display: grid;
  grid-template-columns: 92px auto 1fr 1fr;
  align-items: center;
  gap: var(--space-2);
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
}
.weekday-row:last-child { border-bottom: none; }
.weekday-row > label { margin-bottom: 0 !important; }
.weekday-name { font-size: var(--text-sm); font-weight: 600; color: var(--text); }
.weekday-row input[type="time"] { padding: 8px 10px !important; font-size: var(--text-sm) !important; }
.weekday-row.is-closed input[type="time"] { opacity: 0.35; pointer-events: none; }
@media (max-width: 560px) {
  .weekday-row { grid-template-columns: 1fr auto; grid-template-areas: "name toggle" "from to"; row-gap: 8px; }
  .weekday-name { grid-area: name; }
  .weekday-row .switch { grid-area: toggle; justify-self: end; }
  .weekday-row .time-from { grid-area: from; }
  .weekday-row .time-to { grid-area: to; }
}

/* ---------- Two-up form fields on wider screens ------------------------ */
.field-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 var(--space-3); }
.field-grid > label { min-width: 0; }
.field-grid-full { grid-column: 1 / -1; }
@media (max-width: 560px) { .field-grid { grid-template-columns: 1fr; } }

/* ---------- Bottom navigation (phones only) ---------------------------
   The drawer is still the full menu, exactly as everywhere else in the
   app. This is a shortcut bar for the four screens an operator opens
   twenty times a day, put where a thumb already is. */
.bottom-nav { display: none; }
@media (max-width: 720px) {
  .bottom-nav {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 35;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    background: var(--surface-1);
    background: color-mix(in srgb, var(--surface-1) 94%, transparent);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-top: 1px solid var(--border);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  .bottom-nav a {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    min-height: 56px;
    color: var(--text-tertiary);
    font-size: 10px;
    font-weight: 600;
  }
  .bottom-nav a.is-active { color: var(--accent); }
  .bottom-nav a svg { width: 20px; height: 20px; }
  /* Keep every other fixed element clear of the nav bar. Without this the
     kitchen screen's Done button - the one control that screen exists for -
     ends up underneath it. */
  .global-save-bar { bottom: calc(56px + env(safe-area-inset-bottom, 0px)); }
  .button-row { bottom: calc(56px + env(safe-area-inset-bottom, 0px)); }
  .toast-stack { bottom: calc(124px + env(safe-area-inset-bottom, 0px)); }
  body.app-shell .settings-wrap { padding-bottom: calc(var(--space-6) + 76px + 56px); }
  body.app-shell .recipe-shell { padding-bottom: calc(var(--space-6) + 90px + 56px); }
}

/* ---------- Drawer nav grouping ---------------------------------------
   Fourteen destinations in one flat list is a wall. Same drawer, same item
   shape - just a quiet label every few items so the eye can jump. */
.app-menu-group-label {
  padding: 9px 12px 5px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  background: var(--surface-3);
  border-bottom: 1px solid var(--border);
}
.app-menu-item.is-active { color: var(--accent); background: var(--accent-wash); }
.app-menu-item-icon { display: inline-flex; align-items: center; gap: 10px; min-width: 0; flex: 1; }
.app-menu-item-icon svg { width: 17px; height: 17px; flex-shrink: 0; opacity: 0.75; }

/* ---------- Misc ------------------------------------------------------- */
.inline-note {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border-left: 2px solid var(--accent);
  font-size: var(--text-xs);
  color: var(--text-secondary);
  line-height: 1.6;
}
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--text-xs); }
.text-right { text-align: right; }
.muted { color: var(--text-tertiary); }
.stack { display: flex; flex-direction: column; gap: var(--space-3); }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap; }
.divider { height: 1px; background: var(--border); border: none; margin: var(--space-3) 0; }
.pulse-live {
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--success);
  animation: live-pulse 2s ease-in-out infinite;
}
@keyframes live-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }
@media (prefers-reduced-motion: reduce) { .pulse-live { animation: none; } }

/* Inline control labels inside a settings column.
   .settings-wrap label lays every label out as a stacked "caption above
   field" pair, which is right for inputs and wrong for a control that sits
   beside its own text. These two put the row back, with enough specificity
   to win against that rule rather than resorting to !important. */
.settings-wrap label.switch,
.settings-form label.switch,
.recipe-shell label.switch {
  flex-direction: row;
  align-items: center;
  gap: 10px;
  margin-bottom: var(--space-3);
}
.settings-wrap label.checkbox-inline,
.settings-form label.checkbox-inline {
  flex-direction: row;
  align-items: center;
  gap: 8px;
  margin-bottom: 0;
}
.settings-wrap label.checkbox-inline input[type="checkbox"],
.settings-form label.checkbox-inline input[type="checkbox"] {
  width: 17px;
  height: 17px;
  min-width: 17px;
  flex-shrink: 0;
  accent-color: var(--accent);
}
/* A switch inside a weekday row is a bare control with no text of its own. */
.weekday-row label.switch { margin-bottom: 0; }

/* =====================================================================
   DESKTOP LAYOUT

   Below 1080px the panel is exactly what it has always been: a single
   centred column with a sliding drawer, which is the right shape for a
   phone and for the operator checking the board one-handed.

   Above it, that column was leaving most of a desktop screen empty. So the
   same drawer docks open as a permanent sidebar - identical markup,
   identical item styling, it simply stops sliding - and the content column
   widens to match. No JavaScript changes: the drawer's `hidden` attribute
   is overridden here, and the toggle it belongs to is hidden instead.
   ===================================================================== */

@media (min-width: 1080px) {
  /* .app-shell only, never the auth pages: sign-in, setup, password reset
     and the installer have no sidebar in the DOM, so padding the body would
     just shove their centred card off to the right. */
  body.app-shell { padding-left: var(--sidebar-width); }

  /* The sidebar carries the brand and the whole menu, so the mobile top bar
     would only be repeating itself. Each page's own .topbar keeps the title. */
  .app-shell .app-header { display: none; }

  .app-shell .app-menu,
  .app-shell .app-menu[hidden] {
    display: flex;
    transform: none;
    width: var(--sidebar-width);
    border-right: 1px solid var(--border);
    background: var(--surface-1);
    padding-bottom: var(--space-4);
  }
  .app-shell .app-menu-overlay,
  .app-shell .app-menu-overlay[hidden] { display: none; }
  .app-shell .app-menu-close { display: none; }
  .app-menu-top { padding: var(--space-4) var(--space-4) var(--space-3); }
  .app-menu-list { margin-left: var(--space-3); margin-right: var(--space-3); }

  /* Fixed bars start where the content does, not under the sidebar. */
  .app-shell .global-save-bar,
  .app-shell .button-row { left: var(--sidebar-width); }
  .app-shell .toast-stack { left: calc(50% + (var(--sidebar-width) / 2)); }

  /* Room to breathe now that there is room to have. */
  .settings-wrap {
    max-width: 680px;
    padding-top: var(--space-6);
    padding-bottom: calc(var(--space-6) + 76px);
  }
  .settings-wrap.is-wide { max-width: 1040px; }
  .app-footer { max-width: 680px; }
}

/* An operational screen at full desktop width can carry three board columns
   instead of two, which is what stops "Done today" being a lonely strip at
   the bottom of a very tall page. */
@media (min-width: 1360px) {
  .settings-wrap.is-wide { max-width: 1240px; }
  .board-groups { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Between phone and desktop the drawer is still a drawer, but the column
   should not stay pinned at phone width on a tablet or a small laptop. */
@media (min-width: 720px) and (max-width: 1079px) {
  .settings-wrap { max-width: 640px; }
  .app-footer { max-width: 640px; }
  .app-header-inner { max-width: 640px; }
}

/* ---------- Spacing corrections -------------------------------------
   Things that read as cramped, or as adrift, once there is more width. */

/* A page title sitting directly on top of its first card had no more
   breathing room than two cards have between them. */
.settings-wrap > .topbar { margin-bottom: var(--space-4); }
.settings-wrap > .topbar + .page-sub { margin-top: 0; }
.page-sub { margin: 0 0 var(--space-4); }

/* Card bodies at desktop width: the 34px pad is right for a 560px column
   and mean for a 680px one. */
@media (min-width: 1080px) {
  .card { --card-pad: var(--space-5); }
  .card.accordion-item > .accordion-body { padding-bottom: var(--space-1); }
  .today-row { padding-left: var(--space-5); padding-right: var(--space-5); }
  .today-head { padding-left: var(--space-5); padding-right: var(--space-5); }
}

/* The last card on a page had nothing under it but the save bar. */
.settings-wrap > .card:last-of-type,
.settings-wrap > details.card:last-of-type { margin-bottom: var(--space-5); }

/* Grouped board sections were touching on wide screens because the grid gap
   only applied between rows on a single column. */
.board-groups { align-content: start; }
.board-group + .board-group { margin-top: 0; }

/* Action rows inside a card need the same rhythm as the fields above them. */
.card-body-pad > .data-list:first-child { margin-top: calc(-1 * var(--space-2)); }
.topbar-actions { margin-left: auto; }

/* ---------- Installer: choosing a set of credentials -------------------
   The discovered sets are the whole point of scanning the account, so they
   have to read as buttons and not as summary cards. A left-aligned two-line
   label with a chevron on the right does that; the first one takes the
   accent fill because it is the intended happy path. */
.cred-choice {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  height: auto;
  min-height: 58px;
  padding: 12px 15px;
  text-align: left;
  white-space: normal;
}
.cred-choice-copy {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  text-align: left;
}
.cred-choice-copy strong {
  font-size: var(--text-sm);
  font-weight: 700;
  overflow-wrap: anywhere;
  line-height: 1.35;
}
.cred-choice-copy small { font-size: var(--text-xs); opacity: 0.72; font-weight: 500; }
.cred-choice-go { flex-shrink: 0; opacity: 0.7; }
.cred-choice:hover .cred-choice-go { opacity: 1; }

/* "or paste them yourself" as a rule with the label sitting in it. */
.or-divider {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: 0 0 var(--space-4);
  color: var(--text-tertiary);
  font-size: var(--text-xs);
  font-weight: 600;
}
.or-divider::before,
.or-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}

.install-heading {
  font-family: 'Outfit', 'Inter', sans-serif;
  font-size: var(--text-base);
  font-weight: 700;
  color: var(--text);
  margin: 0 0 var(--space-2);
}

/* The paste box keeps its label for screen readers once the heading above
   has already said what this section is. */
.auth-form label.sr-label { gap: 0; font-size: 0; color: transparent; }
.auth-form label.sr-label textarea { font-size: var(--text-sm); color: var(--text); }
