    :root {
      --bg: #EDF3FF;
      --bg2: #DCE9FF;
      --card: #FFFFFF;
      --ink: #1F2A44;
      --ink-soft: #3B476A; 
      --sun: #FFC93C;
      /* Text-safe version of --sun. --sun itself (#FFC93C) is ~1.5:1 against
         white/card surfaces — fine as a border or a tinted background, but a
         WCAG AA failure as a foreground text colour. Any place --sun was
         being used to colour TEXT should use --sun-ink instead; --sun stays
         exactly as-is for borders, fills, and backgrounds, which is most of
         its uses and where contrast rules don't apply.
         TO REVERT: delete this line and body.theme-night's --sun-ink
         override below, then find/replace every `color: var(--sun-ink)`
         back to `color: var(--sun)` in enhancements.css. */
      --sun-ink: #8A6100;
      --berry: #D81B60; 
      --mint: #00897B;  
      --grape: #7E57C2; 
      --sky: #1565C0;   
      --mascot: var(--mint);
      --shadow: rgba(31,42,68,0.14);
      --radius-lg: 28px;
      --radius-md: 18px;
      --font-scale: 1;
      /* Action green: the hero colour for the core "add food" flow.
         Hardcoded (not theme-overridden) so white text stays legible in every theme.
         Was #0E8C7A, which measured 4.16:1 against white text — a WCAG AA
         fail (needs 4.5:1) on the app's primary CTA colour. Darkened to
         #0B7A6A (5.24:1), a change small enough to be visually
         imperceptible at the sizes this token is used at.
         TO REVERT: change back to #0E8C7A. */
      --sprout-green: #0B7A6A;
      --sprout-green-deep: #00594E;
      --sprout-green-tint: rgba(14,140,122,0.12);
      /* Drinks Station v2 surfaces. The approved mockup hardcoded
         rgba(255,255,255,.04) / rgba(0,0,0,.28), which only reads correctly
         on a dark card — these are the same three layers expressed as
         tokens so every theme gets a legible version. */
      --dv-surface: rgba(31,42,68,0.05);
      --dv-line: rgba(31,42,68,0.16);
      --dv-inset: rgba(31,42,68,0.07);
    }
    body.theme-night {
      --sprout-green-tint: rgba(46,196,182,0.16);
      --dv-surface: rgba(255,255,255,0.04);
      --dv-line: rgba(255,255,255,0.12);
      --dv-inset: rgba(0,0,0,0.28);
    }
    body.theme-contrast, body.theme-contrast-light {
      --sprout-green: #00594E;
    }
    body.theme-contrast {
      --dv-surface: #1A1A1A;
      --dv-line: #FFFFFF;
      --dv-inset: #000000;
    }
    body.theme-contrast-light {
      --dv-surface: #EEEEEE;
      --dv-line: #000000;
      --dv-inset: #FFFFFF;
    }
    body.theme-night {
      --bg: #1B2140;
      --bg2: #131737;
      --card: #262C52;
      --ink: #F3F5FF;
      --ink-soft: #B7BEE0;
      --shadow: rgba(0,0,0,0.35);
      --berry: #FF5D8F;
      --mint: #2EC4B6;
      --grape: #9B6BFF;
      --sky: #3FA9F5;
      --sun-ink: #FFC93C;
    }
    body.theme-rainbow {
      --bg: #FFF1E6;
      --bg2: #FFE1F0;
      --card: #FFFFFF;
      --ink: #2B2250;
      --ink-soft: #5A4F80;
      --berry: #E91E63;
      --mint: #009688;
      --sky: #0288D1;
    }
    body.theme-caregiver {
      --bg: #E0F2FE;
      --bg2: #BAE6FD;
      --card: #FFFFFF;
      --ink: #0369A1;
      --ink-soft: #0284C7;
      --shadow: rgba(3, 105, 161, 0.15);
    }
    body.theme-contrast {
      --bg: #000000;
      --bg2: #1A1A1A;
      --card: #111111;
      --ink: #FFFFFF;
      --ink-soft: #FFFF00;
      --shadow: none;
      --sky: #FFFF00;
      --mint: #00FF00;
      --berry: #FF00FF;
      --sun-ink: #FFC93C;
      border: 2px solid #FFFFFF;
    }
    body.theme-contrast-light {
      --bg: #FFFFFF;
      --bg2: #EEEEEE;
      --card: #FFFFFF;
      --ink: #000000;
      --ink-soft: #1A237E;
      --shadow: none;
      --sky: #0D47A1;
      --mint: #1B5E20;
      --berry: #880E4F;
      border: 2px solid #000000;
    }
    body.theme-low-lume {
      --bg: #0D0F14;
      --bg2: #161A23;
      --card: #1A202C;
      --ink: #E2E8F0;
      --ink-soft: #A0AEC0;
      --shadow: none;
      --sky: #63B3ED;
      --mint: #4FD1C5;
      --berry: #F687B3;
      --sun: #F6E05E;
    }

    body.theme-contrast .calc-card, body.theme-contrast-light .calc-card,
    body.theme-contrast .meal-log-card, body.theme-contrast-light .meal-log-card,
    body.theme-contrast .greeting-card, body.theme-contrast-light .greeting-card,
    body.theme-contrast .drawer, body.theme-contrast-light .drawer {
      border: 3px solid var(--ink) !important;
    }
    body.theme-contrast .step-btn, body.theme-contrast-light .step-btn,
    body.theme-contrast .go-btn, body.theme-contrast-light .go-btn,
    body.theme-contrast .shortcut-share-btn, body.theme-contrast-light .shortcut-share-btn,
    body.theme-contrast .confirm-share-btn, body.theme-contrast-light .confirm-share-btn {
      background: var(--ink-soft) !important;
      color: var(--bg) !important;
      border: 2px solid var(--ink) !important;
      font-weight: 900 !important;
    }
    body.theme-contrast .go-btn:disabled, body.theme-contrast-light .go-btn:disabled {
      opacity: 0.45 !important; cursor: not-allowed !important;
    }
    body.theme-contrast .value-box, body.theme-contrast-light .value-box {
      background: var(--bg) !important;
      border: 2px solid var(--ink) !important;
    }
    body.theme-contrast .value-box input, body.theme-contrast-light .value-box input {
      color: var(--ink-soft) !important;
    }

    #confettiCanvas {
      position: fixed;
      top: 0;
      left: 0;
      width: 100vw;
      height: 100vh;
      pointer-events: none;
      z-index: 150;
    }

    .undo-toast {
      position: fixed;
      left: 50%;
      bottom: 24px;
      transform: translateX(-50%) translateY(20px);
      background: var(--ink);
      color: var(--bg);
      padding: 12px 14px 12px 18px;
      border-radius: 100px;
      box-shadow: 0 10px 28px rgba(0,0,0,0.3);
      display: flex;
      align-items: center;
      gap: 12px;
      font-family: 'Nunito', sans-serif;
      font-weight: 800;
      font-size: 0.9rem;
      z-index: 250;
      opacity: 0;
      pointer-events: none;
      transition: opacity 0.25s ease, transform 0.25s ease;
      max-width: calc(100vw - 32px);
    }
    .undo-toast.show {
      opacity: 1;
      pointer-events: auto;
      transform: translateX(-50%) translateY(0);
    }
    .undo-toast .undo-toast-msg {
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .undo-toast .undo-toast-btn {
      background: var(--sun);
      color: #1F2A44;
      border: none;
      padding: 7px 14px;
      border-radius: 100px;
      font-family: 'Baloo 2', sans-serif;
      font-weight: 800;
      font-size: 0.85rem;
      cursor: pointer;
      flex-shrink: 0;
    }
    .undo-toast .undo-toast-btn:active { transform: scale(0.95); }
    @media (prefers-reduced-motion: reduce) {
      .undo-toast { transition: opacity 0.001ms !important; }
    }

    .achievement-toast {
      position: fixed;
      left: 50%;
      bottom: 24px;
      transform: translateX(-50%) translateY(20px);
      background: var(--card);
      border: 3px solid var(--mint);
      color: var(--ink);
      padding: 10px 18px 10px 12px;
      border-radius: 100px;
      box-shadow: 0 10px 28px var(--shadow);
      display: flex;
      align-items: center;
      gap: 10px;
      z-index: 260;
      opacity: 0;
      pointer-events: none;
      max-width: calc(100vw - 32px);
      transition: opacity 0.25s ease, transform 0.25s ease;
    }
    .achievement-toast.show {
      opacity: 1;
      transform: translateX(-50%) translateY(0);
    }
    .achievement-toast .achievement-toast-icon {
      font-size: 1.6rem;
      line-height: 1;
      flex-shrink: 0;
    }
    .achievement-toast .achievement-toast-text {
      text-align: left;
      line-height: 1.25;
      min-width: 0;
    }
    .achievement-toast .achievement-toast-tag {
      font-family: 'Baloo 2', sans-serif;
      font-size: 0.68rem;
      font-weight: 800;
      color: var(--mint);
      text-transform: uppercase;
      letter-spacing: 0.05em;
    }
    .achievement-toast .achievement-toast-title {
      font-family: 'Baloo 2', sans-serif;
      font-size: 1rem;
      font-weight: 800;
      color: var(--ink);
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    @media (prefers-reduced-motion: reduce) {
      .achievement-toast { transition: opacity 0.001ms !important; }
    }

    .modal-overlay {
      position: fixed; inset: 0; background: rgba(0,0,0,0.6);
      z-index: 100; display: none; align-items: center; justify-content: center;
      padding: 15px;
    }
    .modal-content {
      background: var(--card); border-radius: var(--radius-lg);
      padding: 24px 18px; width: 100%; max-width: 440px;
      max-height: 90vh; overflow-y: auto;
      box-shadow: 0 12px 36px rgba(0,0,0,0.4);
    }

    /* ---- Caregiver "Edit Details" modal polish ---- */
    #editModal .modal-content { padding: 0; }
    #editModal .edit-modal-head {
      background: linear-gradient(135deg, var(--sky), #1E88E5);
      color: #fff; padding: 22px 20px 18px; text-align: center;
    }
    #editModal .edit-modal-head h3 { margin: 0; color: #fff; font-size: 1.32rem; }
    #editModal .edit-modal-sub { margin-top: 5px; font-size: 0.85rem; font-weight: 600; opacity: 0.92; }
    #editModal .edit-modal-body { padding: 20px 18px 22px; }
    #editModal input[type="text"] {
      transition: border-color 0.15s ease, box-shadow 0.15s ease;
    }
    #editModal input[type="text"]:focus {
      outline: none; border-color: var(--sky);
      box-shadow: 0 0 0 3px rgba(63,169,245,0.2);
    }
    #editModal .field label { font-size: 0.9rem; }

    /* Share confirmation card */
    .share-instructions-box {
      margin-top: 18px; padding: 16px 16px 14px; border-radius: 16px;
      background: linear-gradient(135deg, #E1F5FE, #EAF7EA);
      border: 2px solid #B3E5FC;
    }
    body.theme-night .share-instructions-box {
      background: linear-gradient(135deg, #12233A, #12261E); border-color: #1E3A5F;
    }
    .share-instructions-title {
      display: flex; align-items: center; gap: 10px;
      font-family: 'Baloo 2', sans-serif; font-weight: 800; font-size: 1.05rem;
      color: #0284C7; margin-bottom: 8px;
    }
    body.theme-night .share-instructions-title { color: var(--sky); }
    .mini-share-mascot { width: 34px; height: 34px; flex-shrink: 0; }
    .share-sent-time {
      display: inline-block; margin-bottom: 10px;
      font-size: 0.85rem; font-weight: 700; color: #0369A1;
      background: rgba(255,255,255,0.65); border: 1px solid #B3E5FC;
      padding: 6px 11px; border-radius: 10px;
    }
    body.theme-night .share-sent-time {
      color: #8FD0FF; background: rgba(255,255,255,0.06); border-color: #1E3A5F;
    }
    .share-instructions-text { font-size: 0.9rem; color: var(--ink-soft); line-height: 1.5; }
    .share-instructions-text ul { margin: 8px 0 0; padding-left: 20px; }
    .share-instructions-text li { margin-bottom: 4px; }
    .edit-item-row { display: flex; gap: 8px; margin-bottom: 10px; align-items: center; width: 100%; }
    .edit-item-row input[type="text"] { flex: 2; padding: 10px; border-radius: 10px; border: 1px solid var(--bg2); color: var(--ink); background: var(--bg); font-weight:700; min-width: 0; }
    .edit-item-row input[type="number"] { flex: 1; padding: 10px; border-radius: 10px; border: 1px solid var(--bg2); color: var(--ink); background: var(--bg); font-weight:700; min-width: 0; text-align: center; }
    .edit-item-row button { background: var(--bg2); border: none; padding: 10px 14px; border-radius: 10px; cursor: pointer; color: var(--berry); font-weight: bold; flex-shrink: 0; }
    .modal-items-total {
      text-align: right;
      font-family: 'Baloo 2', sans-serif;
      font-weight: 800;
      font-size: 1rem;
      color: var(--sky);
      padding-top: 8px;
      margin: 2px 0 16px;
      border-top: 2px dashed var(--bg2);
    }

    .fancy-safety-card {
      margin: 18px 0;
      padding: 14px 16px;
      background: var(--bg);
      border-radius: var(--radius-md);
      border: 2px dashed var(--bg2);
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 12px;
      cursor: pointer;
      user-select: none;
      -webkit-user-select: none;
      transition: background 0.2s, border-color 0.25s;
    }
    body.theme-night .fancy-safety-card { background: #1B2140; border-color: #262C52; }
    .fancy-safety-card:hover {
      background: var(--bg2);
      opacity: 0.95;
    }
    .fancy-safety-card.activated {
      background: rgba(16, 185, 129, 0.1);
      border: 2px solid var(--mint);
    }
    .fancy-safety-card.activated .switch-track {
      background: var(--mint);
    }
    .fancy-safety-card.activated .switch-knob {
      transform: translateX(20px);
    }
    
    .sprout-validation-gate {
      background: rgba(24, 144, 255, 0.08);
      border: 2px dashed var(--sky);
      border-radius: var(--radius-md);
      padding: 14px;
      margin: 12px 0;
      display: none;
      animation: pop 0.3s ease;
    }
    .sprout-validation-gate-text {
      font-size: 0.88rem;
      font-weight: 800;
      line-height: 1.4;
      color: var(--ink);
      margin-bottom: 10px;
    }
    .sprout-validation-gate-btn {
      width: 100%;
      background: var(--sky);
      color: white;
      border: none;
      padding: 10px;
      border-radius: 10px;
      font-family: 'Baloo 2', sans-serif;
      font-weight: 700;
      font-size: 0.95rem;
      cursor: pointer;
      box-shadow: 0 4px 10px rgba(21,101,192,0.2);
    }
    .carb-ceiling-inline-msg {
      text-align: center;
      font-size: 0.85rem;
      font-weight: 800;
      color: var(--berry);
      margin: 6px 0 2px;
      animation: pop 0.3s ease;
    }
    .carb-ceiling-inline-msg.is-teasing {
      color: var(--sky);
    }
    .sprout-validation-gate-typed-label {
      display: block;
      font-size: 0.8rem;
      font-weight: 700;
      color: var(--ink-soft);
      margin-bottom: 6px;
    }
    .sprout-validation-gate-typed-input {
      width: 100%;
      box-sizing: border-box;
      padding: 10px;
      border-radius: 10px;
      border: 2px solid var(--sky);
      font-family: 'Baloo 2', sans-serif;
      font-weight: 700;
      font-size: 1rem;
      text-align: center;
      background: var(--bg);
      color: var(--ink);
    }
    body.theme-contrast .sprout-validation-gate-typed-input,
    body.theme-contrast-light .sprout-validation-gate-typed-input {
      background: var(--bg) !important;
      border: 2px solid var(--ink) !important;
      color: var(--ink) !important;
    }

    @keyframes inputErrorFlash {
      0%, 100% { box-shadow: 0 0 0 transparent; }
      40% { box-shadow: 0 0 0 4px var(--berry); }
    }
    .flash-error {
      animation: inputErrorFlash 0.7s ease;
      border-radius: 14px;
    }

    .switch-track {
      width: 44px;
      height: 24px;
      background: #B0BEC5;
      border-radius: 100px;
      position: relative;
      flex-shrink: 0;
      transition: background 0.2s ease;
    }
    .switch-knob {
      width: 18px;
      height: 18px;
      background: #FFFFFF;
      border-radius: 50%;
      position: absolute;
      top: 3px;
      left: 3px;
      box-shadow: 0 2px 5px rgba(0,0,0,0.2);
      transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
    }

    .privacy-scroll-box {
      background: var(--bg); border: 2px solid var(--bg2); border-radius: var(--radius-md);
      padding: 14px; max-height: 48vh; overflow-y: auto; font-size: 0.82rem; line-height: 1.45;
      color: var(--ink); text-align: left; font-weight: 700; margin-bottom: 16px;
    }
    body.theme-night .privacy-scroll-box { background: #1B2140; border-color: #262C52; }
    .privacy-scroll-box h4 { font-family: 'Baloo 2', sans-serif; font-size: 0.95rem; margin: 12px 0 4px 0; color: var(--sky); text-transform: none; letter-spacing: normal; }
    .privacy-scroll-box h4:first-child { margin-top: 0; }
    .privacy-scroll-box p { margin: 0 0 10px 0; }
    .privacy-scroll-box ul { margin: 0 0 10px 0; padding-left: 18px; }
    .privacy-scroll-box li { margin-bottom: 4px; }
    .privacy-scroll-box blockquote { margin: 10px 0; background: rgba(255,167,38,0.12); padding: 10px; border-radius: 8px; border-left: 4px solid #FF9800; font-size: 0.78rem; }
    
    .privacy-link-container {
      position: sticky;
      bottom: -30px;
      margin-top: 25px;
      background: var(--card);
      padding: 12px 0;
      text-align: right;
      z-index: 10;
      border-top: 1px dashed var(--bg2);
    }
    .privacy-trigger-link {
      color: var(--ink-soft); 
      font-size: 0.75rem; 
      font-weight: 800; 
      text-decoration: underline; 
      background: none; 
      border: none; 
      cursor: pointer; 
      padding: 4px;
    }
    .privacy-trigger-link:hover { color: var(--sky); }

    /* Share icon row: WhatsApp / Facebook / Email / "more" (native share
       sheet). Plain colored circles rather than a text button — icons scan
       faster than a button label for a share row, and each platform link
       is a plain href (no JS needed) except "more", which opens the native
       share sheet / clipboard fallback. */
    .share-icon-row {
      display: flex;
      justify-content: center;
      gap: 14px;
    }
    .share-icon-btn {
      width: 44px;
      height: 44px;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      border: none;
      cursor: pointer;
      transition: transform 0.15s ease;
      box-shadow: 0 3px 10px var(--shadow);
    }
    .share-icon-btn:hover { transform: scale(1.08); }
    .share-icon-btn:active { transform: scale(0.94); }
    .share-icon-whatsapp { background: #25D366; }
    .share-icon-facebook { background: #1877F2; }
    .share-icon-email { background: var(--sky); }
    .share-icon-more { background: var(--ink-soft); }

    .footer-links-row {
      display: flex;
      justify-content: center;
      flex-wrap: wrap;
      gap: 16px;
      margin-top: 10px;
    }
    .footer-copyright {
      text-align: center;
      font-size: 0.68rem;
      font-weight: 700;
      color: var(--ink-soft);
      opacity: 0.75;
      margin: 10px 0 4px;
      line-height: 1.4;
    }
    .footer-trigger-link {
      color: var(--sky);
      font-size: 0.75rem;
      font-weight: 800;
      text-decoration: underline;
      background: none;
      border: none;
      cursor: pointer;
      padding: 4px;
    }
    .footer-trigger-link:hover { opacity: 0.85; }

    .disclaimer-mascot-container {
      width: 32px;
      height: 32px;
      display: inline-block;
      flex-shrink: 0;
    }

    * { box-sizing: border-box; }
    html {
      scroll-behavior: smooth; scroll-padding-top: 90px;
      /* Stops Chrome for Android's text-autosizing ("font boosting"), which
         guesses at "too small to read" text blocks (short bubbles like the
         greeting text are a classic trigger) and inflates them well past
         their authored font-size. Firefox doesn't do this, hence the same
         CSS looking fine there and oversized in Chrome. This only disables
         Chrome's own heuristic — it does not affect the Android OS-level
         accessibility font-size setting, which still scales normally. */
      -webkit-text-size-adjust: 100%;
      text-size-adjust: 100%;
    } /* reserves space for the sticky topbar (~78px, brand-mark is 60px tall) + breathing room, for every scroll/scrollIntoView on the page */
    /* Give a little breathing room at the top when we scroll a station into view */

    .sr-only {
      position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
      overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
    }
    .skip-link {
      position: absolute; left: 8px; top: -60px; z-index: 1000;
      background: var(--card); color: var(--ink); padding: 10px 16px;
      border-radius: 10px; font-weight: 800; text-decoration: none;
      box-shadow: 0 6px 18px var(--shadow); transition: top 0.15s ease;
    }
    .skip-link:focus { top: 8px; }

    a:focus-visible, button:focus-visible, input:focus-visible,
    [role="button"]:focus-visible, [role="radio"]:focus-visible,
    [tabindex]:focus-visible {
      outline: 3px solid var(--sky);
      outline-offset: 2px;
    }

    @media (prefers-reduced-motion: reduce) {
      html { scroll-behavior: auto; }
      *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
      }
    }
    body {
      margin: 0; padding: 0; min-height: 100%;
      font-family: 'Nunito', system-ui, sans-serif;
      color: var(--ink);
      background: radial-gradient(circle at 20% 0%, var(--bg2), var(--bg) 60%);
      transition: background .4s ease, color .4s ease;
      -webkit-tap-highlight-color: transparent;
    }
    body.modal-open-freeze {
      overflow: hidden;
    }
    body.modal-open-freeze #mainContent {
      filter: blur(5px);
    }
    h1, h2, h3, .display {
      font-family: 'Baloo 2', sans-serif;
      font-weight: 700;
      margin: 0;
    }
    .app {
      width: 95%;
      max-width: 640px;
      margin: 0 auto;
      min-height: 100vh;
      padding: 16px 16px 40px;
      font-size: calc(1em * var(--font-scale));
      transition: filter 0.3s ease;
    }
    .topbar {
      display: flex; align-items: center; justify-content: space-between;
      margin: 0 -16px 4px; padding: 10px 16px 8px;
      position: sticky; top: 0; z-index: 5;
      background: var(--bg);
    }
    .brand { display: flex; align-items: center; gap: 10px; }
    .brand-mark {
      width: 60px; height: 60px; flex: 0 0 auto;
      display: block; padding: 0; border: none; background: none;
      cursor: pointer;
    }
    .brand-mark svg { display: block; width: 100%; height: 100%; }
    .brand-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
    .brand h1 { font-size: 1.4rem; color: var(--ink); line-height: 1.1; }
    /* ============================================================
       CYCLING TAGLINE (added 26 Aug 2026) — see the matching comment
       block in index.html above #brandTagline for the full revert note.
       This block (down to "END") can be deleted as a single unit.
       Kept deliberately small/muted so it reads as a subtitle, not a
       second competing headline next to "Sprout Count" itself — and
       constrained to one line with its own ellipsis so a future longer
       tagline can never push the sticky header taller or wrap awkwardly
       against the icon buttons on the right. ============ */
    .brand-tagline {
      font-size: 0.7rem; font-weight: 700; color: var(--ink-soft);
      margin: 0; line-height: 1.3; white-space: nowrap; overflow: hidden;
      text-overflow: ellipsis; max-width: 100%;
      opacity: 1; transition: opacity 0.4s ease;
    }
    .brand-tagline.fading { opacity: 0; }
    @media (prefers-reduced-motion: reduce) {
      .brand-tagline { transition: none; }
    }
    /* END cycling tagline */
    
    .gear-btn {
      position: relative;
      width: 44px; height: 44px; border-radius: 50%;
      border: none; background: var(--card); box-shadow: 0 4px 10px var(--shadow);
      display: flex; align-items: center; justify-content: center;
      cursor: pointer; padding: 0;
    }
    .gear-btn:active { transform: scale(0.92); }
    /* Lets someone know there's something new to see in "Make it yours"
       since they last opened it — a badge unlocked, a level up, a new
       garden plant, a meal logged, or any setting they changed themselves.
       Cleared the moment the drawer is opened. */
    .settings-notif-dot {
      position: absolute; top: 1px; right: 1px;
      width: 12px; height: 12px; border-radius: 50%;
      background: #FF3B30;
      border: 2px solid var(--card);
      display: none;
    }
    .settings-notif-dot.show { display: block; }

    /* Drill-down dots: the gear icon says "something's new somewhere";
       these say specifically where. Tab dots sit inline next to the tab
       label (part of the flex row, so they just nudge the label over
       slightly); accordion dots are absolutely positioned so they don't
       disturb the existing label/chevron space-between layout. Each
       clears independently — tab dot on switching to that tab, accordion
       dot on opening that specific accordion — so the trail can be
       followed all the way to the actual new content. */
    .tab-notif-dot {
      display: none;
      width: 7px; height: 7px; border-radius: 50%;
      background: #FF3B30;
      margin-left: 4px;
      vertical-align: super;
    }
    .tab-notif-dot.show { display: inline-block; }
    .accordion-notif-dot {
      display: none;
      position: absolute;
      top: 8px; right: 34px;
      width: 8px; height: 8px; border-radius: 50%;
      background: #FF3B30;
    }
    .accordion-notif-dot.show { display: block; }
    /* End of the trail: sits on the specific badge tile that's newly
       unlocked, inside the badges grid. Clears when the badges accordion
       is opened. */
    .badge-notif-dot {
      display: none;
      position: absolute;
      top: 6px; right: 6px;
      width: 8px; height: 8px; border-radius: 50%;
      background: #FF3B30;
      border: 2px solid var(--card);
      z-index: 1;
    }
    .badge-notif-dot.show { display: block; }
    .back-to-top-btn {
      position: fixed; right: 18px; bottom: 22px; z-index: 4;
      width: 46px; height: 46px; border-radius: 50%;
      border: none; background: var(--card); box-shadow: 0 4px 14px var(--shadow);
      display: flex; align-items: center; justify-content: center;
      color: var(--ink);
      font-size: 1.2rem; cursor: pointer; padding: 0;
      opacity: 0; visibility: hidden; transform: translateY(8px) scale(0.9);
      transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s;
    }
    .back-to-top-btn.visible { opacity: 1; visibility: visible; transform: translateY(0) scale(1); }
    .back-to-top-btn:active { transform: scale(0.9); }
    @media (prefers-reduced-motion: reduce) { .back-to-top-btn { transition: opacity 0.15s linear; } }
    .hamburger-icon {
      width: 18px; height: 14px;
      display: flex; flex-direction: column; justify-content: space-between;
    }
    .hamburger-icon span {
      display: block; width: 100%; height: 3px; background-color: var(--ink-soft);
      border-radius: 4px; transition: background-color 0.2s;
    }
    body.theme-contrast .hamburger-icon span { background-color: var(--ink); }
    body.theme-contrast-light .hamburger-icon span { background-color: var(--ink); }
    
    .greeting-card {
      background: var(--card);
      border-radius: var(--radius-lg);
      padding: 8px 16px;
      box-shadow: 0 8px 24px var(--shadow);
      display: flex; align-items: center; gap: 12px;
      margin-top: 14px;
      margin-bottom: 8px;
      transition: padding 0.25s ease, margin 0.25s ease;
    }
    /* Once the person is actively logging (Step 1 answered), the greeting
       card tightens its own padding/margin a touch to save vertical space —
       but the mascot and text stay full size (previously shrank to 34px /
       0.78rem here, which read as too small to comfortably read). */
    .greeting-card.condensed {
      padding: 5px 14px; margin-top: 10px; margin-bottom: 6px;
    }
    .greeting-mascot { 
      width: 60px; 
      flex: 0 0 auto; 
      height: 60px; 
      cursor: pointer;
      user-select: none;
      -webkit-user-select: none;
      transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
    }
    .mascot-avatar-wrap {
      position: relative;
      flex: 0 0 auto;
      width: 60px;
      height: 60px;
      /* Same flicker fix as .go-btn above — the mascot SVG here
         redraws often (idle animation, costume swaps, the confetti
         canvas layered on top), which was likely causing the same
         repeated GPU-layer promotion/demotion flip-flop and seam
         flicker. Forcing a stable layer up front stops it. */
      transform: translateZ(0);
      backface-visibility: hidden;
    }
    /* Confined to exactly the avatar circle (not the corner badges, which
       poke out past this 60x60 box) — used only during the dance easter
       egg, drawn/cleared entirely in JS via startMascotConfetti(). */
    .mascot-confetti-canvas {
      position: absolute;
      top: 0; left: 0;
      width: 60px; height: 60px;
      border-radius: 50%;
      pointer-events: none;
      z-index: 1;
    }

    /* Dance easter egg: a disco ball drops into the top-left corner and
       stays there for the whole dance — the plain 🪩 emoji, not animated
       (no spin), with two small twinkling sparkle glints alongside it for
       a bit of "catching the light" motion, plus a very small continuous
       bounce (starts once the drop-in settles, via animation-delay, so
       the two don't stack awkwardly on top of each other). shown/hidden
       via the "show" class from JS, kept in sync with the dance's own
       duration. */
    .mascot-disco-ball {
      position: absolute;
      top: -6px; left: -6px;
      width: 20px; height: 20px;
      display: none;
      opacity: 0;
      transform: translateY(-40px) scale(0.5);
      z-index: 2;
    }
    .mascot-disco-ball.show {
      display: block;
      animation: discoDropIn 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
    }
    .mascot-disco-ball-emoji {
      display: block;
      font-size: 1.05rem;
      line-height: 1;
      filter: drop-shadow(0 2px 3px rgba(0,0,0,0.35));
      animation: discoIdleBounce 1.3s ease-in-out 0.6s infinite;
    }
    .mascot-disco-ball .disco-sparkle {
      position: absolute;
      width: 3px; height: 3px;
      border-radius: 50%;
      background: #fff;
      box-shadow: 0 0 4px 1px rgba(255,255,255,0.95);
      animation: discoSparkle 1s ease-in-out infinite;
    }
    .mascot-disco-ball .disco-sparkle:nth-child(2) { top: 1px; right: -3px; animation-delay: 0s; }
    .mascot-disco-ball .disco-sparkle:nth-child(3) { bottom: 2px; left: -2px; animation-delay: 0.45s; }
    @keyframes discoDropIn {
      0%   { opacity: 0; transform: translateY(-40px) scale(0.5); }
      60%  { opacity: 1; transform: translateY(3px) scale(1.08); }
      80%  { transform: translateY(-2px) scale(0.97); }
      100% { opacity: 1; transform: translateY(0) scale(1); }
    }
    @keyframes discoIdleBounce {
      0%, 100% { transform: translateY(0); }
      50% { transform: translateY(-1.5px); }
    }
    @keyframes discoSparkle {
      0%, 100% { opacity: 0; transform: scale(0.5); }
      50% { opacity: 1; transform: scale(1.2); }
    }
    @media (prefers-reduced-motion: reduce) {
      .mascot-disco-ball.show { animation: none; opacity: 1; transform: translateY(0) scale(1); }
      .mascot-disco-ball-emoji { animation: none; }
      .mascot-disco-ball .disco-sparkle { animation: none; opacity: 0; }
    }
    
    .greeting-mascot:not(.interacting) {
      animation: playfulBounce 0.5s ease-in-out infinite alternate;
    }

    .greeting-mascot.sprout-spin-action {
      animation: spinYOnce 0.65s cubic-bezier(0.4, 0, 0.2, 1);
    }
    .greeting-mascot.sprout-bounce-action {
      animation: quickJump 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.5) 2;
    }
    .greeting-mascot.sprout-shiver-action {
      animation: microTremble 0.1s linear infinite;
    }
    .greeting-mascot.sprout-fart-action {
      animation: blastBack 0.45s cubic-bezier(0.36, 0.07, 0.19, 0.97) 1;
    }
    /* Easter egg: tap Sprout rapidly (6 taps in a row) and it breaks into a
       little dance instead of the usual single-tap reaction. Iteration
       count matches the 9s the dialogue stays up in triggerMascotDance()
       below, so Sprout keeps moving — and the confined confetti in its
       circle keeps falling — for as long as the text is on screen, rather
       than any of the three cutting off before the others. */
    .greeting-mascot.sprout-dance-action {
      animation: discoWiggle 0.5s ease-in-out 18;
    }
    @keyframes discoWiggle {
      0%, 100% { transform: translateY(0) rotate(0deg) scale(1); }
      20% { transform: translateY(-8px) rotate(-14deg) scale(1.08); }
      40% { transform: translateY(0) rotate(10deg) scale(0.96); }
      60% { transform: translateY(-10px) rotate(-10deg) scale(1.1); }
      80% { transform: translateY(0) rotate(14deg) scale(0.96); }
    }

    @keyframes spinYOnce {
      0% { transform: rotate(0deg) scale(1); }
      50% { transform: rotate(180deg) scale(1.25); }
      100% { transform: rotate(360deg) scale(1); }
    }
    @keyframes quickJump {
      0%, 100% { transform: translateY(0) scale(1); }
      50% { transform: translateY(-16px) scale(1.1); }
    }
    @keyframes microTremble {
      0%, 100% { transform: translate(0, 0) scale(1); }
      25% { transform: translate(-1.5px, 1px); }
      75% { transform: translate(1.5px, -1px); }
    }
    @keyframes blastBack {
      0% { transform: scale(1) translateX(0); }
      20% { transform: scale(1.15) translateX(8px) rotate(8deg); }
      50% { transform: scale(0.9) translateX(-12px) rotate(-4deg); }
      100% { transform: scale(1) translateX(0); }
    }
    @keyframes playfulBounce {
      0% { transform: translateY(0); }
      100% { transform: translateY(-6px); }
    }

    /* Rex (welcome-banner presence) removed — he now lives in the
       "Rex's Garden" section title instead (see .rex-garden-title-icon
       further down this file, and the matching markup in index.html
       above .garden-card). This block used to hold
       .rex-group/.rex-avatar/rexHappyHop and their
       shared-bounce-with-Sprout animation; all removed along with
       js/rex.js (deleted) and the matching resync logic in
       js/app.js's resetMascotToIdle(). See docs/NOTES.md for the full
       history of his time in this spot if ever revisiting it. */

    .greeting-text-wrap {
      flex: 1 1 auto;
      min-width: 0;
      display: flex;
      flex-direction: column;
      gap: 6px;
    }
    /* Fixed px base (not rem) so this stays consistent across browsers —
       Chrome for Android scales rem/em text according to the device's
       system "Font size" accessibility setting, but Firefox for Android
       doesn't apply that same scaling, which is why the same rem-based
       size looked fine in Firefox and oversized in Chrome. Using px here
       sidesteps that inconsistency; --font-scale still lets the app's own
       in-app accessibility control resize it on purpose. */
    .greeting-text {
      font-size: calc(15px * var(--font-scale));
      font-weight: 600;
      line-height: 1.35;
    }

    /* Streak badge: mirrors .level-badge-btn below, but sits on the top-right
       corner of the mascot avatar instead of bottom-right, so the two never
       overlap. Only shown once there's a real streak (2+ days). Amber ring
       + gentle pulse when today isn't logged yet and the streak needs a
       save; a small ice tint once the one-day freeze has been spent. */
    .streak-badge-btn {
      position: absolute;
      top: -10px;
      right: -10px;
      width: 23px;
      height: 23px;
      border-radius: 50%;
      border: 1.5px solid var(--sun);
      background: var(--card);
      box-shadow: 0 1px 4px var(--shadow);
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      padding: 0;
      gap: 0;
      transition: transform 0.15s ease;
      z-index: 2;
    }
    .streak-badge-btn:hover { transform: scale(1.08); }
    .streak-badge-btn:active { transform: scale(0.96); }
    .streak-badge-icon { font-size: 0.62rem; line-height: 1; }
    .streak-badge-num {
      font-family: 'Baloo 2', sans-serif;
      font-weight: 800;
      font-size: 0.62rem;
      line-height: 1;
      color: var(--ink);
    }
    .streak-badge-btn.at-risk {
      border-color: #FF6D00;
      box-shadow: 0 0 0 2px rgba(255,109,0,0.3), 0 1px 4px var(--shadow);
      animation: streakBadgePulse 1.8s ease-in-out infinite;
    }
    @keyframes streakBadgePulse {
      0%, 100% { opacity: 1; }
      50% { opacity: 0.6; }
    }
    @media (prefers-reduced-motion: reduce) {
      .streak-badge-btn.at-risk { animation: none; }
    }

    /* Achievement button: a compact numbered badge overlaid on the mascot avatar.
       Pushed further into the corner than a badge normally would be — it used
       to overlap deep enough into the mascot's own tap area (helped along by
       its own expanded invisible hit zone below) that Sprout became genuinely
       hard to tap, especially for the rapid-tap dance easter egg. */
    .level-badge-btn {
      position: absolute;
      bottom: -14px;
      right: -14px;
      width: 23px;
      height: 23px;
      border-radius: 50%;
      border: 1.5px solid var(--mint);
      background: var(--card);
      box-shadow: 0 1px 4px var(--shadow);
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      padding: 0;
      transition: transform 0.15s ease;
      z-index: 2;
    }
    .level-badge-btn:hover { transform: scale(1.08); }
    .level-badge-btn:active { transform: scale(0.96); }
    .level-badge-icon {
      display: none;
    }
    .level-badge-num {
      position: static;
      min-width: 0;
      height: auto;
      padding: 0;
      border: none;
      background: transparent;
      color: var(--ink);
      font-family: 'Baloo 2', sans-serif;
      font-weight: 800;
      font-size: 0.8rem;
      line-height: 1;
    }
    .level-badge-btn.maxed {
      border-color: var(--sun);
      background: var(--card);
      box-shadow: 0 0 0 2px rgba(255, 201, 60, 0.35), 0 1px 4px var(--shadow);
    }
    .level-badge-btn.maxed .level-badge-num {
      color: var(--ink);
    }
    /* Achievement card shown above the "Who's eating?" panel in the "Make it yours" drawer */
    .drawer-level-badge {
      width: 100%;
      display: flex;
      align-items: center;
      gap: 10px;
      background: var(--bg);
      border: 1.5px solid var(--mint);
      border-radius: var(--radius-md);
      padding: 10px 12px;
      font-family: inherit;
      text-align: left;
      cursor: pointer;
      transition: transform 0.15s ease;
    }
    .drawer-level-badge:hover { transform: translateY(-1px); }
    .drawer-level-badge:active { transform: scale(0.98); }
    .drawer-level-badge.maxed {
      border-color: var(--sun);
      background: rgba(255, 201, 60, 0.14);
    }
    .drawer-level-badge-icon-wrap {
      flex: 0 0 auto;
      width: 36px;
      height: 36px;
      border-radius: 50%;
      background: rgba(46, 196, 182, 0.16);
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .drawer-level-badge.maxed .drawer-level-badge-icon-wrap {
      background: rgba(255, 201, 60, 0.22);
    }
    .drawer-level-badge-icon {
      font-size: 1.15rem;
      line-height: 1;
    }
    .drawer-level-badge-text {
      flex: 1 1 auto;
      min-width: 0;
      display: flex;
      flex-direction: column;
      gap: 1px;
    }
    .drawer-level-badge-eyebrow {
      font-size: 0.62rem;
      font-weight: 800;
      text-transform: uppercase;
      letter-spacing: 0.06em;
      color: var(--mint);
    }
    .drawer-level-badge.maxed .drawer-level-badge-eyebrow { color: #C98A00; }
    .drawer-level-badge-title {
      font-weight: 800;
      font-size: 0.9rem;
      color: var(--ink);
    }
    .drawer-level-badge-chevron {
      flex: 0 0 auto;
      font-size: 1.2rem;
      color: var(--ink-soft);
    }

    .level-info-icon {
      font-size: 2.6rem;
      width: 72px; height: 72px;
      margin: 0 auto 10px;
      display: flex; align-items: center; justify-content: center;
      background: rgba(46, 196, 182, 0.12);
      border-radius: 50%;
    }
    .level-info-badge-strip {
      display: flex;
      flex-wrap: wrap;
      justify-content: center;
      gap: 6px;
      margin-top: 14px;
    }
    .level-info-badge-strip span {
      font-size: 1.3rem;
      background: var(--bg);
      border-radius: 50%;
      width: 34px; height: 34px;
      display: flex; align-items: center; justify-content: center;
    }
    body.theme-night .level-info-badge-strip span { background: #1B2140; }
    .level-info-badge-strip .level-info-badge-empty {
      font-size: 0.78rem;
      font-weight: 700;
      color: var(--ink-soft);
      background: none;
      width: auto; height: auto;
    }

    .caregiver-card {
      background: var(--card);
      border-radius: var(--radius-lg);
      padding: 30px 24px;
      box-shadow: 0 12px 32px var(--shadow);
      text-align: center;
      margin-bottom: 18px;
      display: none;
    }
    .caregiver-card.show { display: block; animation: pop .5s ease; }
    .caregiver-badge {
      display: inline-block; background: #E0F2FE; color: #0369A1;
      padding: 6px 14px; border-radius: 20px; font-weight: 800; font-size: 0.85rem;
      text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 16px;
    }
    .caregiver-event-tag {
      font-size: 1.15rem; font-weight: 800; color: #0369A1; margin: 4px 0 16px;
      font-family: 'Baloo 2', sans-serif; display: none; background: #F0F9FF;
      padding: 10px 14px; border-radius: 16px; border: 2px dashed #BAE6FD;
    }
    .caregiver-timestamp {
      font-size: 0.85rem; font-weight: 700; color: #0284C7; margin-bottom: 6px;
    }
    .caregiver-total-box {
      background: #F0F9FF; border: 4px dashed #0284C7; border-radius: 24px;
      padding: 24px; margin: 20px 0;
    }
    .caregiver-num {
      font-family: 'Baloo 2', sans-serif; font-size: 4rem; font-weight: 800;
      color: #0369A1; line-height: 1;
    }
    .caregiver-sub { font-weight: 700; color: #0284C7; font-size: 1.1rem; margin-top: 4px; }
    
    .caregiver-breakdown-title {
      font-family: 'Baloo 2', sans-serif; font-size: 1.15rem; text-align: left;
      margin: 20px 0 10px; color: #0369A1; font-weight: 800;
    }
    .caregiver-list {
      display: flex; flex-direction: column; gap: 8px; margin-bottom: 24px; text-align: left;
    }
    .caregiver-item {
      display: flex; align-items: center; justify-content: space-between;
      background: #F0F9FF; padding: 10px 14px; border-radius: 14px;
      font-size: 0.95rem; font-weight: 700; border: 1px solid #BAE6FD;
    }
    .caregiver-item-details { color: #0284C7; font-size: 0.8rem; font-weight: 600; margin-top: 2px; }
    .caregiver-item-name-row { display: flex; align-items: center; gap: 6px; }
    .caregiver-item-icon { font-size: 1rem; flex-shrink: 0; }
    .caregiver-edited-tag {
      display: inline-block; background: #FEF3C7; color: #92400E;
      font-size: 0.68rem; font-weight: 800; padding: 2px 7px; border-radius: 20px;
      margin-top: 3px;
    }
    .caregiver-disclaimer {
      background: #FEF9C3; border: 2px dashed #FBBF24; color: #713F12;
      font-size: 0.78rem; font-weight: 700; line-height: 1.4; text-align: left;
      padding: 12px 14px; border-radius: 14px; margin-bottom: 18px;
    }

    .return-btn {
      width: 100%; border: none; padding: 14px; background: #0284C7; color: white;
      font-family: 'Baloo 2', sans-serif; font-weight: 700; font-size: 1.1rem;
      border-radius: var(--radius-md); cursor: pointer; transition: background 0.2s;
    }
    .return-btn:hover { background: #0284C7; }

    .calc-card {
      background: var(--card);
      border-radius: var(--radius-lg);
      padding: 18px;
      box-shadow: 0 10px 28px var(--shadow);
      margin-bottom: 12px;
      position: relative;
      overflow: hidden;
    }
    .calc-card.hidden { display: none; }
    
    .soda-fizz-overlay-container {
      position: absolute;
      inset: 0;
      pointer-events: none;
      z-index: 1;
      overflow: hidden;
    }
    .calc-card-interactive-content-wrap {
      position: relative;
      z-index: 2;
    }

    .fizz-bubble {
      position: absolute;
      bottom: -20px;
      background: rgba(63, 169, 245, 0.18);
      border: 1.5px solid rgba(255, 255, 255, 0.4);
      border-radius: 50%;
      animation: upwardFloat linear infinite;
    }
    body.theme-night .fizz-bubble {
      background: rgba(46, 196, 182, 0.15);
    }
    body.theme-rainbow .fizz-bubble {
      background: rgba(233, 30, 99, 0.12);
    }

    @keyframes upwardFloat {
      0% {
        transform: translateY(0) translateX(0);
        opacity: 0;
      }
      10% { opacity: 0.8; }
      90% { opacity: 0.8; }
      100% {
        transform: translateY(-420px) translateX(var(--bubble-drift, 15px));
        opacity: 0;
      }
    }

    .field { margin-bottom: 14px; transition: opacity 0.2s ease; }
    .field label {
      display: block; font-weight: 800; font-size: 0.95rem; margin-bottom: 6px;
      color: var(--ink);
    }
    .field label .icon-tag { margin-right: 6px; }
    #carbsField > label, #weightField > label, .step-label-flex {
      display: flex; align-items: center; flex-wrap: wrap;
    }
    /* The volume step's label text gets swapped between "How much fluid?" /
       "Scale Weight" / "How much powder?" via innerHTML depending on drink
       mode, so its badge and summary/chevron live as siblings instead of
       inside the label itself — otherwise every mode switch would wipe them. */
    .step-label-group { display: flex; align-items: center; gap: 6px; }
    .step-summary-group { display: flex; align-items: center; }
    .field .hint { font-weight: 600; color: var(--ink-soft); font-size: 0.8rem; }
    /* A word beats an icon here: no guessing what the symbol means, and the
       filled state shows which tips are already open. */
    .info-hint-btn {
      display: inline-flex; align-items: center; justify-content: center;
      width: 23px; height: 23px; padding: 0; margin-left: 6px;
      border: none; border-radius: 50%;
      background: rgba(56,189,248,0.14); color: var(--sky);
      font-family: 'Nunito', sans-serif; font-size: 0; line-height: 1;
      cursor: pointer; white-space: nowrap;
      vertical-align: middle; position: relative;
      -webkit-tap-highlight-color: transparent;
      transition: background-color 0.15s ease, color 0.15s ease, transform 0.12s ease, box-shadow 0.15s ease;
    }
    /* Same friendly ⓘ in both states — no symbol swap, since something like
       an X reads as "close/cancel/delete" and felt alarming. Open vs closed
       is signalled by colour (solid vs pale) and a soft glow ring instead. */
    .info-hint-btn::after {
      content: 'ⓘ'; font-weight: 800; font-size: 0.9rem;
    }
    /* Keeps the pill compact while the touch area stays a comfortable 44px. */
    .info-hint-btn::before {
      content: ''; position: absolute; top: 50%; left: 50%;
      width: 100%; height: 44px; min-width: 44px; transform: translate(-50%, -50%);
    }
    .info-hint-btn:hover { background: rgba(56,189,248,0.28); }
    .info-hint-btn:active { transform: scale(0.9); }
    .info-hint-btn:focus-visible { outline: 3px solid var(--sky); outline-offset: 2px; }
    .info-hint-btn[aria-expanded="true"] {
      background: var(--sky); color: #fff;
      box-shadow: 0 0 0 3px rgba(21,101,192,0.25);
    }
    body.theme-night .info-hint-btn { background: rgba(56,189,248,0.2); }
    body.theme-contrast .info-hint-btn, body.theme-contrast-light .info-hint-btn {
      color: var(--bg); background: var(--ink-soft);
    }
    body.theme-contrast .info-hint-btn[aria-expanded="true"],
    body.theme-contrast-light .info-hint-btn[aria-expanded="true"] {
      background: var(--ink); color: var(--bg);
    }
    @media (prefers-reduced-motion: reduce) { .info-hint-btn { transition: none; } }
    .hint.hint-collapsible {
      margin: -2px 0 8px;
    }
    /* Step 3's badge/title and its summary+chevron are separate flex items
       (not one label — see note below), so a full-width memory note inside
       the summary group would otherwise only stretch to that narrow item's
       own width. Force the whole group onto its own full-width line instead,
       so it reads the same as every other collapsed step. */
    .step-summary-group:has(.field-summary-value.is-memory) {
      flex-basis: 100%;
      justify-content: flex-start;
    }
    @keyframes sugarFreeConfirmPop {
      0% { transform: scale(1); }
      45% { transform: scale(1.15); }
      100% { transform: scale(1); }
    }
    @media (prefers-reduced-motion: reduce) {
    }

    /* .drink-branching-box / .drink-branch-title removed 2026-08 — dead
       CSS. The live drink-type buttons render directly inside
       .drink-branch-buttons (still used, kept below); these two were
       styles for an outer wrapper/heading that no longer appears in the
       markup (verified via cross-reference audit). */
        .section-divider {
      font-family: 'Baloo 2', sans-serif; font-size: 1.15rem; font-weight: 800;
      color: var(--sky); margin: 6px 0 12px; padding-bottom: 4px; border-bottom: 2px dashed var(--bg2);
      display: flex; justify-content: space-between; align-items: center;
    }
    /* Lets the Rex icon (added 31 Aug 2026, see index.html's own
       comment above .rex-garden-title-icon) sit vertically centered
       next to the "Rex's Garden" text rather than aligning to the
       text baseline, which would look odd for an image this size. */
    .section-divider span:first-child {
      display: flex; align-items: center; gap: 6px;
    }
    .rex-garden-title-icon {
      /* Height-constrained, not width. Artwork swapped 31 Aug 2026 —
         new upload is a head-and-shoulders crop (aspect ~0.83 w/h),
         replacing the previous full sitting-body art (~0.47 w/h) that
         had been here since v1.4.0/v1.4.1. Height-constraint means
         this swap didn't need a size adjustment: at height:48px the
         new crop is proportionately wider than the old one (since
         it's less tall relative to its width), but stays comfortably
         clear of both "Rex's Garden" text and the star pill — checked
         at both a normal (420px) and the narrowest realistic (320px)
         viewport width before shipping. Same cropping technique as
         every prior Rex asset (tightened the SVG's own viewBox to his
         real silhouette, confirmed genuinely transparent, C2PA
         metadata stripped). */
      height: 48px;
      width: auto;
      display: block;
    }

    /* Sprout Score pill — lives in the Garden card's section-divider (which
       is already display:flex; justify-content:space-between), so no extra
       layout rules needed here beyond the pill's own look. Changed from a
       <span> to a <button> so it can open the score breakdown sheet —
       needs the usual button resets (border, background, font, cursor)
       since it now inherits browser button chrome by default. Uses a
       plain ⭐ emoji, not the Sprout-holding-star illustration — that
       artwork is reserved for the breakdown sheet only, so the small
       pill stays a simple star. */
    .sprout-score-pill {
      position: relative;
      display: inline-flex; align-items: center; gap: 4px;
      font-family: 'Nunito', sans-serif; font-size: 0.82rem; font-weight: 800;
      color: var(--sun-ink, #8A6100);
      background: rgba(255, 201, 60, 0.14);
      border: 1px solid rgba(255, 201, 60, 0.35);
      border-radius: 999px;
      padding: 4px 10px;
      white-space: nowrap;
      cursor: pointer;
      -webkit-tap-highlight-color: transparent;
    }
    .sprout-score-pill:active { transform: scale(0.96); }
    .sprout-score-pop {
      position: absolute; top: -10px; right: -6px;
      font-size: 0.68rem; font-weight: 800; color: var(--mint, #2EC4B6);
      background: rgba(46, 196, 182, 0.18);
      border-radius: 999px; padding: 1px 6px;
      opacity: 0; pointer-events: none;
    }
    .sprout-score-pop-anim {
      animation: sproutScorePop 1.4s ease-out;
    }
    @keyframes sproutScorePop {
      0%   { opacity: 0; transform: translateY(4px) scale(0.85); }
      15%  { opacity: 1; transform: translateY(-2px) scale(1); }
      75%  { opacity: 1; transform: translateY(-8px) scale(1); }
      100% { opacity: 0; transform: translateY(-14px) scale(0.9); }
    }
    @media (prefers-reduced-motion: reduce) {
      .sprout-score-pop-anim { animation: none; opacity: 1; }
    }

    /* Sprout Score breakdown sheet. Reuses .modal-overlay/.modal-content
       from the shared modal system so it inherits the same open/close
       mechanics (display:flex/none) and mobile-safe sizing (max-height,
       overflow-y) as every other modal in the app; everything below is
       purely this sheet's own look. Presented bottom-sheet style via
       align-items:flex-end on this specific overlay, rather than the
       centered dialog most other modals use, since a bottom sheet reads
       better for a "tap a chip, see more" pattern than a centered card. */
    .sprout-score-sheet-overlay { align-items: flex-end; padding: 0; }
    .sprout-score-sheet-content {
      max-width: 440px;
      border-radius: 26px 26px 0 0;
      padding: 18px 20px 26px;
      animation: sproutScoreSheetUp 0.28s ease-out;
    }
    @keyframes sproutScoreSheetUp {
      from { transform: translateY(100%); }
      to { transform: translateY(0); }
    }
    @media (prefers-reduced-motion: reduce) {
      .sprout-score-sheet-content { animation: none; }
    }
    .sprout-score-sheet-content .sheet-handle {
      width: 40px; height: 5px; border-radius: 999px;
      background: var(--dv-line, rgba(255,255,255,0.18));
      opacity: 0.5;
      margin: 0 auto 14px;
    }
    .sprout-score-sheet-sprout-wrap {
      /* `justify-content: center` was still centering the whole
         Sprout+Rex row as a single flex block (confirmed live 1 Sep
         2026 via screenshots — Sprout visibly shifted ~3-4px depending
         on which Rex costume was selected, since a wider costume
         changes the row's total content width, which changes where a
         centered block's midpoint falls). This is exactly the failure
         mode an earlier version of this comment already described and
         intended to avoid, but the fix was never actually applied to
         the CSS below it — the bug persisted until Jon caught it live
         with two side-by-side screenshots.

         Real fix: Sprout's glow is now positioned independently at a
         fixed horizontal center within this wrapper
         (.sprout-score-sheet-glow uses left: 50%; margin-left: -48px,
         half its own 96px width — a self-contained centering method
         that has nothing to do with Rex or flex layout at all), and
         Rex is positioned relative to Sprout's own fixed edge rather
         than being a flex sibling whose width affects a shared center
         point. Sprout's position is now determined ENTIRELY by his own
         box and this wrapper's width — nothing about Rex, whatever
         costume he's wearing, can ever move Sprout again. This wrapper
         itself no longer uses flex for horizontal layout at all
         (position: relative + absolutely-positioned children instead),
         since flex's shared-space model is exactly what caused this
         bug in the first place. */
      position: relative;
      height: 96px;
      margin-bottom: 6px;
    }
    .sprout-score-sheet-glow {
      /* Absolutely positioned and self-centered (left: 50% + negative
         margin-left of half its own width) rather than a flex child —
         this is what actually makes Sprout's position independent of
         Rex's width. `left: 50%` is 50% of THIS GLOW'S OWN CONTAINING
         BLOCK (.sprout-score-sheet-sprout-wrap, since that's
         position:relative), not 50% of some shared flex space that
         Rex's width could ever influence. */
      position: absolute;
      top: 0;
      left: 50%;
      margin-left: -48px; /* half of the 96px width below, to truly center rather than left-align at the 50% mark */
      width: 96px; height: 96px;
      display: flex; align-items: center; justify-content: center;
    }
    .sprout-score-sheet-glow::before {
      content: "";
      position: absolute; inset: -12px;
      border-radius: 50%;
      background: radial-gradient(circle, rgba(255,201,60,0.35), transparent 70%);
      animation: sproutScoreGlowPulse 2.4s ease-in-out infinite;
    }
    @keyframes sproutScoreGlowPulse {
      0%, 100% { opacity: 0.6; transform: scale(0.96); }
      50% { opacity: 1; transform: scale(1.04); }
    }
    @media (prefers-reduced-motion: reduce) {
      .sprout-score-sheet-glow::before { animation: none; opacity: 0.85; }
    }
    .sprout-score-sheet-img {
      width: 96px; height: 96px; position: relative; z-index: 1;
      filter: drop-shadow(0 6px 14px var(--shadow));
    }
    /* Rex sits OUTSIDE the glow, in .sprout-score-sheet-sprout-wrap's
       own flex row, immediately to Sprout's right — NOT a second child
       inside the glow (see .sprout-score-sheet-sprout-wrap's own
       comment for why that approach puts the glow off-center). Sized
       to 22px — small enough to read as a secondary character rather
       than competing with Sprout for visual weight. Full-body artwork
       (images/rex-fullbody.svg, a dedicated copy separate from
       images/rex.svg's head-and-shoulders crop used in the
       garden-title spot). Vertical alignment is a margin-top offset,
       not a simple box-edge match — see .sprout-score-sheet-rex-img's
       own comment for the full reasoning and the alpha-channel
       measurements it's based on. */
    /* .sprout-score-sheet-rex-frame is the actual flex item now (Rex's
       <img> moved one level deeper — see index.html's comment on this
       markup for the full history of why). This wrapper carries the
       margin-top/margin-left that used to live directly on
       .sprout-score-sheet-rex-img (that offset's own reasoning — the
       alpha-channel measurements, Sprout's visible-vs-box-bottom
       mismatch — is unchanged, just documented on
       .sprout-score-sheet-rex-img below where the underlying numbers
       still apply). width/height match Rex's own rendered size exactly
       (22px / auto, same aspect ratio) since this wrapper's only
       purpose is to be "Rex's box" for the tail to size itself against.
       position: relative makes this a valid anchor for the
       absolutely-positioned tail wrapper inside it — the bug this
       replaced was trying to anchor against .sprout-score-sheet-sprout-wrap
       instead, which had no position:relative of its own and wasn't
       sized to Rex specifically anyway. */
    .sprout-score-sheet-rex-frame {
      /* Positioned absolutely, anchored to the glow's own right edge
         (left: 50% + half the glow's 96px width + the small gap/margin
         that used to come from flex's margin-left: -8px) rather than
         flex flow — this is the change that actually stops Rex's own
         width (which varies per costume — see setRexCostume() in
         js/sprout-score.js) from ever being able to shift Sprout's
         position again. Sprout's glow computes its own center purely
         from ITS OWN box; Rex sits at a fixed offset from that same
         fixed point regardless of how wide Rex himself renders. */
      position: absolute;
      top: 35.1px;
      left: calc(50% + 40px); /* 48px (half glow width) - 8px (the old margin-left gap, kept identical for the same visual spacing) */
      width: 22px; height: auto;
    }
    /* #rexTailWag is positioned/sized/animated entirely by
       js/sprout-score.js (see REX_TAIL_WAG_FRAMES and startRexTailWag())
       — each of the 7 steps sets left/top/width/height/transform-origin/
       rotation directly via inline style, since the animation needs to
       swap which <img> src is showing (tail-a vs tail-b) at the
       midpoint, which a CSS-only @keyframes animation cannot do (it can
       only animate properties of ONE element/image, not swap the image
       itself). This CSS rule only sets what's true at every step:
       position:absolute so left/top are meaningful, and z-index:0 to
       keep it behind .sprout-score-sheet-rex-img (z-index:1) so the
       base tucks behind Rex's hip at every step of the sweep. */
    #rexTailWag {
      position: absolute;
      z-index: 0;
      pointer-events: none;
    }
    #rexTailWag img {
      width: 100%; height: 100%; display: block;
    }
    .sprout-score-sheet-rex-img {
      /* margin-top aligns Rex's visible bottom with Sprout's visible
         bottom — NOT with Sprout's box bottom, which is a different
         point. images/sprout-star.svg has real trailing whitespace
         below the drawn artwork: the visible content only extends to
         ~85.3% of the canvas height (measured via alpha-channel
         inspection: content bottom at row 853 of a 1000px-tall
         render). Matching box edges therefore doesn't match visible
         edges — Sprout's box bottom sits well below where he's
         actually visibly standing. images/rex-fullbody.svg has no
         such padding (visible content reaches 99.2% of its canvas),
         so its box bottom and visible bottom are effectively the same
         point.

         The offset: at Sprout's 96px rendered box height, his visible
         bottom sits at 96 * 0.853 ≈ 81.9px from the top of his box.
         Rex at 22px wide renders ≈46.8px tall (his aspect ratio,
         ~0.47 w/h). Top-aligned, Rex's own bottom would land at
         46.8px — 35.1px short of Sprout's visible bottom — hence
         margin-top: 35.1px pushes his bottom down to match.

         General rule for multi-character SVG alignment in this
         project: check with alpha-channel bounding-box inspection
         whether an asset's box edge matches its visible content edge
         before aligning by box coordinates alone —
         getBoundingClientRect() only reports the box, and a box match
         can still look visibly wrong if either asset has invisible
         padding.

         NOTE (1 Sep 2026): margin-top/margin-left themselves moved up
         to .sprout-score-sheet-rex-frame, the new wrapper one level up
         (see that rule above and index.html's comment on this markup),
         since the tail needs to share Rex's exact positioned box and
         two separate elements each carrying their own copy of the same
         offset is a duplication bug waiting to happen if either one is
         ever tuned without the other. The reasoning/measurements above
         are unchanged and still the source of truth for the number —
         it just lives one element higher now. */
      width: 22px; height: auto; position: relative; z-index: 1;
      filter: drop-shadow(0 6px 14px var(--shadow));
    }
    /* Rex costume picker (added 1 Sep 2026, rebuilt 2 Sep 2026 into a
       horizontally-scrollable strip of real costume thumbnails — see
       index.html's own comment on this markup for the full history of
       why the two earlier versions, a native <select> and then a
       pill+popover menu, were each replaced). Designed for a growing
       list, not just today's seven costumes — Jon's plan is to keep
       adding more — so the strip scrolls horizontally rather than
       wrapping or growing the sheet's own height, and each thumbnail
       is a generic .rex-costume-thumb with no per-costume styling, so
       adding the 50th costume needs zero new CSS, only a new button
       element (see index.html) and a REX_COSTUMES entry in
       js/sprout-score.js.

       Visual language matches this file's other pill/card surfaces
       (rounded corners, soft tinted backgrounds, thin colored borders)
       rather than introducing a one-off style. */
    .sprout-score-sheet-rex-costume-picker {
      margin-top: 8px;
      margin-bottom: 4px;
      position: relative;
    }
    .rex-costume-strip {
      display: flex;
      gap: 10px;
      overflow-x: auto;
      /* Padding on the sides (not just between items) so the first and
         last thumbnails don't sit flush against the sheet's own edge —
         matches the sheet's own 20px side padding
         (.sprout-score-sheet-content) so the strip visually aligns
         with everything else in it. */
      padding: 4px 20px 8px;
      margin: 0 -20px; /* pulls the strip back out to the sheet's full width so its own padding above can still create edge breathing room without double-indenting */
      scroll-snap-type: x proximity;
      -webkit-overflow-scrolling: touch;
      /* No visible scrollbar at all (reworked 2 Sep 2026 — Jon: "that
         scrollbar under the costumes is a travesty"). A bare
         browser-default scroll track looked out of place against this
         app's own warm, rounded, colorful style regardless of how its
         thickness/color were tuned — this sandbox's own Chromium
         wasn't even rendering the earlier ::-webkit-scrollbar rules
         consistently with what Jon saw on a real Android device, which
         is reason enough not to keep tuning a scrollbar's appearance
         instead of just removing it. Scrollability itself is
         communicated instead by the edge-fade gradient below and, more
         importantly, by Captain Canine/Rex-o-naut etc. visibly peeking
         in from the right edge at rest — the same "there's more, keep
         scrolling" cue app store screenshots and story pickers use,
         needing no scrollbar affordance at all. */
      scrollbar-width: none; /* Firefox */
      -ms-overflow-style: none; /* old Edge/IE */
    }
    .rex-costume-strip::-webkit-scrollbar { display: none; } /* Chrome/Safari/Android WebView */
    /* Fade-to-transparent gradient over the strip's right edge, hinting
       there's more to scroll past what's visible — fades out entirely
       once scrolled near the end so it doesn't look like a stray edge
       once every costume has been seen. Purely decorative (no pointer-
       events), sits above the strip via z-index. */
    .rex-costume-picker-fade {
      position: absolute;
      top: 4px;
      right: 0;
      bottom: 8px;
      width: 28px;
      /* Fades to var(--card) — the sheet's own actual background
         (.modal-content { background: var(--card); }), not an invented
         color — so this genuinely blends into the sheet rather than
         showing as its own visible edge. */
      background: linear-gradient(90deg, transparent, var(--card) 85%);
      pointer-events: none;
      opacity: 1;
      transition: opacity 0.15s ease;
    }
    .rex-costume-picker-fade[hidden] { display: none; }

    /* Full-screen costume preview overlay (added 2 Sep 2026). Fixed to
       the viewport (not the sheet) so it genuinely covers the whole
       screen regardless of how far the sheet itself has scrolled —
       this is a step above the Sprout Score sheet, not scoped inside
       it, since the sheet is a bottom-anchored panel that doesn't
       itself fill the screen. z-index deliberately higher than this
       app's other modal layers (checked against .modal-overlay's own
       z-index before picking this value) so it can open from within
       the already-open Sprout Score sheet without being hidden behind
       it. */
    .rex-costume-preview {
      position: fixed;
      inset: 0;
      /* Must sit above .modal-overlay (z-index: 100, used by the
         Sprout Score sheet itself via .sprout-score-sheet-overlay) —
         confirmed by actually checking that rule rather than assuming
         a number, since this preview opens FROM WITHIN that already-open
         sheet and needs to render on top of it, not behind. */
      z-index: 110;
      background: rgba(10, 12, 26, 0.94);
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .rex-costume-preview[hidden] { display: none; }
    .rex-costume-preview-close {
      position: absolute;
      top: 16px; right: 16px;
      width: 36px; height: 36px;
      border-radius: 50%;
      background: rgba(255, 255, 255, 0.1);
      border: 1px solid rgba(255, 255, 255, 0.2);
      color: #fff;
      font-size: 1.1rem;
      line-height: 1;
      cursor: pointer;
      -webkit-tap-highlight-color: transparent;
    }
    .rex-costume-preview-arrow {
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      width: 44px; height: 44px;
      border-radius: 50%;
      background: rgba(255, 255, 255, 0.1);
      border: 1px solid rgba(255, 255, 255, 0.2);
      color: #fff;
      font-size: 1.6rem;
      line-height: 1;
      cursor: pointer;
      -webkit-tap-highlight-color: transparent;
    }
    .rex-costume-preview-arrow:active { transform: translateY(-50%) scale(0.92); }
    .rex-costume-preview-arrow-left { left: 12px; }
    .rex-costume-preview-arrow-right { right: 12px; }
    /* Hidden (rather than disabled) at either end of the costume list
       — REX_COSTUMES has a fixed order and cycling doesn't wrap, so
       there's genuinely nothing to go back/forward to at the ends;
       hiding the arrow communicates that more directly than a merely
       greyed-out one still sitting there. */
    .rex-costume-preview-arrow[hidden] { display: none; }
    .rex-costume-preview-body {
      display: flex;
      flex-direction: column;
      align-items: center;
      max-width: 320px;
      padding: 0 24px;
    }
    .rex-costume-preview-name {
      font-family: 'Baloo 2', sans-serif;
      font-size: 1.2rem;
      font-weight: 800;
      color: var(--sun, #FFC93C);
      margin-bottom: 16px;
      text-align: center;
    }
    .rex-costume-preview-img {
      width: 200px;
      height: auto;
      max-height: 50vh;
      /* object-fit isn't needed here the way it might be for a fixed
         box — width:200px with height:auto lets each costume's own
         natural aspect ratio (see setRexCostume()'s height-matching
         logic elsewhere) determine its displayed height directly,
         same principle as the thumbnails, just at a much larger size. */
      filter: drop-shadow(0 10px 30px rgba(0, 0, 0, 0.5));
    }
    .rex-costume-preview-actions {
      display: flex;
      gap: 12px;
      margin-top: 28px;
    }
    .rex-costume-preview-cancel,
    .rex-costume-preview-select {
      padding: 12px 24px;
      border-radius: 999px;
      font-family: 'Nunito', sans-serif;
      font-weight: 700;
      font-size: 0.9rem;
      cursor: pointer;
      -webkit-tap-highlight-color: transparent;
      white-space: nowrap;
    }
    .rex-costume-preview-cancel {
      background: rgba(255, 255, 255, 0.08);
      border: 1px solid rgba(255, 255, 255, 0.25);
      color: #fff;
    }
    .rex-costume-preview-select {
      background: var(--sun, #FFC93C);
      border: none;
      color: #1a1a2e;
      font-weight: 800;
    }
    .rex-costume-preview-cancel:active,
    .rex-costume-preview-select:active { transform: scale(0.96); }

    .rex-costume-thumb {
      flex: 0 0 auto;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 4px;
      width: 60px;
      background: none;
      border: none;
      padding: 0;
      cursor: pointer;
      -webkit-tap-highlight-color: transparent;
      scroll-snap-align: start;
    }
    .rex-costume-thumb-img {
      width: 52px;
      height: 52px;
      border-radius: 14px;
      background: var(--card);
      border: 2px solid rgba(255, 201, 60, 0.25);
      display: flex;
      align-items: center;
      justify-content: center;
      overflow: hidden;
      transition: border-color 0.15s ease, transform 0.1s ease;
    }
    .rex-costume-thumb-img img {
      /* Each costume's own art has a different natural aspect ratio
         (see setRexCostume()'s height-matching logic in
         js/sprout-score.js) — height:100% + width:auto here lets each
         thumbnail's image fill the circle vertically and center itself
         horizontally via the parent's flex centering, rather than
         stretching every costume to a fixed square and distorting the
         ones that aren't naturally square. */
      height: 100%;
      width: auto;
      max-width: none;
    }
    .rex-costume-thumb:active .rex-costume-thumb-img {
      transform: scale(0.94);
    }
    .rex-costume-thumb[aria-current="true"] .rex-costume-thumb-img {
      border-color: var(--sun, #FFC93C);
      background: rgba(255, 201, 60, 0.12);
    }
    .rex-costume-thumb-label {
      font-family: 'Nunito', sans-serif;
      font-size: 0.62rem;
      font-weight: 700;
      color: var(--ink);
      text-align: center;
      line-height: 1.15;
      /* Two lines max, ellipsis after — costume names vary a lot in
         length ("Rex" vs "Captain Canine") and the thumbnail column is
         narrow; wrapping to 2 lines handles most names cleanly without
         needing per-name width tuning, and anything longer still
         degrades gracefully rather than breaking the layout. */
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
      overflow: hidden;
    }
    .rex-costume-thumb[aria-current="true"] .rex-costume-thumb-label {
      color: var(--sun-ink, #8A6100);
    }
    .sprout-score-sheet-header {
      display: flex; align-items: center; justify-content: space-between;
      margin-bottom: 2px;
    }
    .sprout-score-sheet-header h3 {
      font-family: 'Baloo 2', sans-serif; font-size: 1.2rem; font-weight: 800;
      margin: 0; color: var(--ink);
    }
    .sprout-score-sheet-content .sheet-close {
      background: var(--dv-surface, rgba(255,255,255,0.08)); border: none;
      color: var(--ink-soft); width: 30px; height: 30px; border-radius: 50%;
      font-size: 1rem; cursor: pointer; flex-shrink: 0;
    }
    .sprout-score-sheet-total { text-align: center; margin: 2px 0 20px; }
    .sprout-score-sheet-bignum {
      font-family: 'Baloo 2', sans-serif;
      font-size: 2.6rem; font-weight: 800; line-height: 1;
      background: linear-gradient(135deg, var(--sun, #FFC93C), #ffe08a);
      -webkit-background-clip: text; background-clip: text; color: transparent;
    }
    .sprout-score-sheet-sub {
      font-size: 0.78rem; color: var(--ink-soft); font-weight: 600; margin-top: 6px;
    }
    .sprout-score-breakdown-list { display: flex; flex-direction: column; gap: 10px; margin-bottom: 4px; }
    .sprout-score-breakdown-row {
      position: relative;
      display: flex; align-items: center; gap: 12px;
      background: var(--dv-surface, rgba(255,255,255,0.045));
      border: 1px solid var(--dv-line, rgba(255,255,255,0.09));
      border-radius: 16px;
      padding: 12px 14px 12px 16px;
      overflow: hidden;
    }
    .sprout-score-breakdown-row::before {
      content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
    }
    .sprout-score-breakdown-row.log::before { background: var(--mint); }
    .sprout-score-breakdown-row.scan::before { background: var(--sky); }
    .sprout-score-breakdown-row.badge::before { background: var(--sun); }
    .sprout-score-breakdown-icon {
      width: 42px; height: 42px; border-radius: 13px;
      display: flex; align-items: center; justify-content: center;
      font-size: 1.35rem; flex-shrink: 0;
      box-shadow: inset 0 0 0 1px var(--dv-line, rgba(255,255,255,0.06));
    }
    .sprout-score-breakdown-icon.log { background: rgba(46,196,182,0.16); }
    .sprout-score-breakdown-icon.scan { background: rgba(63,169,245,0.16); }
    .sprout-score-breakdown-icon.badge { background: rgba(255,201,60,0.16); }
    .sprout-score-breakdown-main { flex: 1; min-width: 0; }
    .sprout-score-breakdown-label { font-weight: 800; font-size: 0.92rem; color: var(--ink); }
    .sprout-score-breakdown-sub { font-size: 0.7rem; color: var(--ink-soft); font-weight: 600; margin-top: 1px; }
    .sprout-score-breakdown-value { text-align: right; flex-shrink: 0; }
    .sprout-score-breakdown-points { font-weight: 800; font-size: 1.05rem; color: var(--sun-ink, #8A6100); }
    .sprout-score-breakdown-count { font-size: 0.66rem; color: var(--ink-soft); font-weight: 700; }
    .sprout-score-breakdown-bar-track {
      height: 5px; border-radius: 999px; background: var(--dv-inset, rgba(255,255,255,0.08));
      margin-top: 18px; overflow: hidden; display: flex;
    }
    .sprout-score-breakdown-bar-seg.log { background: var(--mint); }
    .sprout-score-breakdown-bar-seg.scan { background: var(--sky); }
    .sprout-score-breakdown-bar-seg.badge { background: var(--sun); }
    .sprout-score-breakdown-bar-caption {
      display: flex; justify-content: space-between; margin-top: 6px;
      font-size: 0.64rem; color: var(--ink-soft); font-weight: 700;
    }
    .sprout-score-sheet-footer-note {
      text-align: center; font-size: 0.7rem; color: var(--ink-soft); font-weight: 600;
      margin-top: 16px; line-height: 1.4;
    }
    .header-reset-btn {
      background: var(--bg); border: 2px solid var(--bg2); color: var(--ink-soft);
      font-family: 'Nunito', sans-serif; font-weight: 800; font-size: 1.2rem;
      cursor: pointer; padding: 4px 9px; line-height: 1; border-radius: 10px;
      transition: all 0.2s, transform 0.4s ease;
    }
    
    @media (hover: hover) {
      .header-reset-btn:hover { color: var(--berry); border-color: var(--berry); }
    }
    .header-reset-btn:active { color: var(--berry); border-color: var(--berry); }

    @keyframes iconSpin {
      0% { transform: rotate(0deg); color: var(--berry); border-color: var(--berry); }
      100% { transform: rotate(-360deg); color: var(--ink-soft); border-color: var(--bg2); }
    }
    .header-reset-btn.spin-anim {
      animation: iconSpin 0.5s ease-out;
    }

    body.theme-night .header-reset-btn { background: #1B2140; border-color: #262C52; }

    .header-reset-btn.reset-text-btn {
      font-size: 0.76rem; font-weight: 800; padding: 6px 12px;
      letter-spacing: 0.01em;
      position: relative;
    }
    /* Touch-target fix: the visual pill is ~32px tall, below the 44px
       convention — risky for a destructive, no-confirmation action sitting
       right next to the section title. Same invisible-hitbox trick as
       .info-hint-btn's own ::before: keeps the compact pill look, makes the
       actual tappable area 44px.
       TO REVERT: delete this ::before block. */
    .header-reset-btn.reset-text-btn::before {
      content: ''; position: absolute; top: 50%; left: 50%;
      width: 100%; height: 44px; min-width: 44px; transform: translate(-50%, -50%);
    }
    @keyframes textResetPulse {
      0% { color: var(--berry); border-color: var(--berry); transform: scale(1.08); }
      100% { color: var(--ink-soft); border-color: var(--bg2); transform: scale(1); }
    }
    .header-reset-btn.reset-text-btn.spin-anim {
      animation: textResetPulse 0.35s ease-out;
    }

    .fluid-toggle-zone {
      margin: 14px 0 4px;
    }

    /* Bumped from a small pill "invitation" to full CTA weight — a
       small pill read as an afterthought rather than a real option.
       Dashed border instead of solid keeps it visually distinct from
       the solid "Add food" button above (still secondary in the
       food+drink hierarchy) while matching it in size and padding, so
       it reads as a real second station rather than a footnote link.
       Bubbles and gradient fill kept from the original design — same
       glass-of-something-fizzy identity, just given room to be seen. */
    .add-fluid-trigger-btn {
      position: relative;
      overflow: hidden;
      isolation: isolate;
      width: 100%;
      background: linear-gradient(180deg,
        rgba(63, 169, 245, 0.16) 0%,
        rgba(63, 169, 245, 0.06) 55%,
        rgba(63, 169, 245, 0.13) 100%);
      border: 2px dashed rgba(63, 169, 245, 0.55);
      border-radius: 18px;
      color: var(--sky);
      padding: 16px 20px;
      font-family: 'Baloo 2', sans-serif;
      font-weight: 800;
      font-size: 1.05rem;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
      text-decoration: none;
      transition: transform 0.18s ease, box-shadow 0.25s ease, border-color 0.25s ease;
      box-shadow: 0 2px 10px rgba(63, 169, 245, 0.14),
                  inset 0 1px 0 rgba(255, 255, 255, 0.35);
    }
    .afb-label { position: relative; z-index: 2; }
    body.theme-night .add-fluid-trigger-btn {
      background: linear-gradient(180deg,
        rgba(63, 169, 245, 0.24) 0%,
        rgba(63, 169, 245, 0.10) 55%,
        rgba(63, 169, 245, 0.20) 100%);
      border-color: rgba(63, 169, 245, 0.55);
      box-shadow: 0 2px 12px rgba(63, 169, 245, 0.20),
                  inset 0 1px 0 rgba(255, 255, 255, 0.12);
    }
    .add-fluid-trigger-btn:hover {
      border-color: var(--sky);
      box-shadow: 0 4px 16px rgba(63, 169, 245, 0.26),
                  inset 0 1px 0 rgba(255, 255, 255, 0.4);
      transform: translateY(-1px);
    }
    .add-fluid-trigger-btn:active { transform: scale(0.98); }
    .add-fluid-trigger-btn:focus-visible { outline: 3px solid var(--sun); outline-offset: 3px; }

    .add-fluid-subtext {
      text-align: center;
      font-size: 0.72rem;
      font-weight: 700;
      color: var(--ink-soft);
      margin: 8px 0 4px;
    }

    /* ---- bubbles, confined to the button ---------------------------- */
    .afb-fizz {
      position: absolute;
      inset: 0;
      z-index: 1;
      pointer-events: none;
      overflow: hidden;
      border-radius: inherit;
    }
    /* On a dark card a white rim reads as a bubble's highlight. On the light
       themes it disappears into the background, so those get a sky-tinted
       rim and a slightly stronger fill instead — same bubble, drawn for the
       surface it's actually sitting on. */
    .afb-bubble {
      position: absolute;
      bottom: -12px;
      border-radius: 50%;
      background: rgba(63, 169, 245, 0.22);
      border: 1.5px solid rgba(63, 169, 245, 0.55);
      animation: afbRise linear infinite;
      opacity: 0;
    }
    body.theme-night .afb-bubble {
      background: rgba(46, 196, 182, 0.20);
      border-color: rgba(255, 255, 255, 0.45);
    }
    body.theme-rainbow .afb-bubble {
      background: rgba(233, 30, 99, 0.16);
      border-color: rgba(233, 30, 99, 0.5);
    }
    body.theme-contrast .afb-bubble {
      background: transparent;
      border-color: rgba(255, 255, 255, 0.7);
    }
    body.theme-contrast-light .afb-bubble {
      background: transparent;
      border-color: rgba(0, 0, 0, 0.55);
    }

    /* Hand-placed rather than random: nine bubbles across the width on
       mismatched durations and delays, so the loop never visibly repeats in
       step the way an evenly-spaced set does. */
    .afb-bubble:nth-child(1) { left: 7%;  width: 7px; height: 7px; animation-duration: 3.4s; animation-delay: 0s;   --afb-drift: 5px; }
    .afb-bubble:nth-child(2) { left: 17%; width: 4px; height: 4px; animation-duration: 2.6s; animation-delay: 1.1s; --afb-drift: -4px; }
    .afb-bubble:nth-child(3) { left: 28%; width: 9px; height: 9px; animation-duration: 4.1s; animation-delay: 0.5s; --afb-drift: 7px; }
    .afb-bubble:nth-child(4) { left: 39%; width: 5px; height: 5px; animation-duration: 3.0s; animation-delay: 2.0s; --afb-drift: -6px; }
    .afb-bubble:nth-child(5) { left: 50%; width: 6px; height: 6px; animation-duration: 2.9s; animation-delay: 0.3s; --afb-drift: 4px; }
    .afb-bubble:nth-child(6) { left: 61%; width: 8px; height: 8px; animation-duration: 3.7s; animation-delay: 1.5s; --afb-drift: -5px; }
    .afb-bubble:nth-child(7) { left: 72%; width: 4px; height: 4px; animation-duration: 2.4s; animation-delay: 0.8s; --afb-drift: 3px; }
    .afb-bubble:nth-child(8) { left: 83%; width: 7px; height: 7px; animation-duration: 3.3s; animation-delay: 2.2s; --afb-drift: -4px; }
    .afb-bubble:nth-child(9) { left: 92%; width: 5px; height: 5px; animation-duration: 2.7s; animation-delay: 1.3s; --afb-drift: 6px; }

    @keyframes afbRise {
      0%   { transform: translateY(0) translateX(0) scale(0.6); opacity: 0; }
      15%  { opacity: 0.85; }
      80%  { opacity: 0.7; }
      100% { transform: translateY(-64px) translateX(var(--afb-drift, 5px)) scale(1); opacity: 0; }
    }

    /* Motion is decoration here, so it goes entirely rather than slowing
       down — a still glass reads fine. */
    @media (prefers-reduced-motion: reduce) {
      .afb-fizz { display: none; }
      .add-fluid-trigger-btn:hover { transform: none; }
    }
    
    .fluid-collapsible-content {
      display: none;
      /* Was the generic `pop` scale/fade — swapped for a slide-down-and-
         settle (18 Aug 2026) so a conscious tap ("Add a drink to this
         meal") reads as something arriving, not just fading in place.
         Existing scroll-to-station logic (scrollDrinkStationBelowTopbar)
         is untouched; this only changes how the section looks once it's
         in view. */
      animation: drinkStationReveal 0.5s cubic-bezier(.25,.8,.35,1);
      margin-top: 10px;
      scroll-margin-top: 16px; /* land with a little breathing room, not flush to the top edge */
    }
    @keyframes drinkStationReveal {
      0%   { opacity: 0; transform: translateY(-16px) scale(0.97); }
      100% { opacity: 1; transform: translateY(0) scale(1); }
    }
    /* A brief ring around the station itself, on top of the slide, so the
       eye is drawn straight to it rather than having to notice a general
       layout shift. Fades to nothing well within a second. */
    .drinks-v2 {
      border-radius: 20px;
      animation: drinkStationFocusRing 1.1s ease-out;
    }
    @keyframes drinkStationFocusRing {
      0%   { box-shadow: 0 0 0 3px rgba(63, 169, 245, 0.55); }
      100% { box-shadow: 0 0 0 3px rgba(63, 169, 245, 0); }
    }
    @media (prefers-reduced-motion: reduce) {
      .fluid-collapsible-content, .drinks-v2 { animation: none; }
    }
    .fluid-section-header-row {
      display: flex;
      align-items: center;
      justify-content: space-between;
    }
    .stepper-row { display: flex; align-items: center; gap: 8px; }
    .stepper-row[hidden] { display: none; }
    .step-btn {
      width: 38px; height: 38px; border-radius: 12px; border: none;
      background: var(--sprout-green); color: #FFFFFF; font-size: 19px; font-weight: 800;
      cursor: pointer; flex: 0 0 auto;
      box-shadow: 0 3px 0 rgba(0,0,0,0.16);
      user-select: none; -webkit-user-select: none;
      line-height: 1;
    }
    .step-btn:active { transform: translateY(2px); box-shadow: none; }
    /* +/- are a matched pair; the sign carries the meaning, not the colour. */
    .step-btn.minus { background: var(--sprout-green); color: #FFFFFF; }
    .value-box {
      flex: 1; text-align: center; background: var(--bg); border-radius: 12px; padding: 6px 6px;
      border: 1.5px solid transparent; transition: border-color 0.15s ease, box-shadow 0.15s ease;
    }
    .value-box.field-focused {
      border-color: var(--sprout-green); box-shadow: 0 0 0 3px var(--sprout-green-tint);
    }
    body.theme-night .value-box { background: #1B2140; }
    body.theme-caregiver .value-box { background: #F0F9FF; }
    .value-box input {
      width: 100%; border: none; background: transparent; text-align: center;
      font-family: 'Baloo 2', sans-serif; font-size: 1.3rem; font-weight: 700;
      color: var(--ink); outline: none;
    }
    .value-box input::-webkit-outer-spin-button,
    .value-box input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
    .value-box input[type=number] { -moz-appearance: textfield; }
    .value-box .unit { font-size: 0.68rem; color: var(--ink-soft); font-weight: 700; letter-spacing: .03em; }
    /* Carbs-per-100g box: the number and its 'g' sit together as one group so
       the unit reads at a glance, while the caption below still wraps onto
       its own line underneath (unchanged from the plain value-box). */
    .value-box-suffixed { display: flex; flex-wrap: wrap; justify-content: center; align-items: baseline; }
    .value-box-suffixed input { width: auto; min-width: 0; flex: 0 1 auto; padding-right: 0; text-align: right; }
    .value-box-suffixed .value-suffix {
      font-family: 'Baloo 2', sans-serif; font-size: 1rem; font-weight: 700; color: var(--ink-soft);
      margin-left: 1px;
    }
    .value-box-suffixed .unit { flex-basis: 100%; margin-top: 2px; }
    
    .preset-row { display: flex; gap: 4px; margin-top: 8px; justify-content: space-between; align-items: center; width: 100%; }
    .preset-row[hidden] { display: none; }
    .preset-btn {
      flex: 1; background: var(--bg); border: 2px solid var(--bg2); color: var(--ink);
      padding: 8px 2px; border-radius: 10px; font-size: 0.8rem; font-weight: 800; cursor: pointer;
      text-align: center; min-width: 0;
      /* Object-style chips (Carton/Can/Glass/Bottle/Big cup), matching the
         approved mockup's VOLS pattern — icon + name + ml as fine print,
         not a bare number. Milk in a bottle and juice in a carton read
         differently even at the same volume; naming the container is more
         recognisable at a glance than a number is. */
      display: flex; flex-direction: column; align-items: center; gap: 2px; white-space: nowrap;
    }
    .preset-btn-icon { font-size: 1.1rem; line-height: 1; }
    .preset-btn-name { font-size: 0.72rem; }
    .preset-btn-sub { font-size: 0.62rem; font-weight: 700; color: var(--ink-soft); }
    .preset-btn.active .preset-btn-sub { color: rgba(255,255,255,0.85); }
    body.theme-night .preset-btn { background: #1B2140; border-color: #262C52; }
    .preset-btn.active { background: var(--sky); color: white; border-color: var(--sky); }
    body.theme-night .preset-btn.active { background: var(--sky); color: white; border-color: var(--sky); }

    .go-btn {
      width: 100%; border: none; padding: 16px;
      background: linear-gradient(135deg, var(--sprout-green), var(--sprout-green-deep));
      color: white; font-family: 'Baloo 2', sans-serif; font-weight: 700; font-size: 1.15rem;
      border-radius: 18px; cursor: pointer;
      box-shadow: 0 8px 18px rgba(0,89,78,0.32);
      /* The result panel sits directly above this button in both stations,
         and with no top margin the two were flush — a big green slab welded
         to the total, which read as one control rather than "here's the
         answer, now add it". 12px matches the drinks button's own gap. */
      margin-top: 12px;
      margin-bottom: 4px;
      /* Fix for a thin flickering horizontal line across this
         button's text — same flicker pattern seen on the mascot SVG.
         Cause: the box-shadow + rounded corners here,
         combined with the opacity change on :disabled firing every time
         Step 1's answer state changes, was making the browser repeatedly
         promote/demote this element to and from its own GPU compositing
         layer. The flicker is the seam at that layer's edge failing to
         line up cleanly frame-to-frame during the flip-flop. Forcing a
         stable layer up front (rather than letting the browser decide on
         the fly) stops the flip-flop and the seam with it. Purely a
         rendering hint — no visual or behavioural change otherwise.
         See mascot-avatar-wrap below for the same fix on the other
         reported element. */
      transform: translateZ(0);
      backface-visibility: hidden;
    }
    .go-btn:active { transform: scale(0.98); }
    /* The step badge is normally green-on-white (to sit inside a light label);
       inverted here so it still reads clearly against the button's own green. */
    .step-badge-on-btn {
      background: rgba(255,255,255,0.92); color: var(--sprout-green-deep);
    }
    .go-btn:disabled {
      opacity: 0.45; cursor: not-allowed; box-shadow: none;
    }
    .go-btn.shake { animation: goBtnShake 0.45s ease; }
    @keyframes goBtnShake {
      0%, 100% { transform: translateX(0); }
      20% { transform: translateX(-6px); }
      40% { transform: translateX(5px); }
      60% { transform: translateX(-3px); }
      80% { transform: translateX(2px); }
    }
    @media (prefers-reduced-motion: reduce) {
      .go-btn.shake { animation: none; }
    }
    
    /* Drinks are blue — a meaningful, calmer secondary to the green food flow. */
    .drink-go-btn {
      background: linear-gradient(135deg, var(--sky), #0D47A1);
      box-shadow: 0 8px 18px rgba(21,101,192,0.3);
    }
    body.theme-night .drink-go-btn { background: linear-gradient(135deg, var(--sky), #1565C0); }

    /* Live running total — updates as the child types, so the number moves with them. */
    .live-preview {
      display: flex;
      align-items: baseline;
      justify-content: center;
      gap: 8px;
      margin: 14px 0 10px;
      padding: 12px 16px;
      border-radius: var(--radius-md);
      background: var(--sprout-green-tint);
      border: 2px dashed rgba(14,140,122,0.35);
      transition: opacity 0.2s ease;
      text-align: center;
      flex-wrap: wrap;
    }
    body.theme-night .live-preview { border-color: rgba(46,196,182,0.4); }
    .live-preview.is-empty { opacity: 0.7; }
    .live-preview-label {
      font-family: 'Nunito', sans-serif; font-weight: 800; font-size: 0.9rem;
      color: var(--ink-soft);
    }
    .live-preview-num {
      font-family: 'Baloo 2', sans-serif; font-weight: 800; font-size: 2rem;
      line-height: 1; color: var(--sprout-green);
      transition: transform 0.18s cubic-bezier(0.175,0.885,0.32,1.4);
    }
    body.theme-night .live-preview-num { color: #2EC4B6; }
    body.theme-contrast .live-preview-num, body.theme-contrast-light .live-preview-num { color: var(--ink); }
    .live-preview-num.bump { transform: scale(1.18); }
    .live-preview-unit {
      font-family: 'Baloo 2', sans-serif; font-weight: 700; font-size: 0.9rem;
      color: var(--ink-soft);
    }
    .live-preview .live-preview-hint {
      font-family: 'Nunito', sans-serif; font-weight: 700; font-size: 0.9rem;
      color: var(--ink-soft); width: 100%;
    }
    @media (prefers-reduced-motion: reduce) {
      .live-preview-num { transition: none; }
    }

    /* Label helper — shows kids exactly which number to copy off the food label. */
    .label-helper {
      display: flex; align-items: center; gap: 10px;
      margin: 4px 0 6px;
      padding: 8px 10px;
      background: var(--bg);
      border: 1.5px solid var(--bg2);
      border-radius: 12px;
    }
    body.theme-night .label-helper { background: #1B2140; border-color: #262C52; }
    .label-helper svg { flex: 0 0 auto; display: block; }
    .label-helper-text {
      font-family: 'Nunito', sans-serif; font-weight: 700; font-size: 0.78rem;
      color: var(--ink-soft); line-height: 1.35; text-align: left;
    }
    .label-helper-text b { color: var(--sprout-green); }
    body.theme-night .label-helper-text b { color: #2EC4B6; }

    /* Progress ring around the mascot showing how close the child is to the next level. */
    .mascot-avatar-wrap::before {
      content: "";
      position: absolute;
      inset: -4px;
      border-radius: 50%;
      background: conic-gradient(var(--sprout-green) calc(var(--level-progress, 0) * 1%), rgba(31,42,68,0.14) 0);
      -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
              mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
      z-index: 0;
      pointer-events: none;
      transition: background 0.4s ease;
    }
    body.theme-night .mascot-avatar-wrap::before {
      background: conic-gradient(#2EC4B6 calc(var(--level-progress, 0) * 1%), rgba(255,255,255,0.14) 0);
    }
    .mascot-avatar-wrap.ring-maxed::before {
      background: conic-gradient(var(--sun) 100%, var(--sun) 0);
    }
    .greeting-mascot { position: relative; z-index: 1; }
    /* Invisible expanded hit area so small fingers can tap the level badge
       reliably — kept smaller than before (was -9px) since the badge now
       sits further from the mascot; a bigger expansion here would just eat
       back into Sprout's tap area from the new position. */
    .level-badge-btn::before {
      content: "";
      position: absolute;
      inset: -6px;
      border-radius: 50%;
    }

    /* ---- Emoji plate builder ---- */
    .food-emoji-picker { margin: 6px 0 14px; }

    /* ---- Progressive disclosure: collapse a step's body once it's answered,
       reusing the step's own existing header as the tap target rather than
       adding a duplicate summary bar. Nothing about the internal markup of
       each step changes — only whether it's visible. ---- */
    .food-emoji-picker-head.can-collapse { cursor: pointer; -webkit-tap-highlight-color: transparent; }
    .step-chevron {
      display: inline-block; margin-left: auto; font-size: 1.3rem; font-weight: 800;
      color: var(--ink-soft); line-height: 1;
      transition: transform 0.2s ease; flex: 0 0 auto;
      padding: 4px;
    }
    .food-emoji-picker.step-collapsed .food-picker-row,
    .food-emoji-picker.step-collapsed .add-food-panel,
    .food-emoji-picker.step-collapsed .food-search-wrap,
    .food-emoji-picker.step-collapsed .food-search-empty,
    .food-emoji-picker.step-collapsed .food-picker-purpose {
      display: none;
    }
    /* Search sits above the row; slightly tighter than the modal version
       since Step 1 is already a tall block. */
    .food-search-wrap { margin-bottom: 10px; padding: 7px 12px; }
    .fav-search-clear {
      background: none; border: none; color: var(--ink-soft); cursor: pointer;
      font-size: 0.85rem; padding: 2px 4px; flex-shrink: 0; line-height: 1;
    }
    .food-search-empty {
      margin: 0 0 10px; font-size: calc(12px * var(--font-scale, 1)); font-weight: 700;
      color: var(--ink-soft); line-height: 1.45;
    }
    /* While filtering, the horizontal strip becomes a wrapping grid. This is
       the actual win: a one-row scroller hides its own contents, so you can't
       tell whether the thing you want is in there without dragging to the end.
       Wrapped, every match is visible at once. */
    .food-emoji-scroll.is-filtering {
      flex-wrap: wrap; overflow-x: hidden; overflow-y: auto;
      max-height: 46vh; padding-bottom: 6px;
    }
    .food-emoji-scroll.is-filtering .is-clone,
    .food-emoji-scroll .food-emoji-chip.is-hidden-by-search { display: none; }
    /* Your own foods come first: they're more specific than a generic chip,
       so if one matches it's almost certainly the thing being looked for. */
    .food-search-group { margin-bottom: 10px; }
    .food-search-group-label {
      margin: 0 0 6px; font-family: 'Baloo 2', sans-serif;
      font-size: calc(12px * var(--font-scale, 1)); font-weight: 700;
      color: var(--ink-soft); letter-spacing: 0.02em;
    }
    .food-search-custom-list { display: flex; flex-direction: column; gap: 6px; }
    /* Each saved size is its own row rather than one row per food, so the
       choice between "13g" and "26g" is made by reading, not by opening a
       second sheet to find out what the options were. */
    .custom-result-chip {
      display: flex; align-items: center; gap: 10px; width: 100%;
      background: var(--bg); border: 1.5px solid var(--bg2); border-radius: 12px;
      padding: 9px 12px; cursor: pointer; text-align: left;
      font-family: 'Nunito', sans-serif; color: var(--ink); min-height: 52px;
    }
    .custom-result-chip:hover, .custom-result-chip:focus-visible { border-color: var(--sprout-green); }
    .custom-result-chip:active { transform: scale(0.985); }
    .custom-result-emoji { font-size: calc(22px * var(--font-scale, 1)); line-height: 1; flex: 0 0 auto; }
    .custom-result-text { flex: 1 1 auto; min-width: 0; }
    .custom-result-name {
      display: block; font-weight: 800; font-size: calc(14px * var(--font-scale, 1));
      line-height: 1.25; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .custom-result-meta {
      display: block; font-weight: 700; font-size: calc(11.5px * var(--font-scale, 1));
      color: var(--ink-soft); line-height: 1.3; margin-top: 2px;
    }
    .custom-result-meta .cr-carbs { color: var(--sprout-green); }
    body.theme-night .custom-result-meta .cr-carbs { color: var(--mint, #2EC4B6); }
    /* Same star/camera distinction as the favourites drawer — a scanned
       number stays visibly community-sourced even when reached via search. */
    .custom-result-badge { flex: 0 0 auto; font-size: calc(13px * var(--font-scale, 1)); opacity: 0.85; }
    @media (prefers-reduced-motion: reduce) { .custom-result-chip:active { transform: none; } }
    .food-emoji-picker.step-collapsed .step-chevron { transform: rotate(-90deg); }
    /* Once a food is chosen, "Skip" no longer means anything — hide it so
       the collapsed row just shows what was picked. */
    .food-emoji-picker.step-collapsed .food-picker-skip-btn {
      display: none;
    }
    .food-picker-change-label {
      display: none; flex: 0 0 auto; white-space: nowrap; margin-left: 8px;
      background: var(--card); border: 1.5px solid var(--sprout-green);
      border-radius: 100px; padding: 4px 11px;
      font-family: 'Nunito', sans-serif; font-weight: 800; font-size: 0.72rem;
      color: var(--ink); -webkit-tap-highlight-color: transparent;
    }
    body.theme-night .food-picker-change-label { background: #1B2140; border-color: rgba(46,196,182,0.45); }
    body.theme-contrast .food-picker-change-label, body.theme-contrast-light .food-picker-change-label {
      color: var(--ink); background: var(--bg2); border-color: var(--ink-soft);
    }
    .food-emoji-picker.step-collapsed .food-picker-change-label { display: inline-block; }

    .field.can-collapse > label { cursor: pointer; -webkit-tap-highlight-color: transparent; }
    #drinkCarbsRow.can-collapse label,
    #drinkTypeField.can-collapse .drink-label-row,
    #drinkVolumeRow.can-collapse .drink-label-row { cursor: pointer; -webkit-tap-highlight-color: transparent; }
    /* 2026-07-30: the info hint text used to be deliberately excluded from
       this hide-list, so the ⓘ button kept working even after its step
       collapsed. Changed on request — a hint (this one included, e.g. the
       "see Carbohydrate on the food label" diagram) is meant to track
       whether its own step is the one currently active: shown while that
       step is open, hidden the moment it collapses forward. The ⓘ button
       is hidden alongside it, since leaving it visible with nothing left
       for it to open would just be a dead control. This only affects the
       CSS-level visibility — the underlying open/closed state (including
       the sticky ones remembered in localStorage) is untouched, so the
       hint reopens in whatever state it was left in if the step is
       re-expanded. */
    .field.step-collapsed .stepper-row,
    .field.step-collapsed .portion-chips,
    .field.step-collapsed .portion-guide,
    .field.step-collapsed .field-subtitle,
    .field.step-collapsed .preset-row,
    .field.step-collapsed .step-question-text,
    .field.step-collapsed .step-continue-btn,
    .field.step-collapsed .hint.hint-collapsible,
    .field.step-collapsed .info-hint-btn {
      display: none;
    }
    .field.step-collapsed .step-chevron { transform: rotate(-90deg); }
    .field-summary-value {
      display: inline-flex; align-items: center; gap: 4px;
      font-size: 0.78rem; font-weight: 800; color: #fff;
      background: var(--sprout-green); border-radius: 100px;
      padding: 4px 10px; margin-left: 6px; line-height: 1.2;
    }
    .field-summary-value:empty { display: none; padding: 0; margin: 0; }
    .field-summary-value.is-guess { background: var(--sun); color: #5C4400; }
    /* The favourite message is much longer than a bare number, so it drops
       the pill shape (which only suits short content) for a wrapping
       rounded-rect that can take a full line without looking broken. */
    .field-summary-value.is-favourite {
      display: block; width: 100%; margin-left: 0; margin-top: 6px;
      border-radius: 10px; font-size: 0.74rem; line-height: 1.4;
      padding: 6px 10px; white-space: normal;
    }
    /* Same wrapping treatment as the favourite note, for the "same as last
       time" message — a different colour (blue, not green/amber) so it
       reads as its own distinct kind of note rather than a guess or a pick. */
    .field-summary-value.is-memory {
      display: block; width: 100%; margin-left: 0; margin-top: 6px;
      border-radius: 10px; font-size: 0.74rem; line-height: 1.4;
      padding: 6px 10px; white-space: normal;
      background: var(--sky); color: #fff;
    }
    /* The drink volume note is short ("🔁 330ml — same as last time"),
       unlike the food favourite note which can run to a full sentence —
       so it shouldn't stretch into a full-width block. It still breaks
       onto its own line under "How much fluid?" (via the summary group's
       wrap below), just sized to its content like a normal pill. */
    #drinkVolumeSummaryValue.is-memory {
      display: inline-flex; width: auto; margin-top: 4px;
    }
    /* Explicit "I'm done adjusting this" action — deliberately NOT inferred
       from stepper release or blur. Both were tried and both had a false-
       positive: release/blur fires after a single tap of +/-, collapsing
       the stepper before a second tap could land. An explicit tap avoids
       that ambiguity entirely. */
    .step-continue-btn {
      display: block; width: auto; min-width: 128px; margin: 22px auto 0;
      border: none; background: linear-gradient(135deg, var(--sprout-green), var(--sprout-green-deep));
      color: #fff;
      border-radius: 100px; padding: 9px 24px; font-family: 'Baloo 2', sans-serif;
      font-weight: 800; font-size: 0.82rem; letter-spacing: 0.2px; cursor: pointer;
      box-shadow: 0 4px 10px rgba(0,89,78,0.3);
      -webkit-tap-highlight-color: transparent;
      transition: transform 0.15s ease, box-shadow 0.15s ease;
    }
    body.theme-night .step-continue-btn { box-shadow: 0 4px 10px rgba(0,0,0,0.45); }
    .step-continue-btn:active { transform: scale(0.94); box-shadow: 0 2px 5px rgba(0,89,78,0.3); }
    .step-continue-btn[hidden] { display: none; }
    /* Steps 2/3 start locked until the step before them is answered — dimmed,
       not interactive, and collapsed to just its header so it reads as
       "coming up" rather than an empty field demanding attention early. */
    .field.step-locked {
      opacity: 0.45; pointer-events: none;
    }
    .field.step-locked .hint.hint-collapsible,
    .field.step-locked .stepper-row,
    .field.step-locked .portion-chips,
    .field.step-locked .portion-guide,
    .field.step-locked .field-subtitle,
    .field.step-locked .preset-row,
    .field.step-locked .step-continue-btn,
    .field.step-locked .bread-slice-note,
    .field.step-locked .field-summary-value {
      display: none;
    }
    /* Step 1 now collapses to a single-line summary with nothing "coming up"
       shown beneath it. Step 3 (drink carbs) should read the same way while
       it's waiting on Step 2 — fully out of the way, not a dimmed preview —
       so the station doesn't look lopsided between one step that vanishes
       and one that lingers. Scoped to the drink carbs row only; the food
       side's carbs/weight "coming up" preview is unchanged. */
    #drinkCarbsRow.step-locked {
      display: none;
    }
    .step-badge {
      display: inline-flex; align-items: center; justify-content: center;
      width: 17px; height: 17px; flex: 0 0 auto; border-radius: 50%;
      background: var(--sprout-green); color: #fff;
      font-family: 'Baloo 2', sans-serif; font-weight: 800; font-size: 0.7rem;
      line-height: 1; margin-right: 8px;
    }
    /* Drinks are blue (see .drink-go-btn) — carrying that through to the
       step numbers too, so the food flow's 1-2-3-4 and the drink flow's
       own 1-2-3-4 read as two distinct sequences at a glance, not one
       confusing repeated set of badges on the same screen. Deliberately
       NOT touching .step-badge-on-btn (the badge on the Add buttons) —
       that one's already a near-white circle designed to pop against
       whichever button colour it sits on, and the button itself already
       signals food vs. drink, so it doesn't need this too. */
    .drink-label-row .step-badge {
      background: var(--sky);
    }
    body.theme-contrast .step-badge, body.theme-contrast-light .step-badge {
      background: var(--ink-soft); color: var(--bg);
    }
    /* Steps 2/3/4 are a fixed numbered sequence — this one isn't, so it
       shouldn't look like it belongs to the same countdown. Dashed and
       unfilled rather than solid, ⚡ instead of a number. */
    .step-badge.step-badge-optional {
      background: transparent; border: 1.5px dashed var(--sprout-green);
      color: var(--sprout-green); font-size: 0.62rem;
    }
    body.theme-night .step-badge.step-badge-optional {
      border-color: #2EC4B6; color: #2EC4B6;
    }
    body.theme-contrast .step-badge.step-badge-optional,
    body.theme-contrast-light .step-badge.step-badge-optional {
      background: transparent; border-color: var(--ink-soft); color: var(--ink-soft);
    }
    /* A one-line explanation of what this section actually does, since
       "optional" alone doesn't say why — a shortcut, not a form field. */
    .food-picker-purpose {
      margin: 4px 0 10px; font-family: 'Nunito', sans-serif; font-weight: 700;
      font-size: 0.72rem; color: var(--ink-soft); line-height: 1.4;
    }
    .food-emoji-picker-label {
      display: block; font-family: 'Nunito', sans-serif; font-weight: 800;
      font-size: 0.82rem; color: var(--ink-soft); margin-bottom: 6px;
    }
    /* The "(optional)" note is now part of the heading text itself rather
       than a separate pill, so it reads in one breath with the question
       instead of being a small side-detail easy to skim past. Lighter
       weight than the heading around it is enough to mark it as an aside
       without needing its own background/border. */
    .food-picker-heading-optional {
      font-weight: 700; color: var(--ink-soft);
    }
    body.theme-night .food-picker-heading-optional { color: rgba(255,255,255,0.65); }
    .food-emoji-picker-head {
      display: flex; align-items: center; flex-wrap: wrap;
      row-gap: 6px; column-gap: 0;
    }
    .food-emoji-picker-head .step-badge { margin-right: 6px; }
    /* Grows to fill the row's leftover space, so whatever comes after it
       (the skip/change chip, then the chevron) sits packed together at
       the true right edge instead of each grabbing its own share of the
       gap — two elements both using margin-left:auto in the same row
       split the space between them rather than one flush right-aligned
       group. */
    .food-emoji-picker-head .food-emoji-picker-label {
      margin-bottom: 0; flex: 1 1 auto; min-width: 0;
    }
    .food-picker-skip-btn {
      flex: 0 0 auto; white-space: nowrap; margin-left: 8px;
      background: var(--card); border: 1.5px solid var(--sprout-green);
      border-radius: 100px; padding: 4px 11px; cursor: pointer;
      font-family: 'Nunito', sans-serif; font-weight: 800; font-size: 0.72rem;
      color: var(--ink); -webkit-tap-highlight-color: transparent;
      transition: transform 0.12s ease, border-color 0.15s ease;
    }
    .food-picker-skip-btn:active { transform: scale(0.95); }
    body.theme-night .food-picker-skip-btn { background: #1B2140; border-color: rgba(46,196,182,0.45); }
    body.theme-contrast .food-picker-skip-btn, body.theme-contrast-light .food-picker-skip-btn {
      color: var(--ink); background: var(--bg2); border-color: var(--ink-soft);
    }
    .food-picker-skip-btn:focus-visible { outline: 3px solid var(--sky); outline-offset: 2px; }
    .food-picker-skip-btn.was-skipped {
      background: var(--card); border-color: var(--sprout-green);
      color: var(--ink); cursor: pointer; opacity: 0.75;
    }
    body.theme-night .food-picker-skip-btn.was-skipped { background: #1B2140; }

    .food-emoji-scroll {
      display: flex; gap: 8px; overflow-x: auto; padding: 4px 2px 20px;
      -webkit-overflow-scrolling: touch;
      scrollbar-width: none;        /* Firefox */
      -ms-overflow-style: none;     /* old Edge/IE */
    }
    .food-emoji-scroll::-webkit-scrollbar { display: none; } /* Chrome/Safari/Edge */
    /* Desktop only: signal the row is draggable and keep panning smooth. */
    @media (hover: hover) and (pointer: fine) {
      .food-emoji-scroll { cursor: grab; }
      .food-emoji-scroll.dragging { cursor: grabbing; user-select: none; scroll-behavior: auto; }
      .food-emoji-scroll.dragging .food-emoji-chip { pointer-events: none; }
    }
    /* Icon + name label, stacked in ONE element (not a wrapper + sibling).
       This matters structurally, not just visually: the "endless food row"
       loop below clones whichever elements carry the .food-emoji-chip
       class directly as children of the scroll track, so the label has to
       live INSIDE that same element for cloneNode(true) to keep carrying
       it — wrapping it externally would silently break the infinite-scroll
       system, since the clone logic would then find zero direct children
       with this class. */
    .food-emoji-chip {
      flex: 0 0 auto; width: 58px; height: 64px; border-radius: 14px;
      border: 2px solid var(--bg2); background: var(--bg);
      cursor: pointer; position: relative;
      display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
      transition: transform 0.12s ease, border-color 0.12s ease, background 0.12s ease;
    }
    .food-emoji-chip-icon { font-size: 22px; line-height: 1; }
    .food-emoji-chip-name {
      font-family: 'Nunito', sans-serif; font-weight: 800; font-size: 0.62rem;
      color: var(--ink); line-height: 1.1; max-width: 52px;
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    body.theme-night .food-emoji-chip { background: #1B2140; border-color: #262C52; }
    .food-emoji-chip:active { transform: scale(0.9); }
    /* Selected state must out-specify the theme override above, or it's invisible in night mode. */
    .food-emoji-chip.active,
    body.theme-night .food-emoji-chip.active,
    body.theme-contrast .food-emoji-chip.active,
    body.theme-contrast-light .food-emoji-chip.active {
      border-color: var(--sprout-green);
      background: var(--sprout-green-tint);
      transform: scale(1.08);
      box-shadow: 0 0 0 3px var(--sprout-green-tint), 0 4px 12px rgba(14,140,122,0.35);
    }
    .food-emoji-chip.active::after {
      content: "✓";
      position: absolute;
      top: -6px; right: -6px;
      width: 18px; height: 18px;
      background: var(--sprout-green); color: #fff;
      border-radius: 50%; font-size: 11px; font-weight: 900;
      display: flex; align-items: center; justify-content: center;
      box-shadow: 0 1px 3px rgba(0,0,0,0.3);
    }

    /* ---- "Add food" button: pinned outside the scrolling carousel, so
       it's always visible and never affected by the infinite-loop/clone
       logic that powers the built-in food row. ---- */
    .food-picker-row { display: flex; align-items: flex-start; gap: 8px; flex-wrap: wrap; }
    .food-picker-row .food-emoji-scroll { flex: 1; min-width: 120px; }
    /* [hidden] alone isn't reliably specific enough to beat the class rules
       above (same specificity, and these come later in source order) — the
       existing .fav-recent-row[hidden] rule hit the same issue, so this
       follows that precedent rather than relying on the attribute alone. */
    .food-emoji-scroll[hidden] { display: none; }

    /* ---- "The Usual": personalised, time-of-day chip row that stands in
       for the generic scroll above. Same icon+label shape as
       .food-emoji-chip so swapping one row for the other reads as a
       content change, not a layout change. Also deliberately NO ★/📷-style
       badge — those already mean "where this food's data came from", and
       reusing that glyph slot here for "why is this chip here" would
       blur two different meanings onto one symbol. Name label is load-
       bearing here, not decorative: this is a small, personalised set
       where two real foods (two different cereals, two different
       biscuits) can land on the same or a near-identical emoji, unlike
       the generic scroll's ~60 visually distinct icons. ---- */
    .usual-foods-scroll {
      flex: 1; min-width: 120px;
      display: flex; gap: 10px; overflow-x: auto; padding: 4px 2px 20px;
      -webkit-overflow-scrolling: touch;
      scrollbar-width: none; -ms-overflow-style: none;
    }
    .usual-foods-scroll::-webkit-scrollbar { display: none; }
    .usual-foods-scroll[hidden] { display: none; }
    .usual-chip {
      flex: 0 0 auto; width: 58px; height: 64px; border-radius: 14px;
      border: 2px solid var(--bg2); background: var(--bg);
      cursor: pointer; position: relative;
      display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
      transition: transform 0.12s ease, border-color 0.12s ease, background 0.12s ease;
      -webkit-tap-highlight-color: transparent;
    }
    .usual-chip-icon { font-size: 22px; line-height: 1; }
    .usual-chip-name {
      font-family: 'Nunito', sans-serif; font-weight: 800; font-size: 0.62rem;
      color: var(--ink); line-height: 1.1; max-width: 52px;
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    body.theme-night .usual-chip { background: #1B2140; border-color: #262C52; }
    .usual-chip:active { transform: scale(0.9); }
    .usual-chip:focus-visible { outline: 3px solid var(--sky); outline-offset: 2px; }
    .usual-chip.add-own { border-style: dashed; border-color: var(--ink-soft); background: transparent; }
    .usual-chip.add-own .usual-chip-icon,
    .usual-chip.add-own .usual-chip-name { color: var(--ink-soft); }

    /* Detail-on-demand amount tooltip — hover (desktop) / long-press
       500ms (touch), the same interaction already used for the badge
       notification dots elsewhere in the app, so it introduces no new
       gesture. Answers "how much exactly", which the name label doesn't
       cover. Solid on/off (no fade) with a fixed, non-variable colour and
       a visible border, so it can't be caught half-transparent and lose
       contrast against whatever theme or background is behind it. */
    .usual-amount-tip {
      position: absolute; bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%);
      background: #12172B; color: #FFFFFF; padding: 7px 11px; border-radius: 10px;
      font-family: 'Nunito', sans-serif; font-size: 0.74rem; font-weight: 800; white-space: nowrap;
      pointer-events: none; border: 1.5px solid rgba(255,255,255,0.35);
      box-shadow: 0 4px 14px rgba(0,0,0,0.45);
      display: none; z-index: 20;
    }
    .usual-amount-tip::after {
      content: ""; position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
      border: 5px solid transparent; border-top-color: #12172B;
    }
    .usual-chip.show-tip .usual-amount-tip { display: block; }
    .add-food-chip-pinned {
      flex: 0 0 auto; height: 64px; padding: 0 14px; border-radius: 100px;
      border: 2px dashed var(--sprout-green); background: var(--card);
      color: var(--ink); cursor: pointer; white-space: nowrap;
      font-family: 'Baloo 2', sans-serif; font-weight: 800; font-size: 0.86rem; line-height: 1;
      display: flex; align-items: center; justify-content: center; gap: 5px;
      -webkit-tap-highlight-color: transparent;
      transition: transform 0.12s ease, background-color 0.15s ease;
    }
    .add-food-chip-pinned span { font-size: 20px; line-height: 1; color: inherit; }
    .add-food-chip-pinned:active { transform: scale(0.96); }
    .add-food-chip-pinned:focus-visible { outline: 3px solid var(--sky); outline-offset: 2px; }
    body.theme-night .add-food-chip-pinned { background: #1B2140; }
    .add-food-chip-pinned.panel-open {
      background: var(--sprout-green); color: #fff; border-style: solid;
    }
    .add-food-chip-pinned.panel-open span { color: #fff; }

    /* ---- "⭐" favourites button: same pinned spot, brighter treatment so
       it reads as "open a collection" rather than "add new". ---- */
    .fav-food-chip-pinned {
      flex: 0 0 auto; width: 58px; height: 64px; border-radius: 14px;
      border: 2px solid var(--sun); background: linear-gradient(160deg, #FFF6DA, var(--sun));
      color: #7A5B00; cursor: pointer;
      display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
      -webkit-tap-highlight-color: transparent;
      box-shadow: 0 2px 6px rgba(255, 201, 60, 0.45);
      transition: transform 0.12s ease;
    }
    .fav-food-chip-pinned .pinned-chip-icon { font-size: 24px; line-height: 1; }
    .fav-food-chip-pinned:active { transform: scale(0.9); }
    .fav-food-chip-pinned:focus-visible { outline: 3px solid var(--sky); outline-offset: 2px; }
    body.theme-night .fav-food-chip-pinned { background: linear-gradient(160deg, #4A3C10, #8A6F1E); }

    /* ---- Add-your-own food panel (opened by the "+" chip) ---- */
    .add-food-panel { margin-top: 10px; }
    .add-food-panel[hidden] { display: none; }
    .add-food-panel-row { display: flex; align-items: center; gap: 8px; }
    .custom-food-preview {
      flex: 0 0 auto; width: 38px; height: 38px; border-radius: 50%;
      display: flex; align-items: center; justify-content: center; font-size: 1.2rem;
      background: var(--bg); border: 2px solid var(--sprout-green);
    }
    body.theme-night .custom-food-preview { background: #1B2140; }
    .add-food-name-input {
      flex: 1; min-width: 0; padding: 9px 12px; border-radius: 10px;
      border: 2px solid var(--bg2); background: var(--card);
      /* Was 0.9rem (14.4px) — under Safari's 16px auto-zoom-on-focus
         threshold. TO REVERT: back to 0.9rem. */
      font-family: 'Nunito', sans-serif; font-weight: 700; font-size: 1rem; color: var(--ink);
    }
    body.theme-night .add-food-name-input { background: #1B2140; border-color: #262C52; }
    .add-food-name-input:focus-visible { outline: 3px solid var(--sky); outline-offset: 1px; }

    /* ---- Category picker (savoury / sweet / treats / other) ---- */
    .custom-food-category-row {
      display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap;
      animation: pop 0.2s ease;
    }
    .custom-food-category-row[hidden] { display: none; }
    .category-chip {
      flex: 1 1 auto; min-width: 0; padding: 7px 8px; border-radius: 100px;
      border: 2px solid var(--bg2); background: var(--card); color: var(--ink-soft);
      font-family: 'Nunito', sans-serif; font-weight: 800; font-size: 0.74rem;
      cursor: pointer; -webkit-tap-highlight-color: transparent; white-space: nowrap;
      transition: transform 0.1s ease, border-color 0.12s ease, background-color 0.12s ease, color 0.12s ease;
    }
    .category-chip:active { transform: scale(0.95); }
    .category-chip:focus-visible { outline: 3px solid var(--sky); outline-offset: 1px; }
    .category-chip[aria-pressed="true"] {
      border-color: var(--sprout-green); background: var(--sprout-green); color: #fff;
    }
    body.theme-night .category-chip { background: #1B2140; border-color: #262C52; }
    /* Must come after the plain night-theme rule above: body.theme-night
       .category-chip has higher specificity than .category-chip[aria-pressed],
       so without this override the pressed/highlighted state was invisible
       in night theme — the chip always fell back to its unpressed colours. */
    body.theme-night .category-chip[aria-pressed="true"] {
      border-color: var(--sprout-green); background: var(--sprout-green); color: #fff;
    }

    .custom-food-add-btn {
      flex: 0 0 auto; border: none; padding: 9px 16px; border-radius: 100px;
      background: var(--sprout-green); color: #fff; font-family: 'Baloo 2', sans-serif;
      font-weight: 800; font-size: 0.84rem; cursor: pointer; -webkit-tap-highlight-color: transparent;
      transition: transform 0.12s ease, background-color 0.15s ease;
    }
    .custom-food-add-btn-full { display: block; width: 100%; margin-top: 10px; padding: 10px; }
    .custom-food-add-btn:active { transform: scale(0.95); }
    .custom-food-add-btn:disabled { background: #B9C7BE; cursor: default; }
    .custom-food-note {
      margin-top: 8px; padding: 8px 11px; border-radius: 10px;
      background: var(--card); border-left: 4px solid var(--sprout-green);
      font-family: 'Nunito', sans-serif;
      font-size: 0.78rem; font-weight: 700; color: var(--ink); line-height: 1.4;
    }
    body.theme-night .custom-food-note { background: #1B2140; }

    /* ---- Favourite Foods modal ----
       Rebuilt around three rules, because the old version broke all three:
       (1) one row per FOOD, never one per saved size, so a food with three
       sizes reads as one thing; (2) no destructive control in the default
       view — removal lives behind the Edit button, so a mis-tap can't wipe a
       saved food; (3) exactly one number per row, on a right-hand rail you
       can run your eye down. Everything else here is type and whitespace. */
    /* Anchored near the top rather than vertically centred. A centred list
       that changes height shifts the whole panel every time you filter or
       search, and a long one pushes its bottom edge down behind the phone's
       navigation bar. Starting from the top keeps the header, search box and
       first few foods in the same place whatever the list is doing. */
    #favFoodsModal { align-items: flex-start; padding-top: max(14px, env(safe-area-inset-top)); }
    .fav-foods-modal-content {
      max-width: 460px; position: relative; padding: 20px 16px 18px;
      max-height: calc(100vh - 28px);
      max-height: calc(100dvh - 28px); /* dvh accounts for mobile browser chrome */
    }
    .fav-modal-close-x {
      position: absolute; top: 12px; right: 12px; z-index: 2;
      width: 34px; height: 34px; padding: 0; line-height: 1;
      display: flex; align-items: center; justify-content: center;
      border: none; border-radius: 50%; background: var(--bg);
      color: var(--ink-soft); font-size: 17px; font-weight: 900; cursor: pointer;
      -webkit-tap-highlight-color: transparent;
      transition: background-color 0.15s ease, color 0.15s ease, transform 0.12s ease;
    }
    .fav-modal-close-x:hover { background: var(--bg2); color: var(--ink); }
    .fav-modal-close-x:focus-visible { outline: 3px solid var(--sky); outline-offset: 2px; }
    .fav-modal-close-x:active { transform: scale(0.92); }
    body.theme-night .fav-modal-close-x { background: #1B2140; }

    /* Header: title, then a single quiet line carrying the count on the left
       and the Edit switch on the right. The old explanatory sub-caption is
       gone — every row now prints its own numbers, so there is nothing left
       to explain. */
    .fav-modal-head { margin-bottom: 12px; padding-right: 42px; }
    #favFoodsModalTitle {
      font-family: 'Baloo 2', sans-serif; font-size: 1.28rem; font-weight: 800;
      color: var(--ink); margin: 0; line-height: 1.2;
    }
    .fav-modal-head-row {
      display: flex; align-items: center; justify-content: space-between;
      gap: 10px; margin-top: 3px; min-height: 30px;
    }
    .fav-modal-count { font-size: 0.76rem; font-weight: 700; color: var(--ink-soft); }
    .fav-edit-toggle {
      border: none; background: none; cursor: pointer;
      padding: 7px 8px; margin: -7px -8px -7px 0; border-radius: 10px;
      font-family: 'Nunito', sans-serif; font-size: 0.8rem; font-weight: 800;
      color: var(--sky); -webkit-tap-highlight-color: transparent;
      transition: background-color 0.14s ease;
    }
    .fav-edit-toggle[hidden] { display: none; }
    .fav-edit-toggle:hover { background: var(--bg); }
    .fav-edit-toggle.is-active { background: var(--bg2); color: var(--ink); }
    .fav-edit-toggle:focus-visible { outline: 3px solid var(--sky); outline-offset: 1px; }

    #favFoodsSearchWrap { margin-bottom: 10px; }
    /* .fav-search-wrap.show sets display:flex, which beats the [hidden]
       attribute on its own — the ID selector here is what actually wins, so
       the search box really does disappear on the empty state. */
    #favFoodsSearchWrap[hidden] { display: none; }
    .fav-modal-head-row[hidden] { display: none; }

    /* One control strip, not three. Category chips FILTER (they used to only
       scroll you to a section, which meant the long list stayed long), and
       they share the row with the view switch instead of stacking above it.
       The chips scroll horizontally so a fifth category never wraps the row. */
    .fav-filter-bar { display: flex; align-items: center; gap: 8px; margin-bottom: 14px; }
    .fav-filter-bar[hidden] { display: none; }
    .fav-filter-bar.no-filters { justify-content: flex-end; margin-bottom: 10px; }
    .fav-filter-bar.no-filters .fav-filter-scroll { display: none; }
    .fav-filter-scroll {
      display: flex; gap: 6px; flex: 1 1 auto; min-width: 0;
      overflow-x: auto; -webkit-overflow-scrolling: touch;
      scrollbar-width: none; padding: 2px 10px 2px 0;
      /* Fades the last chip out under the view switch instead of guillotining
         it, so an overflowing row reads as "there's more" rather than broken. */
      -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 22px), transparent 100%);
      mask-image: linear-gradient(to right, #000 calc(100% - 22px), transparent 100%);
    }
    .fav-filter-scroll::-webkit-scrollbar { display: none; }
    .fav-filter-chip {
      flex: 0 0 auto; display: inline-flex; align-items: center; gap: 5px;
      border: 1.5px solid var(--bg2); background: transparent; color: var(--ink-soft);
      border-radius: 999px; padding: 7px 13px; cursor: pointer;
      font-family: 'Nunito', sans-serif; font-weight: 800; font-size: 0.75rem;
      -webkit-tap-highlight-color: transparent;
      transition: background-color 0.14s ease, color 0.14s ease, border-color 0.14s ease;
    }
    .fav-filter-chip-count { font-weight: 700; opacity: 0.6; font-variant-numeric: tabular-nums; }
    /* Filled with --ink rather than an accent: it stays legible in every
       theme, including both high-contrast ones, without a special case. */
    .fav-filter-chip.is-active { background: var(--ink); border-color: var(--ink); color: var(--card); }
    .fav-filter-chip.is-active .fav-filter-chip-count { opacity: 0.7; }
    .fav-filter-chip:focus-visible { outline: 3px solid var(--sky); outline-offset: 2px; }

    .fav-view-toggle {
      flex: 0 0 auto; display: flex; gap: 2px;
      background: var(--bg); border-radius: 999px; padding: 3px;
    }
    .fav-view-toggle[hidden] { display: none; }
    body.theme-night .fav-view-toggle { background: #131737; }
    .fav-view-btn {
      width: 34px; height: 30px; border: none; background: transparent; border-radius: 999px;
      color: var(--ink-soft); font-size: 0.92rem; line-height: 1; cursor: pointer;
      display: flex; align-items: center; justify-content: center;
      -webkit-tap-highlight-color: transparent;
      transition: background-color 0.14s ease, color 0.14s ease;
    }
    .fav-view-btn.is-active { background: var(--card); color: var(--ink); box-shadow: 0 1px 3px var(--shadow); }
    .fav-view-btn:focus-visible { outline: 3px solid var(--sky); outline-offset: 2px; }

    /* Shown only when something scanned is actually on screen. Says once,
       in words, what the old per-chip "≈" badge left you to guess. */
    /* A footnote, so it sits at the foot: below the list, out of the way of
       scanning, next to nothing it has to compete with. */
    .fav-source-legend {
      margin: 16px 6px 0; padding-top: 12px; border-top: 1px solid var(--bg2);
      font-size: 0.7rem; font-weight: 600; line-height: 1.45; color: var(--ink-soft);
    }
    .fav-source-legend[hidden] { display: none; }

    .fav-group-label {
      font-family: 'Nunito', sans-serif; font-size: 0.64rem; font-weight: 800;
      letter-spacing: 0.09em; text-transform: uppercase; color: var(--ink-soft);
      margin: 16px 0 4px; opacity: 0.75;
    }
    .fav-group-label:first-child { margin-top: 0; }

    /* ---- List view ---- */
    .fav-list { display: flex; flex-direction: column; }
    .fav-row {
      position: relative; display: flex; align-items: center; gap: 12px;
      padding: 11px 6px; border-radius: 12px; cursor: pointer;
      -webkit-tap-highlight-color: transparent;
      transition: background-color 0.14s ease;
    }
    /* Divider starts after the emoji column — it separates the text blocks
       without slicing through the icon rail. */
    .fav-row + .fav-row::before {
      content: ""; position: absolute; left: 44px; right: 6px; top: 0;
      border-top: 1px solid var(--bg2);
    }
    .fav-row:hover, .fav-row:active { background: var(--bg); }
    body.theme-night .fav-row:hover, body.theme-night .fav-row:active { background: #131737; }
    .fav-row:focus-visible { outline: 3px solid var(--sky); outline-offset: -1px; }
    .fav-row-icon { flex: 0 0 auto; width: 26px; text-align: center; font-size: 1.35rem; line-height: 1; }
    .fav-row-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
    .fav-row-name {
      font-family: 'Baloo 2', sans-serif; font-size: 0.98rem; font-weight: 700;
      color: var(--ink); line-height: 1.2;
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .fav-row-meta {
      font-size: 0.72rem; font-weight: 600; color: var(--ink-soft); line-height: 1.3;
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    /* The pack label carries the meaning on a row whose other numbers are
       deliberately quiet, so it gets the full ink colour and extra weight
       rather than sitting at the same grey as the grams around it. */
    .fav-pack { font-weight: 800; color: var(--ink); }
    .fav-row.is-incomplete .fav-row-meta { color: #B45309; font-weight: 700; }
    body.theme-night .fav-row.is-incomplete .fav-row-meta { color: #FBBF6B; }

    /* The one number on the row: carbs in the saved portion. The "carbs"
       label repeats down the rail on purpose — in a carb-counting app used
       around a child's health, an unlabelled number sitting next to a "40g
       portion" is a genuinely dangerous ambiguity, and at this size the
       repetition reads as texture rather than clutter. */
    .fav-value {
      flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-end;
      min-width: 46px; line-height: 1;
    }
    .fav-value-num {
      font-family: 'Baloo 2', sans-serif; font-size: 1.02rem; font-weight: 800;
      color: var(--ink); font-variant-numeric: tabular-nums;
    }
    .fav-value-unit {
      font-size: 0.55rem; font-weight: 700; letter-spacing: 0.07em;
      text-transform: uppercase; color: var(--ink-soft); margin-top: 3px; opacity: 0.68;
    }
    /* Was a bare 1.15rem glyph in the muted meta colour — almost invisible,
       and the only thing signalling "this food has more than one size".
       Now a filled chip: full ink on a tinted circle, so it reads as
       something you can press. */
    .fav-value.is-chevron {
      min-width: 0; width: 30px; height: 30px; border-radius: 50%;
      background: var(--bg2); color: var(--ink);
      font-size: 1.2rem; font-weight: 900; line-height: 1;
      display: flex; align-items: center; justify-content: center;
      padding-bottom: 3px; /* optical centring of the › glyph */
      box-shadow: inset 0 0 0 1.5px var(--ink-soft);
    }
    body.theme-night .fav-value.is-chevron { background: #333C70; }
    body.theme-contrast .fav-value.is-chevron,
    body.theme-contrast-light .fav-value.is-chevron { border: 2px solid var(--ink-soft); }
    .fav-row:hover .fav-value.is-chevron { background: var(--sky); color: #fff; }
    .fav-value.is-empty { font-size: 1rem; font-weight: 800; color: var(--ink-soft); }

    /* ---- Grid view ---- */
    .fav-tile-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 10px; }
    .fav-tile {
      position: relative; display: flex; flex-direction: column; align-items: flex-start;
      gap: 4px; padding: 12px 11px; border-radius: 16px; background: var(--bg);
      cursor: pointer; -webkit-tap-highlight-color: transparent;
      transition: transform 0.1s ease, background-color 0.14s ease;
    }
    body.theme-night .fav-tile { background: #131737; }
    .fav-tile:active { transform: scale(0.97); }
    .fav-tile:focus-visible { outline: 3px solid var(--sky); outline-offset: 2px; }
    .fav-tile-emoji { font-size: 1.5rem; line-height: 1; }
    .fav-tile-name {
      width: 100%; font-family: 'Baloo 2', sans-serif; font-size: 0.82rem; font-weight: 700;
      color: var(--ink); line-height: 1.2;
      display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
    }
    .fav-tile-value {
      /* Pushed to the bottom so the figures line up across a row of tiles
         whose names run to different lengths. */
      margin-top: auto; padding-top: 2px;
      font-size: 0.71rem; font-weight: 800; color: var(--ink-soft);
      font-variant-numeric: tabular-nums;
    }
    .fav-tile.is-incomplete .fav-tile-value { color: #B45309; }
    body.theme-night .fav-tile.is-incomplete .fav-tile-value { color: #FBBF6B; }

    /* ---- Remove control: only ever exists while Edit is on ---- */
    /* Keeps the number rail in one column while editing, on rows that have
       no remove button of their own (multi-size foods). */
    .fav-row-remove-spacer { flex: 0 0 auto; width: 28px; height: 28px; }
    .fav-row-remove, .fav-tile-remove {
      flex: 0 0 auto; width: 28px; height: 28px; border-radius: 50%; border: none;
      background: var(--bg2); color: var(--ink-soft);
      font-size: 12px; font-weight: 900; line-height: 1; cursor: pointer;
      display: flex; align-items: center; justify-content: center;
      -webkit-tap-highlight-color: transparent; animation: pop 0.16s ease;
      transition: background-color 0.14s ease, color 0.14s ease;
    }
    .fav-row-remove.confirming, .fav-tile-remove.confirming { background: #E4573D; color: #fff; }
    .fav-row-remove:focus-visible, .fav-tile-remove:focus-visible { outline: 3px solid var(--sky); outline-offset: 2px; }
    .fav-tile-remove {
      position: absolute; top: 6px; right: 6px; width: 24px; height: 24px;
      background: var(--card); box-shadow: 0 1px 4px var(--shadow);
    }

    .fav-foods-empty {
      text-align: center; padding: 34px 16px; color: var(--ink-soft);
      font-size: 0.86rem; font-weight: 700; line-height: 1.6;
    }
    .fav-foods-empty-icon { font-size: 2rem; line-height: 1; margin-bottom: 8px; }

    /* High-contrast themes flatten --bg and --bg2 to near-invisible against
       the card, so the surfaces that carry meaning get an explicit edge. */
    body.theme-contrast .fav-tile, body.theme-contrast-light .fav-tile,
    body.theme-contrast .fav-view-toggle, body.theme-contrast-light .fav-view-toggle {
      border: 2px solid var(--ink-soft);
    }
    body.theme-contrast .fav-row + .fav-row::before,
    body.theme-contrast-light .fav-row + .fav-row::before { border-top-color: var(--ink-soft); }
    body.theme-contrast .fav-filter-chip, body.theme-contrast-light .fav-filter-chip {
      border-color: var(--ink-soft);
    }
    /* --card and --bg collapse to near-identical blacks here, so "which view
       am I in" has to be carried by an inversion rather than a tint. */
    body.theme-contrast .fav-view-btn.is-active, body.theme-contrast-light .fav-view-btn.is-active {
      background: var(--ink); color: var(--card);
    }

    @media (prefers-reduced-motion: reduce) {
      .fav-modal-close-x, .fav-row, .fav-tile, .fav-filter-chip,
      .fav-view-btn, .fav-edit-toggle, .fav-row-remove, .fav-tile-remove { transition: none; }
      .fav-modal-close-x:active, .fav-tile:active { transform: none; }
      .fav-row-remove, .fav-tile-remove { animation: none; }
    }

    /* ---- Variant picker bottom sheet — sits above the favourites modal ---- */
    /* Was pinned to the bottom of the screen. Now that the favourites modal
       is anchored to the top, a bottom sheet left a screen-height void between
       the two and put the options at the far end of a tall phone. It opens
       where the row you tapped already was instead. */
    .variant-picker-overlay {
      position: fixed; inset: 0; background: rgba(0,0,0,0.5);
      z-index: 200; display: none; align-items: flex-start; justify-content: center;
      padding: max(14px, env(safe-area-inset-top)) 15px 15px;
    }
    .variant-picker-overlay.show { display: flex; }
    .variant-picker-sheet {
      background: var(--card); border-radius: var(--radius-lg); width: 100%; max-width: 460px;
      padding: 18px 16px 20px;
      max-height: calc(100vh - 30px);
      max-height: calc(100dvh - 30px);
      overflow-y: auto;
      box-shadow: 0 12px 36px rgba(0,0,0,0.4);
      animation: pop 0.18s ease;
    }
    @media (prefers-reduced-motion: reduce) { .variant-picker-sheet { animation: none; } }
    body.theme-night .variant-picker-sheet { background: #161B36; }
    .variant-picker-title {
      font-family: 'Baloo 2', sans-serif; font-weight: 800; font-size: 1.05rem;
      margin: 0 0 2px; color: var(--ink);
    }
    .variant-picker-sub { font-size: 0.78rem; color: var(--ink-soft); margin: 0 0 14px; font-weight: 600; }
    .variant-picker-option {
      display: flex; align-items: center; gap: 12px;
      background: var(--bg); border-radius: 12px; padding: 11px 13px; margin-bottom: 8px;
      cursor: pointer; border: 2px solid transparent; -webkit-tap-highlight-color: transparent;
      transition: border-color 0.12s ease, transform 0.1s ease;
    }
    body.theme-night .variant-picker-option { background: #1B2140; }
    .variant-picker-option:active { border-color: var(--sprout-green); transform: scale(0.99); }
    .variant-picker-option-badge {
      flex: 0 0 auto; width: 50px; height: 50px; border-radius: 14px;
      background: var(--sprout-green); color: #fff; position: relative; overflow: hidden;
      display: flex; flex-direction: column; align-items: center; justify-content: center;
      font-family: 'Baloo 2', sans-serif; line-height: 1;
    }
    .variant-picker-option-badge .emoji-watermark {
      position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
      font-size: 34px; opacity: 0.28; filter: grayscale(0.3); line-height: 1;
    }
    .variant-picker-option-badge .num,
    .variant-picker-option-badge .unit { position: relative; z-index: 1; }
    .variant-picker-option-badge .num { font-size: 0.95rem; font-weight: 800; white-space: nowrap; }
    .variant-picker-option-badge .unit { font-size: 0.48rem; font-weight: 700; opacity: 0.9; }
    .variant-picker-option-info { flex: 1; min-width: 0; }
    .variant-picker-option-name { font-size: 0.9rem; font-weight: 800; color: var(--ink); }
    .variant-picker-option-carbs100 { font-size: 0.76rem; font-weight: 700; color: var(--ink-soft); margin-top: 2px; }
    .variant-picker-option-missing { font-size: 0.74rem; font-weight: 800; color: #B45309; margin-top: 3px; }
    body.theme-night .variant-picker-option-missing { color: #FBBF6B; }
    .variant-picker-option-delete {
      flex: 0 0 auto; width: 26px; height: 26px; border-radius: 50%; border: none;
      background: var(--bg2); color: var(--ink-soft); font-size: 12px; font-weight: 900;
      cursor: pointer; display: flex; align-items: center; justify-content: center;
      -webkit-tap-highlight-color: transparent;
      transition: background-color 0.12s ease, width 0.12s ease;
    }
    .variant-picker-option-delete.confirming {
      width: 32px; background: #E4573D; color: #fff; font-size: 14px;
    }
    .variant-picker-cancel-btn {
      width: 100%; border: none; background: var(--bg2); color: var(--ink);
      border-radius: 100px; padding: 11px; font-family: 'Baloo 2', sans-serif;
      font-weight: 800; font-size: 0.88rem; cursor: pointer; margin-top: 4px;
      -webkit-tap-highlight-color: transparent;
    }
    body.theme-night .variant-picker-cancel-btn { background: #262C52; color: #fff; }

    /* ---- Sprout eats: flying food emoji ---- */
    .flying-food {
      position: absolute; z-index: 40; font-size: 30px; pointer-events: none;
      left: 50%; top: -6px; transform: translate(-50%, -120%) scale(0.7);
      animation: flyIntoMouth 0.62s cubic-bezier(0.5,0,0.75,0.2) forwards;
    }
    @keyframes flyIntoMouth {
      0%   { transform: translate(-50%, -120%) scale(0.7) rotate(-12deg); opacity: 0; }
      25%  { opacity: 1; }
      75%  { transform: translate(-50%, 10%) scale(1.1) rotate(8deg); opacity: 1; }
      100% { transform: translate(-50%, 40%) scale(0.15) rotate(0deg); opacity: 0; }
    }
    .greeting-mascot.sprout-chomp-action { animation: sproutChomp 0.36s ease-in-out 2; transform-origin: center bottom; }
    @keyframes sproutChomp {
      0%,100% { transform: scale(1,1); }
      50% { transform: scale(1.06, 0.9); }
    }
    @media (prefers-reduced-motion: reduce) {
      .flying-food { animation-duration: 0.01s; }
      .greeting-mascot.sprout-chomp-action { animation: none; }
      .greeting-mascot.sprout-dance-action { animation: none; }
    }

    /* ---- Growing garden ---- */
    /* Grass tuft colours, themed via variables so the blades recolour with
       the rest of the app. Defaults here are the light-theme greens; each
       theme below overrides --grass-front/-back. Deliberately true greens
       (not the app's teal --sprout-green) so the lawn reads as grass rather
       than cyan, especially on the dark night card. */
    .garden-plot {
      --grass-front: #0E8C7A;
      --grass-back: #00594E;
      --grass-sky-top: #fbfdfc;
      --grass-sky-bot: #eef8f5;
      --grass-border: rgba(14,140,122,0.18);
      position: relative;
      display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; align-items: flex-end;
      padding: 16px 14px 26px; margin-top: 8px;
      background: linear-gradient(180deg, var(--grass-sky-top) 0%, var(--grass-sky-bot) 72%);
      border-radius: var(--radius-md);
      border: 2px solid var(--grass-border);
      min-height: 64px;
      overflow: hidden;
    }
    /* Back tuft layer — taller thin blades, darker, sits behind (offset from
       the front layer so the two interleave into a fuller lawn). */
    .garden-plot::before {
      content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 26px;
      z-index: 1; pointer-events: none; opacity: 0.6;
      background-color: var(--grass-back);
      -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='26' viewBox='0 0 40 26'%3E%3Cg fill='black'%3E%3Cpath d='M2 26 L4 4 L6 26 Z'/%3E%3Cpath d='M9 26 L11 9 L13 26 Z'/%3E%3Cpath d='M16 26 L18 2 L20 26 Z'/%3E%3Cpath d='M23 26 L25 10 L27 26 Z'/%3E%3Cpath d='M30 26 L32 5 L34 26 Z'/%3E%3Cpath d='M36 26 L38 11 L40 26 Z'/%3E%3C/g%3E%3C/svg%3E");
      mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='26' viewBox='0 0 40 26'%3E%3Cg fill='black'%3E%3Cpath d='M2 26 L4 4 L6 26 Z'/%3E%3Cpath d='M9 26 L11 9 L13 26 Z'/%3E%3Cpath d='M16 26 L18 2 L20 26 Z'/%3E%3Cpath d='M23 26 L25 10 L27 26 Z'/%3E%3Cpath d='M30 26 L32 5 L34 26 Z'/%3E%3Cpath d='M36 26 L38 11 L40 26 Z'/%3E%3C/g%3E%3C/svg%3E");
      -webkit-mask-repeat: repeat-x; mask-repeat: repeat-x;
      -webkit-mask-size: 40px 26px; mask-size: 40px 26px;
      -webkit-mask-position: bottom left; mask-position: bottom left;
    }
    /* Front tuft layer — shorter fuller blades in the main grass colour. */
    .garden-plot::after {
      content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 20px;
      z-index: 1; pointer-events: none;
      background-color: var(--grass-front);
      -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='36' height='20' viewBox='0 0 36 20'%3E%3Cg fill='black'%3E%3Cpath d='M0 20 L3 6 L6 20 Z'/%3E%3Cpath d='M6 20 L9 10 L12 20 Z'/%3E%3Cpath d='M12 20 L15 4 L18 20 Z'/%3E%3Cpath d='M18 20 L21 11 L24 20 Z'/%3E%3Cpath d='M24 20 L27 7 L30 20 Z'/%3E%3Cpath d='M30 20 L33 12 L36 20 Z'/%3E%3C/g%3E%3C/svg%3E");
      mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='36' height='20' viewBox='0 0 36 20'%3E%3Cg fill='black'%3E%3Cpath d='M0 20 L3 6 L6 20 Z'/%3E%3Cpath d='M6 20 L9 10 L12 20 Z'/%3E%3Cpath d='M12 20 L15 4 L18 20 Z'/%3E%3Cpath d='M18 20 L21 11 L24 20 Z'/%3E%3Cpath d='M24 20 L27 7 L30 20 Z'/%3E%3Cpath d='M30 20 L33 12 L36 20 Z'/%3E%3C/g%3E%3C/svg%3E");
      -webkit-mask-repeat: repeat-x; mask-repeat: repeat-x;
      -webkit-mask-size: 36px 20px; mask-size: 36px 20px;
      -webkit-mask-position: bottom left; mask-position: bottom left;
    }
    /* Night: warm true-greens, not the cyan mint, so the lawn stays "grass"
       against the dark navy card. */
    body.theme-night .garden-plot {
      --grass-front: #3DBB8E; --grass-back: #1E7A5A;
      --grass-sky-top: #1f2647; --grass-sky-bot: #171d3a;
      --grass-border: rgba(61,187,142,0.22);
    }
    body.theme-contrast .garden-plot {
      --grass-front: #00FF00; --grass-back: #00b800;
      --grass-sky-top: #000000; --grass-sky-bot: #0a0a0a;
      --grass-border: #FFFFFF;
    }
    body.theme-contrast-light .garden-plot {
      --grass-front: #1B5E20; --grass-back: #0d3d13;
      --grass-sky-top: #FFFFFF; --grass-sky-bot: #f4f4f4;
      --grass-border: #000000;
    }
    .garden-plant {
      position: relative;
      z-index: 2;
      font-size: 26px; line-height: 1;
      background: none; border: none; padding: 0; cursor: pointer;
      -webkit-tap-highlight-color: transparent;
      animation: plantPop 0.5s cubic-bezier(0.175,0.885,0.32,1.4) both;
    }
    /* Watering only ever adds: a damp patch and a bead of dew that stay for
       good. A plant that has never been watered still looks perfectly happy. */
    .garden-plant.is-watered { filter: saturate(1.12); }
    .garden-plant.is-watered::after {
      content: ''; position: absolute; left: 50%; bottom: -4px;
      transform: translateX(-50%); width: 22px; height: 5px; border-radius: 50%;
      background: rgba(14,140,122,0.3); pointer-events: none;
    }
    .garden-plant.is-watered::before {
      content: ''; position: absolute; top: -1px; right: -2px;
      width: 7px; height: 7px; border-radius: 50% 50% 50% 0;
      transform: rotate(-45deg); pointer-events: none;
      background: linear-gradient(160deg, #DCF3FF, #5AB6E8);
      box-shadow: 0 0 0 1px rgba(255,255,255,0.55);
    }
    .garden-plant.drink { animation: plantDrink 0.6s ease; }
    @keyframes plantDrink {
      0%,100% { transform: translateY(0) scale(1,1); }
      35% { transform: translateY(2px) scale(1.12,0.88); }
      70% { transform: translateY(-3px) scale(0.94,1.1); }
    }
    .garden-drop, .garden-splash { position: absolute; pointer-events: none; }
    .garden-drop {
      top: -12px; width: 6px; height: 9px; border-radius: 50% 50% 50% 0;
      background: linear-gradient(160deg, #DCF3FF, #4FA8DC);
      animation: dropFall 0.6s ease-in forwards;
    }
    @keyframes dropFall {
      0%   { opacity: 0; transform: translateY(-6px) rotate(-45deg) scale(0.6); }
      25%  { opacity: 1; }
      100% { opacity: 0; transform: translateY(24px) rotate(-45deg) scale(1); }
    }
    .garden-splash {
      left: 50%; bottom: -3px; width: 10px; height: 10px; border-radius: 50%;
      border: 2px solid rgba(90,182,232,0.85);
      animation: splashRing 0.5s ease-out forwards;
    }
    @keyframes splashRing {
      0%   { opacity: 0.9; transform: translateX(-50%) scale(0.3); }
      100% { opacity: 0; transform: translateX(-50%) scale(2.4); }
    }
    .garden-plant:focus-visible { outline: 3px solid var(--sky); outline-offset: 3px; border-radius: 6px; }
    .garden-plant.wiggle { animation: plantWiggle 0.5s ease; }
    @keyframes plantWiggle {
      0%,100% { transform: rotate(0) scale(1); }
      30% { transform: rotate(-12deg) scale(1.25); }
      65% { transform: rotate(10deg) scale(1.15); }
    }
    /* Golden plants: ~1 in 50, purely decorative — a soft pulsing glow plus
       a tiny twinkle riding alongside the plant (a sibling span, not a
       pseudo-element, since ::before/::after on .garden-plant are already
       spoken for by the watered-state dew drop and can co-occur). */
    .garden-plant.is-golden {
      animation: plantPop 0.5s cubic-bezier(0.175,0.885,0.32,1.4) both, goldenPulse 2.2s ease-in-out infinite;
    }
    .garden-plant.is-golden.is-watered { filter: saturate(1.12); }
    @keyframes goldenPulse {
      0%,100% { filter: drop-shadow(0 0 3px rgba(255,196,40,0.65)); }
      50% { filter: drop-shadow(0 0 8px rgba(255,210,80,0.95)); }
    }
    .golden-sparkle {
      position: absolute; top: -9px; right: -7px; font-size: 11px;
      pointer-events: none; animation: goldenTwinkle 1.7s ease-in-out infinite;
    }
    @keyframes goldenTwinkle {
      0%,100% { opacity: 0.35; transform: scale(0.8) rotate(0deg); }
      50% { opacity: 1; transform: scale(1.15) rotate(14deg); }
    }
    /* A rare cameo drifting across whichever bed is on screen — not part of
       the flower-count critter system, never saved, gone in a few seconds. */
    .garden-rare-visitor {
      position: absolute; top: 8px; left: -32px; font-size: 24px;
      pointer-events: none; z-index: 3;
      animation: rareVisitorDrift 5s linear forwards;
    }
    @keyframes rareVisitorDrift {
      0%   { left: -32px; opacity: 0; transform: translateY(0) rotate(0deg); }
      10%  { opacity: 1; }
      50%  { transform: translateY(-16px) rotate(8deg); }
      90%  { opacity: 1; }
      100% { left: 105%; opacity: 0; transform: translateY(8px) rotate(-8deg); }
    }
    /* Visitors drift rather than pop — they arrived, they weren't planted. */
    .garden-critter {
      position: relative;
      font-size: 22px; line-height: 1; align-self: flex-end;
      background: none; border: none; padding: 0; cursor: pointer;
      -webkit-tap-highlight-color: transparent;
      animation: critterFloat 3.2s ease-in-out infinite;
    }
    .garden-critter:focus-visible { outline: 3px solid var(--sky); outline-offset: 3px; border-radius: 6px; }
    /* Fed visitors keep a faint golden shimmer. Nothing here ever gets hungry. */
    .garden-critter.is-fed { filter: drop-shadow(0 0 3px rgba(255,190,60,0.95)); }
    .garden-critter.happy { animation: critterHappy 0.85s ease; }
    @keyframes critterHappy {
      0%   { transform: translateY(0) rotate(0); }
      45%  { transform: translateY(-12px) rotate(180deg); }
      100% { transform: translateY(0) rotate(360deg); }
    }
    .garden-nectar, .garden-pollen { position: absolute; pointer-events: none; }
    .garden-nectar {
      left: 50%; bottom: -7px; width: 9px; height: 9px; border-radius: 50%;
      background: radial-gradient(circle at 32% 30%, #FFEEB4, #F2A93B);
      animation: nectarSip 0.75s ease-in forwards;
    }
    @keyframes nectarSip {
      0%   { opacity: 0; transform: translate(-50%, 8px) scale(0.4); }
      30%  { opacity: 1; transform: translate(-50%, 0) scale(1); }
      100% { opacity: 0; transform: translate(-50%, -3px) scale(0.25); }
    }
    .garden-pollen {
      top: 4px; width: 5px; height: 5px; border-radius: 50%;
      background: #FFD25A; box-shadow: 0 0 4px rgba(255,196,60,0.9);
      animation: pollenRise 0.8s ease-out forwards;
    }
    @keyframes pollenRise {
      0%   { opacity: 0; transform: translateY(0) scale(0.5); }
      30%  { opacity: 1; }
      100% { opacity: 0; transform: translateY(-17px) scale(1); }
    }
    @keyframes critterFloat {
      0%,100% { transform: translateY(0) rotate(-4deg); }
      50% { transform: translateY(-7px) rotate(4deg); }
    }
    .garden-nav {
      display: flex; align-items: center; justify-content: center; gap: 12px;
      margin-top: 10px;
    }
    .garden-nav[hidden] { display: none; }
    .garden-nav button {
      width: 34px; height: 34px; border-radius: 50%; cursor: pointer;
      border: 2px solid rgba(14,140,122,0.3); background: var(--card);
      color: var(--sprout-green-deep); font-size: 0.8rem; line-height: 1;
      -webkit-tap-highlight-color: transparent;
    }
    .garden-nav button:disabled { opacity: 0.35; cursor: default; }
    .garden-nav button:focus-visible { outline: 3px solid var(--sky); outline-offset: 2px; }
    body.theme-night .garden-nav button { background: #1B2140; }
    #gardenBedLabel {
      font-family: 'Nunito', sans-serif; font-weight: 800; font-size: 0.8rem;
      color: var(--ink-soft); min-width: 92px; text-align: center;
    }
    .garden-note {
      font-family: 'Nunito', sans-serif; font-weight: 700; font-size: 0.76rem;
      color: var(--ink-soft); text-align: center; margin-top: 4px; line-height: 1.4;
    }
    .garden-note[hidden] { display: none; }
    .garden-caption.is-memory { color: var(--ink); line-height: 1.4; }
    .garden-memory-name { font-weight: 900; }
    .garden-actions {
      display: flex; justify-content: center; align-items: center;
      gap: 8px; flex-wrap: wrap; margin-top: 8px;
    }
    .garden-actions[hidden] { display: none; }
    .garden-action {
      font-family: 'Nunito', sans-serif; font-weight: 800; font-size: 0.78rem;
      color: var(--ink); background: var(--card); cursor: pointer;
      border: 2px solid rgba(14,140,122,0.35); border-radius: 999px;
      padding: 6px 13px; -webkit-tap-highlight-color: transparent;
    }
    .garden-action:focus-visible { outline: 3px solid var(--sky); outline-offset: 2px; }
    .garden-action.is-done { border-style: dotted; color: var(--ink-soft); }
    body.theme-night .garden-action { background: #1B2140; }
    .garden-name-input {
      font-family: 'Nunito', sans-serif; font-weight: 800; font-size: 0.82rem;
      color: var(--ink); background: var(--card); text-align: center;
      border: 2px solid rgba(14,140,122,0.45); border-radius: 999px;
      padding: 6px 12px; width: 148px; max-width: 55%;
    }
    .garden-name-input:focus-visible { outline: 3px solid var(--sky); outline-offset: 2px; }
    body.theme-night .garden-name-input { background: #1B2140; }
    .garden-memory-quip {
      display: block; font-family: 'Nunito', sans-serif; font-weight: 700;
      font-size: 0.76rem; color: var(--ink-soft); margin-top: 3px;
    }
    @keyframes plantPop { 0% { transform: scale(0) translateY(8px); } 100% { transform: scale(1) translateY(0); } }
    .garden-empty { position: relative; z-index: 2; font-family:'Nunito',sans-serif; font-weight:700; color:var(--ink-soft); font-size:0.85rem; align-self:center; }
    .garden-caption { font-family:'Nunito',sans-serif; font-weight:800; color:var(--ink-soft); font-size:0.82rem; text-align:center; margin-top:10px; min-height: 2.6em; }
    @media (prefers-reduced-motion: reduce) {
      .garden-plant, .garden-plant.wiggle, .garden-plant.drink, .garden-plant.is-golden,
      .golden-sparkle, .garden-rare-visitor,
      .garden-critter, .garden-critter.happy { animation: none; }
    }

    /* ---- Full-screen level-up takeover ---- */
    .levelup-overlay {
      position: fixed; inset: 0; z-index: 9999;
      display: none; align-items: center; justify-content: center;
      background: radial-gradient(circle at center, rgba(14,140,122,0.55), rgba(11,18,40,0.92));
      backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
      text-align: center; padding: 24px;
    }
    .levelup-overlay.show { display: flex; animation: luFade 0.3s ease; }
    @keyframes luFade { from { opacity: 0; } to { opacity: 1; } }
    .levelup-inner { position: relative; z-index: 2; }
    .levelup-icon { font-size: 5rem; line-height: 1; animation: luPop 0.6s cubic-bezier(0.175,0.885,0.32,1.4) both; }
    @keyframes luPop { 0% { transform: scale(0) rotate(-25deg); } 70% { transform: scale(1.25) rotate(8deg); } 100% { transform: scale(1) rotate(0); } }
    .levelup-kicker {
      font-family: 'Baloo 2', sans-serif; font-weight: 800; letter-spacing: 0.12em;
      text-transform: uppercase; font-size: 0.95rem; color: #FFE194; margin-top: 10px;
    }
    .levelup-title {
      font-family: 'Baloo 2', sans-serif; font-weight: 800; color: #FFFFFF;
      font-size: 2.1rem; line-height: 1.1; margin: 4px 0 6px;
      text-shadow: 0 3px 0 rgba(0,0,0,0.25);
    }
    .levelup-sub { font-family:'Nunito',sans-serif; font-weight:800; color:#DFF7EF; font-size:1rem; margin-bottom:22px; }
    .levelup-btn {
      border: none; padding: 14px 34px; border-radius: 999px;
      background: var(--sun); color: #4A3B00; font-family:'Baloo 2',sans-serif;
      font-weight: 800; font-size: 1.1rem; cursor: pointer;
      box-shadow: 0 6px 0 rgba(0,0,0,0.2);
    }
    .levelup-btn:active { transform: translateY(3px); box-shadow: none; }
    @media (prefers-reduced-motion: reduce) {
      .levelup-icon, .levelup-overlay.show { animation: none; }
    }

    .shortcut-share-container {
      margin-top: 14px;
      display: none;
      animation: pop 0.4s ease;
    }
    .shortcut-share-btn {
      width: 100%; border: 3px solid var(--sky); padding: 14px;
      background: var(--card); color: var(--sky);
      font-family: 'Baloo 2', sans-serif; font-weight: 800; font-size: 1.05rem;
      border-radius: 18px; cursor: pointer;
      display: flex; align-items: center; justify-content: center; gap: 8px;
      box-shadow: 0 4px 12px var(--shadow);
      transition: background 0.2s, transform 0.1s;
    }
    .shortcut-share-btn:active { transform: scale(0.98); }

    .confirm-share-btn {
      width: 100%; border: none; padding: 12px; background: var(--sky); color: white;
      font-family: 'Baloo 2', sans-serif; font-weight: 800; font-size: 1rem; border-radius: 12px;
      cursor: pointer; box-shadow: 0 4px 10px rgba(63,169,245,0.25);
      transition: all 0.2s ease, transform 0.1s ease;
    }
    .confirm-share-btn:disabled { background: #B0BEC5 !important; color: #FFFFFF !important; opacity: 0.6; cursor: not-allowed; box-shadow: none; }

    .badges-current-rank {
      display: flex; align-items: center; gap: 9px;
      background: #FFF4D6; border: 1.5px solid #FBBF24; border-radius: 12px;
      padding: 9px 11px; margin-bottom: 10px;
    }
    body.theme-night .badges-current-rank { background: rgba(255,193,7,0.14); border-color: rgba(255,193,7,0.4); }
    .badges-current-rank-icon { font-size: 1.3rem; flex: 0 0 auto; }
    .badges-current-rank-text {
      font-family: 'Nunito', sans-serif; font-weight: 700; font-size: 0.76rem;
      color: #8A5A00; line-height: 1.35;
    }
    body.theme-night .badges-current-rank-text { color: #FFD98A; }
    .badges-current-rank-text b { font-family: 'Baloo 2', sans-serif; font-weight: 800; }
    .badges-grid {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 12px 6px;
      margin-top: 4px;
    }
    .badge-item {
      background: var(--bg);
      border: 2px solid var(--bg2);
      border-radius: 14px;
      padding: 10px 2px;
      text-align: center;
      font-size: 0.72rem;
      font-weight: 800;
      opacity: 0.35;
      filter: grayscale(100%);
      position: relative;
      transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
    }
    body.theme-night .badge-item { background: #1B2140; border-color: #262C52; }
    .badge-item.unlocked {
      opacity: 1;
      filter: grayscale(0%);
      border-color: var(--mint);
      background: rgba(46, 196, 182, 0.08);
      cursor: help;
    }
    .badge-item:not(.unlocked):hover {
      opacity: 0.85;
      transform: translateY(-2px);
    }
    .badge-icon {
      font-size: 1.75rem;
      margin-bottom: 3px;
      display: block;
    }
    .badge-title {
      color: var(--ink);
      line-height: 1.2;
      display: block;
    }

    .badge-item.unlocked::after {
      content: "Earned: " attr(data-hint);
      position: absolute;
      bottom: 105%;
      left: 50%;
      transform: translateX(-50%) translateY(4px);
      background: #1F2A44;
      color: #FFFFFF;
      padding: 6px 10px;
      border-radius: 8px;
      font-size: 0.72rem;
      font-weight: 700;
      line-height: 1.3;
      white-space: normal;
      width: 100px;
      opacity: 0;
      pointer-events: none;
      transition: opacity 0.2s ease, transform 0.2s ease;
      box-shadow: 0 4px 12px rgba(0,0,0,0.35);
      border: 1px solid rgba(255,255,255,0.15);
      z-index: 1000;
    }
    .badge-item.unlocked:hover::after, .badge-item.unlocked:focus::after {
      opacity: 1;
      transform: translateX(-50%) translateY(0);
    }

    @keyframes pop {
      0% { transform: scale(0.85); opacity: 0; }
      100% { transform: scale(1); opacity: 1; }
    }
    
    .result-card {
      background: linear-gradient(135deg, var(--mint), #004D40);
      border-radius: 18px; padding: 20px 18px; color: white; text-align: center;
      box-shadow: 0 10px 28px var(--shadow); margin-bottom: 12px; display: none;
    }
    .result-card.show { display: block; animation: pop .5s ease; }
    .result-num { font-family: 'Baloo 2', sans-serif; font-size: 2.6rem; font-weight: 800; line-height: 1; }
    .result-label { font-weight: 700; opacity: 0.9; margin-top: 2px; }
    .sprout-says { margin-top: 12px; background: rgba(255,255,255,0.2); border-radius: 14px; padding: 10px 12px; font-weight: 700; font-size: 0.9rem; }

    .meal-log-card {
      background: var(--card); border-radius: var(--radius-lg); padding: 20px 18px;
      box-shadow: 0 10px 28px var(--shadow); margin-bottom: 18px; display: none;
    }
    .garden-card {
      position: relative;
      background: var(--card); border-radius: var(--radius-lg); padding: 20px 18px;
      box-shadow: 0 10px 28px var(--shadow); margin-bottom: 18px;
    }
    /* Decorative rainbow band removed by request — the plot keeps its soft
       green tint (from .garden-plot's own background) and dashed border, so
       plants still sit on a subtle backdrop rather than a bare card. */
    .meal-log-card.show { display: block; animation: pop .5s ease; }
    .meal-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; border-bottom: 2px dashed var(--bg2); padding-bottom: 8px; }
    .meal-header h2 { font-size: 1.15rem; }
    .meal-header-total { font-size: 0.85rem; font-weight: 800; color: var(--sky); margin-top: 2px; }
    .clear-btn { background: none; border: none; color: var(--mint); font-weight: 800; font-size: 0.85rem; cursor: pointer; }

    /* Promoted "Log This Meal" CTA (3 Sep 2026). Deliberately matches
       .go-btn's visual weight — it IS the same class of action (a primary
       commit), and previously it was a 0.85rem text link while the
       intermediate "add food" step got the hero treatment. That
       hierarchy was backwards. */
    .log-meal-btn {
      width: 100%;
      margin-top: 14px;
      border: none;
      padding: 14px 16px;
      background: linear-gradient(135deg, var(--sprout-green), var(--sprout-green-deep));
      color: #fff;
      border-radius: 18px;
      cursor: pointer;
      box-shadow: 0 8px 18px rgba(0,89,78,0.32);
      display: flex; flex-direction: column; align-items: center; gap: 3px;
      -webkit-tap-highlight-color: transparent;
    }
    .log-meal-btn:active { transform: scale(0.985); }
    .log-meal-btn-main {
      font-family: 'Baloo 2', sans-serif; font-weight: 700; font-size: 1.15rem;
    }
    .log-meal-btn-sub {
      display: flex; align-items: center; gap: 6px;
      font-size: 0.76rem; font-weight: 700;
      color: rgba(255,255,255,0.92);
    }
    .log-meal-btn-stickers { display: inline-flex; align-items: center; gap: 2px; }
    .log-meal-btn-stickers img { width: 20px; height: 20px; display: block; }

    /* Post-log reward panel. Appears where the meal card was, instantly.
       See index.html's own comment on #mealLoggedPanel for why this is a
       panel rather than a toast.

       BUG (found 5 Sep 2026, reported as "the sticker panel never
       appears"): the animation was declared here, on the base selector,
       not on .show below. CSS animations start the moment an element
       MATCHES their selector — independent of display:none — so this ran
       to completion while the panel was still hidden, before JS ever
       added .show. By the time .show flipped display to block, the
       animation declaration hadn't changed, so it never re-triggered.
       Net effect: window.showMealLoggedPanel() was executing correctly
       (confirmed by tracing call order, DOM position, and findEntry
       matching — all fine) and the panel was structurally present, but
       visually never appeared. Moved the animation onto .show, which is
       the actual state transition that should trigger it. */
    .meal-logged-panel {
      display: none;
      background: var(--card);
      border-radius: var(--radius-lg);
      box-shadow: 0 8px 24px var(--shadow);
      padding: 16px;
      margin-bottom: 18px;
    }
    .meal-logged-panel.show {
      display: block;
      animation: mealLoggedPanelIn 0.25s ease-out;
    }
    @keyframes mealLoggedPanelIn {
      from { opacity: 0; transform: translateY(8px); }
      to { opacity: 1; transform: translateY(0); }
    }
    @media (prefers-reduced-motion: reduce) {
      .meal-logged-panel.show { animation: none; }
    }
    .meal-logged-panel-head { display: flex; align-items: center; gap: 10px; }
    .meal-logged-panel-tick { font-size: 1.5rem; line-height: 1; }
    .meal-logged-panel-title {
      font-family: 'Baloo 2', sans-serif; font-weight: 800; font-size: 1.15rem; color: var(--ink);
    }
    .meal-logged-panel-total { font-size: 0.82rem; font-weight: 700; color: var(--ink-soft); }
    .meal-logged-panel-close {
      margin-left: auto; background: none; border: none; cursor: pointer;
      color: var(--ink-soft); font-size: 1rem;
      width: 44px; height: 44px; display: flex; align-items: center; justify-content: center;
    }
    .meal-logged-panel-ask {
      margin: 12px 0 8px; text-align: center;
      font-weight: 800; font-size: 0.9rem; color: var(--ink);
    }

    .meal-item {
      display: flex; justify-content: space-between; align-items: center;
      padding: 10px 12px; background: var(--bg); border-radius: 12px; margin-bottom: 8px;
    }
    body.theme-night .meal-item { background: #1B2140; }
    .theme-contrast .meal-item, body.theme-contrast-light .meal-item { background: var(--bg2); border: 1px solid var(--ink); }
    .meal-item-name-wrap { flex: 1; cursor: pointer; }
    .meal-item-emoji { font-size: 22px; line-height: 1; margin-right: 10px; flex: 0 0 auto; }
    .meal-item-title { font-weight: 800; color: var(--ink); text-transform: capitalize; }
    .rename-hint { font-size: 0.7rem; color: var(--ink-soft); font-weight: 600; margin-left: 6px; }
    .meal-item-details { font-size: 0.75rem; color: var(--ink-soft); font-weight: 600; margin-top: 2px; }
    .meal-item-val { font-weight: 800; color: var(--ink); margin: 0 10px; font-family: 'Baloo 2', sans-serif; }
    .del-btn { background: none; border: none; color: var(--ink-soft); font-size: 20px; cursor: pointer; padding: 0 4px; }
    /* Sits between the value and the bin. Deliberately quieter than the carb
       figure next to it — a repeat is a convenience, not the thing being read. */
    /* Border and glyph follow --ink so the ring reads as a clear outline in
       every theme: near-white on the dark themes, near-black on the light
       ones. var(--bg2) was a background tint in several palettes, which left
       the circle almost invisible against the row it sits on. */
    .repeat-btn { background: var(--bg); border: 1.5px solid var(--ink); color: var(--ink);
      font-family: 'Nunito', sans-serif; font-weight: 800;
      font-size: calc(12px * var(--font-scale, 1)); line-height: 1;
      border-radius: 999px; padding: 0 10px; margin-right: 2px; cursor: pointer;
      min-height: 34px; min-width: 40px; }
    .repeat-btn:hover, .repeat-btn:focus-visible { border-color: var(--sprout-green); color: var(--sprout-green); }
    .repeat-btn:active { transform: scale(0.94); }
    @media (prefers-reduced-motion: reduce) { .repeat-btn:active { transform: none; } }
    
    .disclaimer { text-align: center; font-size: 0.75rem; color: var(--ink-soft); margin-top: 24px; font-weight: 700; line-height: 1.4; padding: 0 12px; }
    
    .overlay { position: fixed; inset: 0; background: rgba(31,42,68,0.5); backdrop-filter: blur(4px); z-index: 10; display: none; opacity: 0; transition: opacity 0.3s; }
    .overlay.show { display: block; opacity: 1; }
    
    .drawer {
      position: fixed; top: 0; bottom: 0; right: 0; width: 295px; background: var(--card); z-index: 20;
      padding: 24px 16px 30px; transform: translateX(100%); transition: transform .35s ease;
      box-shadow: -10px 0 30px rgba(0,0,0,0.2); overflow-y: auto;
    }
    .drawer.show { transform: translateX(0); }
    .drawer h2 { font-size: 1.2rem; margin-bottom: 14px; }
    .drawer .close-btn { position: absolute; top: 16px; right: 16px; border: none; background: none; font-size: 22px; cursor: pointer; color: var(--ink-soft); }

    /* .drawer-left removed 4 Sep 2026 — it was only ever used by
       #favDrawer (My Meals), which became a full-width bottom sheet.
       The 295px side-drawer width was the root cause of the truncation
       and icon-wrap problems patched in v1.16.0; widening the container
       removed the constraint instead of managing it. TO REVERT: restore
       `.drawer-left { left:0; right:auto; transform:translateX(-100%);
       box-shadow:10px 0 30px rgba(0,0,0,0.2); }` plus its `.show` rule,
       and put `class="drawer drawer-left"` back on #favDrawer. */

    /* My Meals bottom sheet. Structure mirrors the existing
       .sprout-score-sheet (handle, slide-up, pinned to the bottom of a
       flex-end overlay) rather than inventing a second sheet idiom. */
    .meals-sheet {
      position: fixed; inset: 0; z-index: 30;
      display: none; align-items: flex-end; justify-content: center;
      background: rgba(0,0,0,0.5);
    }
    .meals-sheet.show { display: flex; }
    .meals-sheet-inner {
      width: 100%; max-width: 440px;
      max-height: 85vh; overflow-y: auto;
      background: var(--bg);
      border-radius: 26px 26px 0 0;
      padding: 10px 16px 26px;
      animation: mealsSheetUp 0.28s ease-out;
    }
    @keyframes mealsSheetUp {
      from { transform: translateY(100%); }
      to { transform: translateY(0); }
    }
    @media (prefers-reduced-motion: reduce) {
      .meals-sheet-inner { animation: none; }
    }
    .meals-sheet-inner .sheet-handle {
      width: 40px; height: 5px; border-radius: 999px;
      background: var(--bg2);
      margin: 0 auto 12px;
    }
    .meals-sheet-head {
      display: flex; align-items: center; justify-content: space-between;
      gap: 10px; margin-bottom: 6px;
    }
    .meals-sheet-head h2 { font-size: 1.15rem; margin: 0; }
    .meals-sheet-close {
      flex: 0 0 auto; width: 44px; height: 44px;
      background: var(--card); border: none; border-radius: 12px;
      color: var(--ink-soft); font-size: 1rem; cursor: pointer;
      display: flex; align-items: center; justify-content: center;
      -webkit-tap-highlight-color: transparent;
    }
    .meals-sheet-close:active { transform: scale(0.92); }
    /* The shared .fav-search-wrap is --bg, which is also the sheet's own
       surface — invisible. Scoped override rather than changing the
       shared rule, which the food search and favourite-foods panels
       also use on --card surfaces where --bg is correct. */
    .meals-sheet .fav-search-wrap { background: var(--card); }
    .fav-drawer-hint { font-size: 0.8rem; font-weight: 600; color: var(--ink-soft); line-height: 1.4; margin-bottom: 14px; }

    .fav-search-wrap {
      display: none; align-items: center; gap: 8px; background: var(--bg); border: 2px solid var(--bg2);
      border-radius: 12px; padding: 9px 12px; margin-bottom: 14px;
    }
    .fav-search-wrap.show { display: flex; }
    .fav-search-icon { font-size: 0.9rem; flex-shrink: 0; opacity: 0.7; }
    .fav-search-input {
      border: none; background: transparent; outline: none; color: var(--ink); font-weight: 700;
      /* Was 0.9rem (14.4px) — under Safari's 16px auto-zoom-on-focus
         threshold, so focusing this field zoomed the whole viewport in on
         iOS. TO REVERT: back to 0.9rem. */
      font-size: 1rem; width: 100%; font-family: inherit; min-width: 0;
    }
    .fav-search-input::placeholder { color: var(--ink-soft); font-weight: 600; }
    body.theme-night .fav-search-wrap { background: #1B2140; border-color: #262C52; }

    .fav-empty-state { display: flex !important; flex-direction: column; align-items: center; gap: 6px; padding: 26px 8px !important; text-align: center; }
    .fav-empty-icon { font-size: 2.2rem; margin-bottom: 2px; }

    /* ---- Favourite MEALS as a compact list (matches fav-list-row foods view) ---- */
    .fav-mrow {
      border-bottom: 1px solid var(--bg2); animation: pop 0.3s ease;
    }
    .fav-mrow:last-child { border-bottom: none; }
    /* ============================================================
       FAVOURITE MEAL ROW — REDESIGNED. A previous fix stacked name
       above meta so the meta text stopped stealing the name's width —
       real improvement, but it only changed the RATIO of space, and the
       underlying assumption was still wrong: #saveFavInput allows up to
       40 characters (maxlength="40", confirmed in index.html), so a
       favourite meal's name isn't really a short label like "Pizza" —
       it's closer to a short SENTENCE a caregiver deliberately typed
       (e.g. "Wednesday After School Snack With Extra Biscuits").
       Single-line-plus-ellipsis is the wrong
       treatment for that: it silently throws away exactly the
       information the caregiver bothered to write, right when they
       need to tell several saved meals apart in a scannable list.
       Redesign: the name now wraps to up to two lines instead of
       truncating to one (line-clamp), and meta/chevron move to their
       own row underneath so the row's height flexes naturally per item
       rather than every row being forced to one fixed height regardless
       of name length. Padding increased so two-line rows don't feel
       cramped against their neighbours in a list.
       ============================================================ */
    .fav-mrow-main {
      display: flex; align-items: flex-start; gap: 10px; padding: 13px 4px;
      cursor: pointer; user-select: none; -webkit-user-select: none;
      -webkit-tap-highlight-color: transparent;
    }
    .fav-mrow-main:active { background: var(--bg); }
    body.theme-night .fav-mrow-main:active { background: #131737; }
    .fav-mrow-main:focus-visible { outline: 2px solid var(--sky); outline-offset: 1px; }
    .fav-mrow-avatar { font-size: 18px; width: 26px; text-align: center; flex-shrink: 0; margin-top: 1px; }
    .fav-mrow-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
    .fav-mrow-name {
      font-size: 0.9rem; font-weight: 800; color: var(--ink); line-height: 1.28;
      font-family: 'Baloo 2', sans-serif;
      /* Wraps up to 2 lines instead of truncating to 1 (see the block
         comment above) — a genuinely long name (up to 40 chars) stays
         readable rather than being cut down to its first ~20
         characters. A -webkit-line-clamp value still needs a fallback
         for the rare non-WebKit engine; the fallback simply lets a
         very long single word overflow rather than break mid-word,
         which is an acceptable rare-case trade-off. */
      display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
      overflow: hidden; word-break: break-word;
    }
    .fav-mrow-meta-row {
      display: flex; align-items: center; justify-content: space-between; gap: 8px;
    }
    .fav-mrow-meta {
      font-size: 0.72rem; color: var(--ink-soft); font-weight: 700;
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
    }
    .fav-mrow-chevron {
      font-size: 1rem; color: var(--ink-soft); flex-shrink: 0;
      transition: transform 0.2s ease; width: 20px; text-align: center;
    }
    .fav-mrow-chevron.open { transform: rotate(180deg); }
    .fav-mrow-details {
      display: none; flex-direction: column; gap: 5px; padding: 0 4px 12px 36px;
    }
    .fav-mrow-details.open { display: flex; animation: pop 0.2s ease; }
    .fav-mrow-detail-item {
      display: flex; justify-content: space-between; gap: 8px;
      font-size: 0.75rem; font-weight: 600; color: var(--ink-soft);
    }
    .fav-mrow-details-footer {
      display: flex; align-items: center; justify-content: space-between; gap: 8px;
      margin-top: 6px; padding-top: 8px; border-top: 1px dashed var(--bg2);
    }

    .fav-meal-quick-add {
      background: none; border: none; color: var(--mint); font-weight: 800; font-size: 0.75rem;
      cursor: pointer; padding: 4px 6px; font-family: 'Baloo 2', sans-serif;
      -webkit-tap-highlight-color: transparent;
    }
    .fav-meal-quick-add:active { opacity: 0.7; }

    .fav-meal-edit-btn {
      background: none; border: none; color: var(--sky); font-weight: 800; font-size: 0.75rem;
      cursor: pointer; padding: 4px 6px; font-family: 'Baloo 2', sans-serif; -webkit-tap-highlight-color: transparent;
    }
    .fav-meal-edit-btn:active { opacity: 0.7; }

    #favMealsList.history-container { gap: 0; max-height: none; overflow-y: visible; }

    .topbar-actions { display: flex; align-items: center; gap: 8px; }
    .fav-meals-btn { position: relative; }
    .fav-meals-btn-icon { font-size: 1.35rem; line-height: 1; }
    .fav-meals-count {
      position: absolute; top: -3px; right: -3px;
      display: none; align-items: center; justify-content: center;
      background: var(--sun); color: #6B4B00; font-family: 'Baloo 2', sans-serif;
      font-size: 0.6rem; font-weight: 800; border-radius: 999px;
      min-width: 16px; height: 16px; padding: 0 4px; line-height: 1;
      border: 2px solid var(--bg);
    }
    .fav-meals-count.show { display: inline-flex; }

    #openSettings { position: relative; }

    .save-fav-row { text-align: center; margin-top: 12px; }
    .save-fav-btn {
      background: rgba(126,87,194,0.10); border: 2px solid var(--grape); color: var(--grape); border-radius: 12px;
      padding: 12px 16px; font-weight: 800; font-size: 0.92rem; cursor: pointer; width: 100%;
      font-family: 'Baloo 2', sans-serif;
      transition: background 0.2s, transform 0.1s;
    }
    .save-fav-btn:hover { background: rgba(126,87,194,0.16); }
    .save-fav-btn:active { transform: scale(0.98); }
    .settings-group { margin-bottom: 20px; width: 100%; display: block; }
    .settings-group h3 { font-size: 0.85rem; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-soft); margin-bottom: 10px; }
    
    .drawer-accordion-header {
      position: relative;
      background: var(--bg); border-radius: 14px; padding: 12px; font-weight: 800; font-size: 0.95rem;
      color: var(--ink); display: flex; justify-content: space-between; align-items: center; cursor: pointer;
      user-select: none; -webkit-user-select: none; font-family: 'Baloo 2', sans-serif;
    }
    body.theme-night .drawer-accordion-header { background: #1B2140; }
    .drawer-accordion-content {
      display: none; padding: 12px 4px 4px 4px; animation: pop 0.25s ease;
    }
    .drawer-accordion-content.open { display: block; }
    .drawer-section-label {
      font-family: 'Baloo 2', sans-serif; font-weight: 800; font-size: 0.7rem;
      text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink-soft);
      margin: 24px 2px 12px; padding-bottom: 6px; border-bottom: 2px solid var(--bg2);
    }
    body.theme-night .drawer-section-label { border-bottom-color: #262C52; }

    /* Dismissible install banner — sits above the tabs, replacing the old
       permanent settings-group card. Dismissing it only hides it for the
       current session (sessionStorage), so it can still resurface next
       time rather than being gone for good on a stray tap. */
    .install-banner-drawer {
      display: flex; align-items: center; gap: 10px;
      background: linear-gradient(135deg, rgba(0,137,123,0.12), rgba(21,101,192,0.10));
      border: 1px solid rgba(0,137,123,0.28);
      border-radius: 14px;
      padding: 10px 10px 10px 14px;
      margin-bottom: 14px;
    }
    body.theme-night .install-banner-drawer {
      background: linear-gradient(135deg, rgba(0,137,123,0.22), rgba(21,101,192,0.18));
    }
    .install-banner-drawer p {
      flex: 1 1 auto; min-width: 0; margin: 0; font-size: 0.72rem; font-weight: 700; color: var(--ink-soft); line-height: 1.35;
    }
    .install-banner-dismiss {
      flex: 0 0 auto; background: none; border: none; color: var(--ink-soft);
      font-size: 1.1rem; line-height: 1; cursor: pointer; padding: 4px;
    }
    .install-banner-cta {
      flex: 0 0 auto; width: auto; white-space: nowrap;
      border: 2px solid var(--sky); border-radius: 100px;
      padding: 7px 14px; font-size: 0.78rem;
      background: var(--card); color: var(--sky);
      font-family: 'Baloo 2', sans-serif; font-weight: 800; cursor: pointer;
      box-shadow: none;
    }
    .install-banner-cta:active { transform: scale(0.96); }

    /* Drawer tabs: Sprout / Data / Help. Only the active tab's panel
       renders, which is the main lever for making the drawer feel less
       busy — instead of every accordion stacked in one long scroll, you
       only ever see the handful belonging to the current tab. */
    .drawer-tab-row {
      display: flex; gap: 6px; margin-bottom: 16px;
    }
    .drawer-tab-btn {
      flex: 1 1 0; background: var(--bg); border: 1.5px solid transparent; border-radius: 100px;
      padding: 8px 4px; font-family: 'Baloo 2', sans-serif; font-weight: 700; font-size: 0.74rem;
      color: var(--ink-soft); cursor: pointer; display: flex; align-items: center; justify-content: center;
      gap: 5px; transition: all 0.15s ease;
    }
    body.theme-night .drawer-tab-btn { background: #1B2140; }
    .drawer-tab-btn[aria-selected="true"] {
      background: var(--card); color: var(--sky); border-color: var(--sky);
      box-shadow: 0 3px 8px var(--shadow);
    }
    body.theme-night .drawer-tab-btn[aria-selected="true"] { background: #262C52; }
    .drawer-tab-panel[hidden] { display: none; }

    /* Merged accordions (Sprout's Look; Get in touch) hold more than one
       labeled sub-section in a single body rather than nesting another
       collapsible toggle inside — keeps the merge from just re-adding the
       complexity it was meant to remove. */
    /* Live "how Sprout looks" preview shown at the top of the Look accordion,
       above the wardrobe chips, so costume/colour changes are visible right
       where they're picked instead of only on the header mascot above the
       fold. Deliberately static (no bounce/hover animation, no tap handler)
       since it's a preview, not the interactive mascot. */
    .look-preview-wrap {
      display: flex; justify-content: center; padding: 4px 0 16px;
    }
    .look-preview-mascot {
      width: 84px; height: 84px; flex: 0 0 auto; pointer-events: none;
    }
    .drawer-accordion-content .sub-section-label {
      font-family: 'Baloo 2', sans-serif; font-weight: 800; font-size: 0.8rem;
      color: var(--ink-soft); margin: 0 0 8px;
    }
    .drawer-accordion-content .sub-section + .sub-section { margin-top: 18px; }

    .drawer-text-input {
      width: 100%; padding: 12px; border-radius: 12px; border: 2px solid var(--bg2); 
      background: var(--bg); color: var(--ink); font-weight: 700; font-size: 1rem; outline: none;
    }
    body.theme-night .drawer-text-input { background: #1B2140; border-color: #262C52; }

    .history-container {
      display: flex; flex-direction: column; gap: 12px; max-height: 250px; overflow-y: auto; width: 100%; padding-right: 4px;
    }
    .history-day-group { display: flex; flex-direction: column; gap: 4px; width: 100%; }
    .history-day-header { 
      font-size: 0.85rem; font-weight: 800; color: var(--sky); cursor: pointer; 
      padding: 10px 12px; background: var(--bg); border-radius: 12px; 
      display: flex; justify-content: space-between; align-items: center;
      font-family: 'Baloo 2', sans-serif; text-transform: capitalize;
      user-select: none; -webkit-user-select: none;
    }
    body.theme-night .history-day-header { background: #1B2140; }
    .history-day-header:active { opacity: 0.85; }
    .history-log-list { display: none; flex-direction: column; gap: 6px; margin-top: 4px; padding-left: 2px; }
    .history-log-list.open { display: flex; }
    
    .history-card-item {
      background: var(--bg); border-radius: 12px; padding: 8px 10px; font-size: 0.8rem; border-left: 4px solid var(--mint); width: 100%; box-sizing: border-box;
      display: flex; align-items: center; justify-content: space-between; gap: 8px;
    }
    body.theme-night .history-card-item { background: #1B2140; border-color: var(--mint); }
    .history-card-content-wrap { flex: 1; min-width: 0; }
    .history-card-time { font-weight: 800; color: var(--ink); margin-bottom: 2px; display: flex; justify-content: space-between; align-items: center; }
    .history-card-total { font-family: 'Baloo 2', sans-serif; font-weight: 800; color: var(--berry); font-size: 0.9rem; }
    .history-card-details { font-weight: 600; color: var(--ink-soft); line-height: 1.3; word-break: break-word; }
    .history-empty-state { font-size: 0.8rem; font-weight: 700; color: var(--ink-soft); text-align: center; padding: 12px 0; width: 100%; }
    .history-del-btn { background: none; border: none; color: var(--ink-soft); font-size: 16px; cursor: pointer; padding: 4px; display: flex; align-items: center; justify-content: center; }
    .history-del-btn:active { transform: scale(0.9); }

    /* ---- Unified "My Meals" drawer (3 Sep 2026) --------------------
       Replaces the split between a 1-tap favourites drawer and a 5-tap
       History accordion buried in settings — both answered the same
       question ("the thing I ate before") with different mental models
       and different capabilities. See index.html's #favDrawer. */
    /* Sticky within .meals-sheet-inner (the scroll container since My
       Meals became a bottom sheet — was .drawer before that). An earlier
       negative-margin approach to pull this flush against the container's
       own padding was tried and discarded: overflow-y:auto implies
       overflow-x:auto, which clips negative side margins rather than
       letting them extend into the padding area. This version stays
       inside its normal content box and relies on an opaque background
       plus sticky's own top offset instead. */
    .meals-range-row {
      display: flex; gap: 6px;
      position: sticky; top: 0; z-index: 5;
      margin: 0 0 12px; padding: 8px 0;
      background: var(--bg);
    }
    .meals-range-btn {
      flex: 1; min-height: 44px;
      border: 2px solid var(--bg2); background: var(--bg);
      color: var(--ink-soft);
      border-radius: 12px;
      font-family: inherit; font-weight: 800; font-size: 0.8rem;
      cursor: pointer;
      -webkit-tap-highlight-color: transparent;
    }
    .meals-range-btn.is-active {
      background: var(--sprout-green); border-color: var(--sprout-green); color: #fff;
    }
    .meals-section-head {
      font-family: 'Baloo 2', sans-serif; font-weight: 800; font-size: 0.82rem;
      color: var(--ink-soft);
      text-transform: uppercase; letter-spacing: 0.04em;
      margin: 14px 0 6px;
    }
    .meals-section-head:first-child { margin-top: 0; }

    .meals-row {
      /* --card (white) on the sheet's --bg surface. Inverted from the old
         side drawer, where the drawer itself was --card and rows were
         --bg; the bottom sheet's surface is --bg, so rows keep their
         contrast by taking the lighter colour instead. */
      background: var(--card); border-radius: 14px;
      padding: 10px 12px; margin-bottom: 8px;
    }
    /* Full-width title row. This is what makes zero-truncation possible —
       nothing else shares this row's horizontal space, so a long meal
       name (e.g. "Chicken Nuggets - Sweet Chilli") wraps onto as many
       lines as it needs rather than being squeezed by neighbouring
       icons and clipped with an ellipsis. */
    .meals-row-title {
      display: block; width: 100%; box-sizing: border-box;
      appearance: none; -webkit-appearance: none;
      background: none; border: none; padding: 0; margin: 0; outline: none;
      text-align: left; cursor: pointer;
      font-family: 'Baloo 2', sans-serif; font-weight: 800; font-size: 0.94rem;
      line-height: 1.3; color: var(--ink);
      white-space: normal; word-break: normal; overflow-wrap: break-word;
      -webkit-tap-highlight-color: transparent;
    }
    .meals-row-title:active { opacity: 0.75; }
    /* Meta text + icon row. Deliberately its OWN row below the title
       (not sharing space with it) so its height — and therefore every
       icon's tap target — stays fixed and predictable no matter how many
       lines the title above wraps to. */
    .meals-row-footer {
      display: flex; align-items: center; justify-content: space-between;
      gap: 8px; margin-top: 8px;
    }
    /* Secondary info (time/grams/item count) — genuinely low-stakes text,
       unlike the meal title above. Truncates if the icon group needs the
       room; the zero-truncation requirement was specifically about the
       meal NAME, which this isn't. */
    .meals-row-meta {
      font-weight: 700; font-size: 0.76rem; color: var(--ink-soft);
      min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .meals-row-icons {
      display: flex; align-items: center; gap: 6px;
      flex: 0 0 auto; flex-shrink: 0; flex-wrap: nowrap;
    }
    /* Every icon in this row is visually 36px (matches the mockup and the
       sticker slot's own row-context size below) but gets a 44px
       INVISIBLE tap area via ::before — same trick already used for the
       Reset button's touch-target fix earlier this session. Shrinking an
       icon visually should never shrink what a thumb can actually hit. */
    .meals-row-add, .meals-row-pin {
      width: 48px; height: 48px;
      /* --bg on the row's --card surface. Inverted alongside the row
         background change when My Meals became a bottom sheet — these
         were --card when rows were --bg. */
      background: var(--bg); border: none; border-radius: 12px;
      color: var(--ink-soft); cursor: pointer; font-size: 1.15rem;
      display: flex; align-items: center; justify-content: center;
      -webkit-tap-highlight-color: transparent;
    }
    /* No ::before hitbox here (unlike .header-reset-btn etc.): these were
       36px in the old 295px side drawer and needed an invisible 44px tap
       area to meet the minimum. At 48px the visible button already
       exceeds it, so the pseudo-element would be dead weight. */
    .meals-row-add {
      border: 1.5px dashed var(--bg2);
      font-weight: 800;
    }
    .meals-row-add:active, .meals-row-pin:active { transform: scale(0.9); }
    /* The sticker slot sits inline in this icon row too, so back-filling
       a reaction on an old meal needs no separate screen — it's the same
       list. Matched to the other two icons at 48px, which is also the
       sticker's own natural full size elsewhere in the app — so no
       row-specific downscale is needed any more. */
    .meals-row-icons .meal-sticker-slot { width: 48px; height: 48px; border-radius: 12px; }
    .meals-row-icons .meal-sticker-slot img { width: 48px; height: 48px; }


    /* Meal-reaction sticker slot on each history card (added 3 Sep 2026).
       48px confirmed against a real mockup — see docs/STICKER-PIPELINE.md.
       See js/meals/meal-stickers.js. */
    .meal-sticker-slot {
      flex: 0 0 auto;
      width: 48px; height: 48px;
      border: none; background: none; padding: 0;
      border-radius: 10px;
      cursor: pointer;
      display: flex; align-items: center; justify-content: center;
      -webkit-tap-highlight-color: transparent;
    }
    .meal-sticker-slot img { width: 48px; height: 48px; display: block; }
    .meal-sticker-slot.empty {
      border: 1.5px dashed var(--bg2);
      color: var(--ink-soft);
      font-size: 1.2rem;
      font-weight: 800;
    }
    .meal-sticker-slot.empty:active { background: var(--bg2); }
    .meal-sticker-slot.has-sticker:active { transform: scale(0.94); }

    /* The sticker picker toast itself. A second element alongside
       #undoToast (see index.html's own comment there for why) rather than
       overloading it — #undoToast's base .undo-toast rules assume one
       line of text plus one button (white-space:nowrap, ellipsis,
       border-radius:100px pill), none of which suit a row of 48px
       sticker images, hence the overrides below. */
    .undo-toast.meal-sticker-toast {
      flex-direction: column;
      align-items: stretch;
      gap: 8px;
      border-radius: 20px;
      padding: 12px 16px 14px;
      max-width: min(calc(100vw - 32px), 340px);
    }
    .meal-sticker-toast .undo-toast-msg {
      white-space: normal;
      text-align: center;
      font-size: 0.85rem;
    }
    .meal-sticker-picker {
      /* Wrapping flex row rather than a fixed one. The sticker set is
         expected to grow well beyond the 5 it launched with (4 Sep 2026),
         so this reflows to whatever fits the container instead of needing
         a layout change per sticker added. Works unchanged in both
         contexts it renders in: the wide My Meals sheet and the narrower
         post-log panel.
         Flex rather than CSS Grid deliberately: grid would express this
         slightly more directly, but wkhtmltoimage (the only renderer
         available for verifying layout in this project's tooling) has no
         grid support, so grid CSS here would be unverifiable before
         shipping. Flex gives the same reflow behaviour and can actually
         be checked.
         64px (up from 48px) is the size at which wordmark text baked into
         the sticker art becomes properly legible — see the legibility
         notes in docs/STICKER-PIPELINE.md. */
      display: flex;
      flex-wrap: wrap;
      justify-content: center;
      align-items: center;
      gap: 8px;
      /* Caps at roughly three rows, then scrolls, so a large set can't
         push the rest of the panel off screen. */
      max-height: 240px;
      overflow-y: auto;
    }
    .meal-sticker-option {
      border: 2px solid transparent;
      background: none;
      padding: 2px;
      border-radius: 10px;
      cursor: pointer;
      display: flex;
      -webkit-tap-highlight-color: transparent;
    }
    .meal-sticker-option img { width: 64px; height: 64px; display: block; }
    .meal-sticker-option:active { transform: scale(0.94); background: rgba(255,255,255,0.12); }


    .swatches { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
    .swatch-wrapper { position: relative; display: inline-block; }
    .swatch { width: 38px; height: 38px; border-radius: 50%; border: 3px solid transparent; cursor: pointer; transition: transform 0.15s ease; }
    .swatch:hover { transform: scale(1.1); }
    .swatch.active { border-color: var(--ink); }

    .swatch-wrapper::after {
      content: attr(data-color-name); position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%) translateY(-6px);
      background: #1F2A44; color: #FFFFFF; padding: 6px 10px; border-radius: 8px; font-size: 0.75rem; font-weight: 800;
      white-space: nowrap; opacity: 0; pointer-events: none; transition: opacity 0.15s ease, transform 0.15s ease;
      box-shadow: 0 4px 14px rgba(0,0,0,0.4); z-index: 999;
      border: 1px solid rgba(255,255,255,0.2);
    }
    .swatch-wrapper:hover::after { opacity: 1; transform: translateX(-50%) translateY(-2px); }

    .theme-opts { display: flex; gap: 8px; flex-wrap: wrap; }
    .theme-chip {
      background: var(--bg); border: 2px solid var(--bg2); color: var(--ink);
      padding: 8px 12px; border-radius: 12px; font-weight: 700; cursor: pointer; flex: 1; text-align: center;
      min-width: 120px; margin-bottom: 4px;
    }
    body.theme-night .theme-chip { background: #1B2140; border-color: #262C52; }
    .theme-chip.active { border-color: var(--sky); background: var(--sky); color: white; }

    .wardrobe-chip {
      background: var(--bg); border: 2px solid var(--bg2); color: var(--ink);
      padding: 8px 12px; border-radius: 12px; font-weight: 700; cursor: pointer; flex: 1; text-align: center;
      min-width: 120px; margin-bottom: 4px;
    }
    body.theme-night .wardrobe-chip { background: #1B2140; border-color: #262C52; }
    /* Seasonal chip shown all year but locked until its dates; still hoverable/tappable for the nudge */
    .wardrobe-chip.locked {
      opacity: 0.5;
      cursor: not-allowed;
    }
    .wardrobe-chip.locked::after {
      content: " 🔒";
      font-size: 0.85em;
    }
    .wardrobe-chip.active { 
      border: 2px solid var(--ink) !important; 
      background: var(--mint); 
      color: white;
      font-weight: 900;
    }

    /* Resource chips: external links to trusted diabetes info (NHS, charities) */
    .resource-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
    .resource-chip {
      background: var(--bg); border: 2px solid var(--bg2); color: var(--ink);
      padding: 9px 8px; border-radius: 12px; font-weight: 700; cursor: pointer;
      text-align: center; font-size: 0.78rem;
      display: inline-flex; align-items: center; justify-content: center; gap: 5px;
      text-decoration: none; line-height: 1.2;
    }
    body.theme-night .resource-chip { background: #1B2140; border-color: #262C52; }
    .resource-chip:hover { border-color: var(--sky); }
    .resource-chip:focus-visible { outline: 3px solid var(--sky); outline-offset: 2px; }
    .resource-chip .resource-chip-ext { font-size: 0.85em; opacity: 0.55; }
    .resource-chip.emergency {
      grid-column: 1 / -1;
      border-color: var(--berry);
      color: var(--berry);
      background: rgba(216,27,96,0.08);
      font-weight: 900;
    }
    body.theme-night .resource-chip.emergency { background: rgba(255,93,143,0.12); }
    .resource-chip.emergency:hover { border-color: var(--berry); background: rgba(216,27,96,0.16); }

    .switch { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; font-weight: 700; color: var(--ink); }
