/* content/tools/food-diary/diary.css
 *
 * Food diary UI styles. Mobile-first; the page is reachable at 320px wide.
 * Loaded ADDITIVELY after the template's stylesheets via extra_css_json.
 *
 * Visual contract: content/tools/food-diary/mockups/v1.html — Component 4
 * (in-context full-page) plus the autocomplete and quick-log components.
 *
 * Token strategy:
 *   1. Reuse template tokens where they exist (--primary-color, --text-color,
 *      --card-bg, --border-color, --background, --text-light, --text-muted,
 *      --border-strong, --shadow-sm/md/lg). Their dark-mode values come from
 *      [data-theme="dark"] in style.css.
 *   2. Net-new tokens (accent/error/source-badge/spacing/radius) are defined
 *      below at :root with [data-theme="dark"] mirrors. NO literal hex values
 *      anywhere except inside :root / [data-theme="dark"] blocks.
 */

/* ════════════════════════════════════════════════════════════════════════
 * DESIGN TOKENS — net-new (template doesn't define these)
 * ════════════════════════════════════════════════════════════════════════ */
:root {
    /* Brand variants */
    --primary-soft:        #dbeafe;
    --primary-dark:        #1d4ed8;

    /* Status colours */
    --accent-color:        #16a34a;
    --accent-soft:         #dcfce7;
    --warn-color:          #ea580c;
    --error-color:         #dc2626;
    --error-soft:          #fef2f2;
    --error-strong:        #b91c1c;
    --error-border:        #fca5a5;

    /* Surface variants */
    --surface-muted:       #f3f4f6;

    /* Source badges (autocomplete + ingredient rows) */
    --source-enc-bg:       #dcfce7;
    --source-enc-fg:       #15803d;
    --source-off-bg:       #dbeafe;
    --source-off-fg:       #1d4ed8;

    /* Diary-specific surfaces */
    --diary-totals-bg-from: #dbeafe;
    --diary-totals-bg-to:   #ffffff;
    --diary-totals-border:  #2563eb;

    /* Effects */
    --shadow-card:         0 1px 2px rgba(17, 24, 39, 0.04), 0 4px 12px rgba(17, 24, 39, 0.06);
    --shadow-pop:          0 8px 24px rgba(17, 24, 39, 0.12);

    /* Spacing scale (4px grid) */
    --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px;
    --s-5: 20px; --s-6: 24px; --s-8: 32px; --s-10: 40px; --s-12: 48px;

    /* Radius */
    --r-sm: 6px; --r-md: 10px; --r-lg: 14px; --r-pill: 999px;
}

[data-theme="dark"] {
    --primary-soft:        rgba(96, 165, 250, 0.15);
    --primary-dark:        #93c5fd;

    --accent-color:        #4ade80;
    --accent-soft:         rgba(74, 222, 128, 0.15);
    --warn-color:          #fb923c;
    --error-color:         #f87171;
    --error-soft:          rgba(248, 113, 113, 0.15);
    --error-strong:        #fecaca;
    --error-border:        rgba(248, 113, 113, 0.45);

    --surface-muted:       #273449;

    --source-enc-bg:       rgba(34, 197, 94, 0.18);
    --source-enc-fg:       #86efac;
    --source-off-bg:       rgba(96, 165, 250, 0.18);
    --source-off-fg:       #93c5fd;

    /* Totals gradient on dark — soft tinted plate, no hard white ceiling. */
    --diary-totals-bg-from: rgba(96, 165, 250, 0.22);
    --diary-totals-bg-to:   rgba(96, 165, 250, 0.04);
    --diary-totals-border:  #60a5fa;

    --shadow-card:         0 1px 2px rgba(0, 0, 0, 0.3), 0 4px 12px rgba(0, 0, 0, 0.35);
    --shadow-pop:          0 8px 24px rgba(0, 0, 0, 0.5);
}

/* ════════════════════════════════════════════════════════════════════════
 * PAGE WRAPPER
 * ════════════════════════════════════════════════════════════════════════ */
.diary-app {
    max-width: 720px;
    margin: 0 auto;
    padding: var(--s-4) var(--s-4) var(--s-10);
}

.diary-app h1.page-title {
    margin: 0 0 var(--s-2);
    letter-spacing: -0.01em;
}

.diary-intro {
    color: var(--text-light);
    line-height: 1.5;
    margin: 0 0 var(--s-6);
}

/* ════════════════════════════════════════════════════════════════════════
 * SECTION HEADERS — uppercase muted labels per Component 4 spec
 * ════════════════════════════════════════════════════════════════════════ */
.diary-section {
    margin: 0 0 var(--s-6);
}
.diary-section-h {
    margin: 0 0 var(--s-3);
    font-size: 13px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    font-weight: 600;
    line-height: 1.2;
    border: 0;
    padding: 0;
}

/* ════════════════════════════════════════════════════════════════════════
 * CARD — base surface for log/today/tools sections
 * ════════════════════════════════════════════════════════════════════════ */
.diary-card {
    background: var(--card-bg);
    border: 1px solid var(--border-color);
    border-radius: var(--r-md);
    padding: var(--s-4);
}
.diary-card--tight   { padding: var(--s-3); }
.diary-card--list    { padding: var(--s-2) var(--s-4); }

/* ════════════════════════════════════════════════════════════════════════
 * SEGMENTED TABS — Single food / Composed meal
 * ════════════════════════════════════════════════════════════════════════ */
.seg-tabs {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 4px;
    padding: 4px;
    background: var(--surface-muted);
    border-radius: var(--r-md);
    margin-bottom: var(--s-3);
}
.seg-tabs button {
    appearance: none;
    border: 0;
    padding: var(--s-2) var(--s-3);
    background: transparent;
    color: var(--text-light);
    font: inherit;
    font-size: 14px;
    font-weight: 500;
    border-radius: var(--r-sm);
    cursor: pointer;
    transition: background 120ms ease, color 120ms ease;
    min-height: 36px;
}
.seg-tabs button.is-active,
.seg-tabs button[aria-selected="true"] {
    background: var(--card-bg);
    color: var(--primary-color);
    box-shadow: var(--shadow-sm);
}
.seg-tabs button[disabled] {
    opacity: 0.55;
    cursor: not-allowed;
}

/* ════════════════════════════════════════════════════════════════════════
 * FORM — typography + spacing aligned with the mockup
 * ════════════════════════════════════════════════════════════════════════ */
/* `minmax(0, 1fr)` (not bare `1fr`) on every flexible track. A `1fr` track
 * defaults to `minmax(auto, 1fr)`, where `auto` is min-content; on a 360–414px
 * viewport the search input's long placeholder ("Search a food or scan a
 * barcode…") makes that min-content larger than the viewport, so the single
 * column expands and the page horizontally scrolls. Forcing the track minimum
 * to 0 lets it shrink to the available width regardless of inner content.
 * Pair with min-width: 0 on items so flex/grid descendants can also shrink. */
.diary-form {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s-3);
}
/* `display: grid` above otherwise wins over the browser's default
 * `[hidden] { display: none }`, so a hidden composed form would still
 * render. Force the right-hand side back to none when the attr is set. */
.diary-form[hidden] { display: none; }
@media (min-width: 480px) {
    .diary-form {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }
}
.diary-form > * { min-width: 0; }

.diary-form .full {
    grid-column: 1 / -1;
}

.diary-form label {
    display: flex;
    flex-direction: column;
    font-size: 14px;
    font-weight: 500;
    color: var(--text-color);
    line-height: 1.3;
    gap: 4px;
}

.diary-form label {
    /* Belt-and-braces: also constrain the label, not just .diary-form > *.
     * Some browsers (Safari especially) compute label widths from the
     * intrinsic width of native input chrome, which can exceed the grid
     * cell. min-width: 0 lets the label shrink; overflow: hidden clips
     * anything that still spills past the cell edge. */
    min-width: 0;
    max-width: 100%;
}
.diary-form input,
.diary-form textarea,
.diary-form select {
    /* iOS Safari auto-zoom prevention — DO NOT shrink below 16px. iOS
       zooms the viewport on focus when font-size < 16px. The viewport-meta
       maximum-scale=1 workaround is NOT acceptable as it disables
       intentional accessibility zoom too. */
    font-size: 16px;
    font-family: inherit;
    line-height: 1.4;
    padding: var(--s-3);
    border: 1px solid var(--border-color);
    border-radius: var(--r-md);
    background: var(--card-bg);
    color: var(--text-color);
    box-sizing: border-box;
    /* display: block forces the input out of inline-block flow, where
     * width:100% is sometimes ignored in favour of intrinsic width. */
    display: block;
    width: 100%;
    min-width: 0;
    max-width: 100%;
}
/* Date and time inputs specifically — on iOS Safari these have an INTRINSIC
 * min-width baked into the native widget that ignores width: 100% / min-width
 * unless the native appearance is stripped. -webkit-appearance:none removes
 * that intrinsic floor; we also clamp the input to its grid track and reserve
 * a little right-padding so the calendar/clock icon (which iOS still renders)
 * doesn't crowd the value. */
.diary-form input[type="date"],
.diary-form input[type="time"],
.diary-form input[type="number"] {
    display: block;
    width: 100%;
    min-width: 0;
    max-width: 100%;
    box-sizing: border-box;
    -webkit-appearance: none;
    appearance: none;
    /* Reserve a bit of room on the right so the native calendar/clock icon
     * iOS still draws inside the field has space without forcing the input
     * to grow. */
    padding-right: calc(var(--s-3) + 6px);
}
/* The native iOS picker chrome lives inside this pseudo-element and can
 * itself report a min-width — collapse it so the input's box is the only
 * width source. */
.diary-form input[type="date"]::-webkit-date-and-time-value,
.diary-form input[type="time"]::-webkit-date-and-time-value {
    min-width: 0;
    text-align: left;
}
.diary-form input:focus,
.diary-form textarea:focus,
.diary-form select:focus {
    outline: 2px solid var(--primary-color);
    outline-offset: -2px;
    border-color: var(--primary-color);
}
.diary-form textarea {
    min-height: 4.5rem;
    resize: vertical;
}
/* Photo picker — camera-icon trigger replaces the default <input type="file">
 * UI. The bare file input is visually hidden inside the trigger label so a
 * tap anywhere on the chip opens the OS-native picker (which on iOS gives
 * "Take Photo / Photo Library / Choose Files" — the user can pick fresh
 * camera or an existing library photo). */
.diary-photo-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.diary-photo-label {
    font-size: 14px;
    font-weight: 500;
    color: var(--text-color);
    line-height: 1.3;
}
.diary-photo-trigger {
    /* Full-width chip — visually consistent with the "Add to diary" /
     * "Reset" action buttons that also span full width on mobile. */
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--s-2);
    padding: var(--s-3) var(--s-4);
    border: 1px dashed var(--border-strong);
    border-radius: var(--r-md);
    background: var(--surface-muted);
    color: var(--text-color);
    cursor: pointer;
    min-height: 48px;
    font-size: 14px;
    line-height: 1.3;
    transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
.diary-photo-trigger:hover,
.diary-photo-trigger:focus-within {
    background: var(--card-bg);
    border-color: var(--primary-color);
    color: var(--primary-color);
}
.diary-photo-trigger:focus-within {
    outline: 2px solid var(--primary-color);
    outline-offset: 2px;
}
.diary-photo-trigger .camera-icon {
    width: 22px;
    height: 22px;
    flex: 0 0 auto;
}
/* Visually-hidden, keyboard-reachable file input. Tab focus reaches the
 * input; the parent label's :focus-within picks that up and outlines the
 * whole chip so keyboard users see the hit target. */
.diary-photo-trigger input[type="file"] {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Food field row — input + adjacent scan button. The scan button opens
 * the modal scanner overlay; both halves share the same row so the user
 * can search OR scan without context switching. */
.diary-food-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.diary-food-label {
    font-size: 14px;
    font-weight: 500;
    color: var(--text-color);
    line-height: 1.3;
}
.diary-food-row {
    /* Mobile: search field on top, scan button full-width below. Side-by-
     * side compressed the autocomplete popout (which inherits its width
     * from the input) and the dropdown rows became unreadable.
     *
     * Desktop (≥ 480 px): grid with the input flexing and a fixed 48px
     * scan button on the right — that's the original side-by-side layout
     * which works fine when there's enough horizontal room. */
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
}
.diary-food-row > .autocomplete,
.diary-food-row > input[type="text"] {
    width: 100%;
    min-width: 0;
    margin-bottom: 0;
}
.diary-scan-btn {
    /* Primary-coloured outline so the button reads clearly as an action
     * against the white form card. The matching grey-on-white styling
     * (surface-muted/border-color) was visually invisible during user
     * testing — users couldn't see the scan affordance at all. */
    width: 100%;                       /* full-width on mobile */
    min-height: 48px;
    border: 1px solid var(--primary-color);
    border-radius: var(--r-md);
    background: var(--card-bg);
    color: var(--primary-color);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 0 var(--s-3);
    transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
@media (min-width: 480px) {
    .diary-food-row {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 48px;
        align-items: stretch;
    }
    .diary-scan-btn {
        width: 48px;
        padding: 0;
    }
}
.diary-scan-btn:hover,
.diary-scan-btn:focus-visible {
    background: var(--primary-color);
    color: var(--card-bg);
    outline: none;
}
.diary-scan-btn svg {
    width: 22px;
    height: 22px;
}

/* ════════════════════════════════════════════════════════════════════════
 * SCAN MODAL — overlays the diary entry form. Form context stays visible
 * behind the backdrop so the user knows they'll return to it on close.
 * ════════════════════════════════════════════════════════════════════════ */
.diary-scan-modal[hidden] { display: none; }
.diary-scan-modal {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--s-3);
}
.diary-scan-modal-backdrop {
    position: absolute;
    inset: 0;
    background: var(--overlay-bg);
}
.diary-scan-modal-inner {
    position: relative;
    width: 100%;
    max-width: 440px;
    background: var(--card-bg);
    color: var(--text-color);
    border: 1px solid var(--border-color);
    border-radius: var(--r-lg);
    padding: var(--s-5) var(--s-4) var(--s-4);
    box-shadow: var(--shadow-pop);
    max-height: 100%;
    overflow-y: auto;
}
.diary-scan-close {
    position: absolute;
    top: var(--s-2);
    right: var(--s-2);
    width: 36px;
    height: 36px;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--text-light);
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
    padding: 0;
}
.diary-scan-close:hover,
.diary-scan-close:focus-visible {
    background: var(--surface-muted);
    color: var(--text-color);
    outline: none;
}
.diary-scan-modal-title {
    margin: 0 0 var(--s-3);
    font-size: 18px;
    font-weight: 600;
    color: var(--text-color);
    line-height: 1.2;
}
.diary-scan-stage {
    position: relative;
    width: 100%;
    aspect-ratio: 4 / 3;
    background: #111;
    border-radius: var(--r-md);
    overflow: hidden;
    margin-bottom: var(--s-3);
}
.diary-scan-stage video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.diary-scan-overlay {
    position: absolute;
    inset: 15% 10%;
    border: 2px solid rgba(255, 255, 255, 0.85);
    border-radius: var(--r-sm);
    box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.25);
    pointer-events: none;
}
.diary-scan-actions {
    display: flex;
    gap: var(--s-2);
    margin-top: var(--s-3);
}
.diary-scan-actions button {
    flex: 1;
    appearance: none;
    border: 1px solid var(--primary-color);
    border-radius: var(--r-md);
    background: var(--card-bg);
    color: var(--primary-color);
    padding: var(--s-3) var(--s-4);
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    min-height: 44px;
}
.diary-scan-actions button:hover,
.diary-scan-actions button:focus-visible {
    background: var(--primary-soft);
    outline: none;
}
.diary-scan-manual {
    margin: var(--s-4) 0 0;
    text-align: center;
    font-size: 13px;
    color: var(--text-light);
}
.diary-scan-link {
    appearance: none;
    background: transparent;
    border: 0;
    color: var(--primary-color);
    text-decoration: underline;
    cursor: pointer;
    font: inherit;
    padding: 0;
}
.diary-scan-manual-form {
    display: flex;
    gap: var(--s-2);
    margin-top: var(--s-2);
}
.diary-scan-manual-form input {
    flex: 1 1 auto;
    border: 1px solid var(--border-color);
    border-radius: var(--r-md);
    padding: var(--s-3);
    /* iOS auto-zoom prevention. */
    font-size: 16px;
    font-family: inherit;
    background: var(--card-bg);
    color: var(--text-color);
    box-sizing: border-box;
    min-width: 0;
}
.diary-scan-manual-form input:focus {
    outline: 2px solid var(--primary-color);
    outline-offset: -2px;
    border-color: var(--primary-color);
}
.diary-scan-manual-form button {
    flex: 0 0 auto;
    appearance: none;
    border: 1px solid var(--primary-color);
    background: var(--primary-color);
    color: var(--card-bg);
    border-radius: var(--r-md);
    padding: var(--s-3) var(--s-4);
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    min-height: 44px;
}

/* ════════════════════════════════════════════════════════════════════════
 * QUICK-LOG SECTION (Phase 4.5.D — Group 6)
 * Templates / Recents tabs above the entry form. Cards are tap-to-log.
 * Hidden by default for new users via .is-collapsed-empty (no content
 * yet → don't show empty cards). diary.js removes the class once either
 * tab has anything to render.
 * ════════════════════════════════════════════════════════════════════════ */
.diary-quicklog-section.is-collapsed-empty {
    display: none;
}
.diary-quicklog .seg-tabs {
    margin-bottom: var(--s-3);
}
.diary-quicklog .seg-count {
    margin-left: 4px;
    color: var(--text-muted);
    font-weight: 400;
    font-size: 13px;
}
/* Active tab on dark theme: ensure the count number stays muted (the
 * override above for .is-active sets primary-color on the whole button —
 * we don't want the count painted in the same vivid blue, just the label). */
.diary-quicklog .seg-tabs button.is-active .seg-count {
    color: var(--text-muted);
}

.quicklog-pane[hidden] { display: none; }

.quicklog-cards {
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
}

.quicklog-card {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--s-3);
    align-items: center;
    padding: var(--s-3) var(--s-4);
    background: var(--card-bg);
    border: 1px solid var(--border-color);
    border-radius: var(--r-md);
    cursor: pointer;
    min-height: 56px;
    transition: transform 80ms ease, box-shadow 80ms ease, border-color 120ms ease;
}
.quicklog-card:hover,
.quicklog-card:focus-within {
    border-color: var(--primary-color);
    box-shadow: var(--shadow-card);
    transform: translateY(-1px);
}
.quicklog-card:focus-visible {
    outline: 2px solid var(--primary-color);
    outline-offset: 2px;
}
/* Templates get a green left-edge accent so they're visually distinct from
 * Recents at-a-glance. Same accent token the source-badge uses for
 * encyclopedia/saved content. */
.quicklog-card.is-template {
    border-left: 3px solid var(--accent-color);
    padding-left: calc(var(--s-4) - 3px);
}
.quicklog-card .meal-info {
    min-width: 0;
}
.quicklog-card .meal-name {
    display: block;
    font-weight: 500;
    color: var(--text-color);
    font-size: 15px;
    line-height: 1.3;
    overflow-wrap: anywhere;
}
.quicklog-card .meal-meta {
    display: block;
    font-size: 12px;
    color: var(--text-muted);
    margin-top: 2px;
    line-height: 1.4;
}
.quicklog-card .meal-meta .dot {
    margin: 0 6px;
    color: var(--text-light);
}
.quicklog-card .star-mark {
    color: var(--accent-color);
    font-size: 12px;
    margin-right: 2px;
}
.quicklog-card .meal-kcal {
    text-align: right;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.quicklog-card .meal-kcal strong {
    display: block;
    font-size: 18px;
    font-weight: 600;
    color: var(--text-color);
}
.quicklog-card .meal-kcal small {
    display: block;
    font-size: 11px;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.quicklog-card .kcal-empty {
    font-size: 16px;
    color: var(--text-muted);
}

.quicklog-empty {
    padding: var(--s-6) var(--s-4);
    text-align: center;
    background: var(--surface-muted);
    border: 1px dashed var(--border-strong);
    border-radius: var(--r-md);
    color: var(--text-muted);
}
.quicklog-empty .icon {
    font-size: 36px;
    display: block;
    margin: 0 auto var(--s-3);
    opacity: 0.55;
    line-height: 1;
}
.quicklog-empty h4 {
    margin: 0 0 4px;
    font-size: 16px;
    color: var(--text-color);
    font-weight: 600;
    line-height: 1.25;
}
.quicklog-empty p {
    margin: 0;
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-muted);
}

/* "Browse all templates →" link below the inline cards. Visible whenever
 * any template exists (label switches: "Browse all (N) →" if over the
 * inline cap, "Manage templates →" otherwise). Styled as a tertiary link-
 * button so it doesn't compete with the primary log buttons. */
.quicklog-browse-all {
    display: block;
    width: 100%;
    margin-top: var(--s-3);
    padding: var(--s-2) var(--s-3);
    appearance: none;
    background: transparent;
    border: 1px dashed var(--border-strong);
    border-radius: var(--r-md);
    color: var(--primary-color);
    font: inherit;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    text-align: center;
    min-height: 44px;
    transition: background 120ms ease, border-color 120ms ease;
}
.quicklog-browse-all:hover,
.quicklog-browse-all:focus-visible {
    background: var(--primary-soft);
    border-color: var(--primary-color);
    outline: none;
}

/* Composed-form actions — Save & log / Save as template / (Save as new) /
 * Reset. Stack on mobile, row on tablet+, same as .diary-form-actions. */
.composed-form-actions {
    flex-direction: column;
    gap: var(--s-2);
}
@media (min-width: 480px) {
    .composed-form-actions {
        flex-direction: row;
        flex-wrap: wrap;
    }
    .composed-form-actions button { flex: 1 1 calc(33% - var(--s-2)); }
}

/* Editing-template banner inside the composed form. Appears when the user
 * loads a template via "Edit recipe in form" from the manage modal. Reuses
 * the .diary-ref-banner accent-soft palette so the visual vocabulary is
 * shared with the source banner on single-food. */
.composed-editing-banner {
    display: none;                               /* override .diary-ref-banner default */
    align-items: center;
    justify-content: space-between;
    gap: var(--s-2);
    flex-wrap: wrap;
}
.composed-editing-banner:not([hidden]) { display: flex; }
.composed-editing-banner-text {
    flex: 1 1 auto;
    min-width: 0;
    overflow-wrap: anywhere;
}
.composed-editing-banner-text strong {
    color: var(--text-color);
    font-weight: 600;
}

/* ════════════════════════════════════════════════════════════════════════
 * MANAGE TEMPLATES MODAL (Group 6.1)
 * Two views inside one panel: list (search + grouped-by-category list of
 * templates) and edit (rename / recategorise / edit recipe / delete).
 * ════════════════════════════════════════════════════════════════════════ */
.diary-templates-modal[hidden] { display: none; }
.diary-templates-modal {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: var(--s-3);
    overflow-y: auto;
}
.diary-templates-modal-backdrop {
    position: fixed;
    inset: 0;
    background: var(--overlay-bg);
}
.diary-templates-modal-inner {
    position: relative;
    width: 100%;
    max-width: 520px;
    background: var(--card-bg);
    color: var(--text-color);
    border: 1px solid var(--border-color);
    border-radius: var(--r-lg);
    padding: var(--s-5) var(--s-4) var(--s-4);
    box-shadow: var(--shadow-pop);
    margin: var(--s-4) auto;
}
.diary-templates-close {
    position: absolute;
    top: var(--s-2);
    right: var(--s-2);
    width: 36px;
    height: 36px;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--text-light);
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
    padding: 0;
}
.diary-templates-close:hover,
.diary-templates-close:focus-visible {
    background: var(--surface-muted);
    color: var(--text-color);
    outline: none;
}
.diary-templates-title {
    margin: 0 var(--s-8) var(--s-1) 0;
    font-size: 18px;
    font-weight: 600;
    color: var(--text-color);
    line-height: 1.25;
}
.diary-templates-hint {
    margin: 0 0 var(--s-4);
    font-size: 13px;
    color: var(--text-muted);
    line-height: 1.4;
}
.diary-templates-search {
    margin: 0 0 var(--s-3);
}
.diary-templates-search input {
    width: 100%;
    box-sizing: border-box;
    border: 1px solid var(--border-color);
    border-radius: var(--r-md);
    padding: var(--s-3) var(--s-3) var(--s-3) var(--s-10);
    font: inherit;
    font-size: 16px;
    line-height: 1.4;
    background: var(--card-bg) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='8'/><path d='m21 21-4.3-4.3'/></svg>") no-repeat var(--s-3) center;
    color: var(--text-color);
    min-height: 44px;
}
.diary-templates-search input:focus {
    outline: 2px solid var(--primary-color);
    outline-offset: -2px;
    border-color: var(--primary-color);
}

.diary-templates-list { display: block; }

.diary-templates-group {
    margin-bottom: var(--s-4);
}
.diary-templates-group:last-child { margin-bottom: 0; }
.diary-templates-group-h {
    margin: 0 0 var(--s-2);
    font-size: 13px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    font-weight: 600;
    line-height: 1.2;
    border: 0;
    padding: 0;
    display: flex;
    align-items: center;
    gap: 6px;
}
.diary-templates-group-count {
    background: var(--surface-muted);
    color: var(--text-muted);
    border-radius: var(--r-pill);
    padding: 1px 8px;
    font-size: 11px;
    letter-spacing: 0;
    text-transform: none;
}
.diary-templates-rows {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
}
.diary-templates-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    gap: var(--s-2);
    align-items: center;
    padding: var(--s-3);
    background: var(--card-bg);
    border: 1px solid var(--border-color);
    border-left: 3px solid var(--accent-color);   /* template green-edge accent */
    border-radius: var(--r-md);
    cursor: pointer;
    min-height: 56px;
    transition: border-color 120ms ease, box-shadow 120ms ease;
}
.diary-templates-row:hover {
    border-color: var(--primary-color);
    border-left-color: var(--accent-color);       /* keep the green edge on hover */
    box-shadow: var(--shadow-card);
}
.diary-templates-row:focus-visible {
    outline: 2px solid var(--primary-color);
    outline-offset: 2px;
}
.diary-templates-row .row-info { min-width: 0; }
.diary-templates-row .row-name {
    display: block;
    font-weight: 500;
    color: var(--text-color);
    font-size: 15px;
    line-height: 1.3;
    overflow-wrap: anywhere;
}
.diary-templates-row .row-meta {
    display: block;
    margin-top: 2px;
    font-size: 12px;
    color: var(--text-muted);
}
.diary-templates-row .row-kcal {
    text-align: right;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.diary-templates-row .row-kcal strong {
    display: block;
    font-size: 16px;
    font-weight: 600;
    color: var(--text-color);
}
.diary-templates-row .row-kcal small {
    display: block;
    font-size: 10px;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.diary-templates-row .row-kcal-empty {
    font-size: 16px;
    color: var(--text-muted);
}
.diary-templates-row .row-edit-btn {
    appearance: none;
    background: transparent;
    border: 0;
    color: var(--text-light);
    cursor: pointer;
    width: 36px;
    height: 36px;
    border-radius: var(--r-sm);
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.diary-templates-row .row-edit-btn:hover,
.diary-templates-row .row-edit-btn:focus-visible {
    background: var(--surface-muted);
    color: var(--primary-color);
    outline: none;
}
.diary-templates-empty {
    padding: var(--s-6) var(--s-4);
    text-align: center;
    color: var(--text-muted);
    font-size: 14px;
    background: var(--surface-muted);
    border: 1px dashed var(--border-strong);
    border-radius: var(--r-md);
}
.diary-templates-empty p { margin: 0; line-height: 1.5; }

/* Edit view — replaces the list inside the same modal panel. Back button
 * sits at the top, then form fields, then action buttons. */
.diary-templates-edit-view[hidden] { display: none; }
.diary-templates-back-btn {
    appearance: none;
    background: transparent;
    border: 0;
    color: var(--primary-color);
    font: inherit;
    font-size: 14px;
    padding: 4px 0;
    cursor: pointer;
    margin-bottom: var(--s-3);
}
.diary-templates-back-btn:hover,
.diary-templates-back-btn:focus-visible {
    text-decoration: underline;
    outline: none;
}
.diary-templates-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: var(--s-3);
    font-size: 14px;
    font-weight: 500;
    color: var(--text-color);
    line-height: 1.3;
}
.diary-templates-field input,
.diary-templates-field select {
    font-size: 16px;
    font-family: inherit;
    line-height: 1.4;
    padding: var(--s-3);
    border: 1px solid var(--border-color);
    border-radius: var(--r-md);
    background: var(--card-bg);
    color: var(--text-color);
    box-sizing: border-box;
    width: 100%;
    min-height: 44px;
}
.diary-templates-field input:focus,
.diary-templates-field select:focus {
    outline: 2px solid var(--primary-color);
    outline-offset: -2px;
    border-color: var(--primary-color);
}
/* Pin <option> colours so the OS popup follows our theme — same gotcha as
 * the portion-unit dropdown earlier. */
.diary-templates-field select option,
.diary-templates-field select optgroup {
    color: var(--text-color);
    background-color: var(--card-bg);
}
.diary-templates-edit-actions {
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
    margin-top: var(--s-4);
}
.diary-templates-edit-actions button {
    appearance: none;
    border: 1px solid var(--primary-color);
    background: var(--primary-color);
    color: var(--card-bg);
    padding: var(--s-3) var(--s-4);
    font-size: 15px;
    font-weight: 600;
    border-radius: var(--r-md);
    cursor: pointer;
    min-height: 44px;
}
.diary-templates-edit-actions button.is-secondary {
    background: var(--card-bg);
    color: var(--primary-color);
}
.diary-templates-edit-actions button.is-danger {
    background: var(--card-bg);
    color: var(--error-strong);
    border-color: var(--error-border);
}
.diary-templates-edit-actions button.is-danger:hover,
.diary-templates-edit-actions button.is-danger:focus-visible {
    background: var(--error-soft);
    outline: none;
}
.diary-templates-edit-actions button:focus-visible {
    outline: 2px solid var(--primary-color);
    outline-offset: 2px;
}

/* Field-hint span beneath the field label. Soft muted text, smaller. */
.diary-templates-field-hint {
    display: block;
    font-size: 12px;
    color: var(--text-muted);
    font-weight: 400;
    margin-top: 2px;
    margin-bottom: 4px;
    line-height: 1.4;
}
.diary-templates-field-optional {
    color: var(--text-muted);
    font-weight: 400;
    font-size: 12px;
}

/* Live preview block under the instructions textarea (Phase 6.4) — shows
 * the auto-rendered ordered list as the user types so they don't have to
 * save to see the format. Hidden when the textarea is empty. */
.diary-templates-preview-wrap {
    background: var(--surface-muted);
    border: 1px solid var(--border-color);
    border-radius: var(--r-md);
    padding: var(--s-3);
    margin: -8px 0 var(--s-3);
}
.diary-templates-preview-wrap[hidden] { display: none; }
.diary-templates-preview-label {
    display: block;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    font-weight: 600;
    margin-bottom: 4px;
}
.diary-templates-preview {
    font-size: 14px;
    line-height: 1.5;
    color: var(--text-color);
}
.diary-templates-preview .recipe-instructions-list {
    margin: 0;
    padding-left: var(--s-5);
}
.diary-templates-preview .recipe-instructions-list > li {
    margin-bottom: 4px;
}
.diary-templates-preview .recipe-instructions-list > li::marker {
    color: var(--primary-color);
    font-weight: 600;
}
.diary-templates-preview > p { margin: 0; }
.diary-templates-field textarea {
    font-size: 16px;
    font-family: inherit;
    line-height: 1.5;
    padding: var(--s-3);
    border: 1px solid var(--border-color);
    border-radius: var(--r-md);
    background: var(--card-bg);
    color: var(--text-color);
    box-sizing: border-box;
    width: 100%;
    min-height: 5rem;
    resize: vertical;
}
.diary-templates-field textarea:focus {
    outline: 2px solid var(--primary-color);
    outline-offset: -2px;
    border-color: var(--primary-color);
}

/* Share-actions group — secondary action row inside the edit view, sat
 * between the primary save row and the destructive delete row. The label
 * hints what the buttons do without crowding them. */
.diary-templates-share-actions {
    margin-top: var(--s-4);
    padding-top: var(--s-3);
    border-top: 1px solid var(--border-color);
}
.diary-templates-share-label {
    display: block;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    font-weight: 600;
    margin-bottom: var(--s-2);
}
.diary-templates-share-buttons {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--s-2);
}
.diary-templates-share-buttons button {
    appearance: none;
    border: 1px solid var(--border-strong);
    background: var(--card-bg);
    color: var(--text-color);
    padding: var(--s-3) var(--s-2);
    font: inherit;
    font-size: 14px;
    font-weight: 500;
    border-radius: var(--r-md);
    cursor: pointer;
    min-height: 44px;
}
.diary-templates-share-buttons button:hover,
.diary-templates-share-buttons button:focus-visible {
    background: var(--surface-muted);
    border-color: var(--primary-color);
    color: var(--primary-color);
    outline: none;
}
.diary-templates-danger-actions {
    margin-top: var(--s-3);
    padding-top: var(--s-3);
    border-top: 1px solid var(--border-color);
}

/* Bulk actions at the top of the manage list view — Export all / Import /
 * Scan QR to import. Wrapping flex on mobile, side-by-side on tablet+. */
.diary-templates-bulk-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-2);
    margin-bottom: var(--s-3);
}
.diary-templates-bulk-actions button {
    flex: 1 1 calc(33% - var(--s-2));
    min-width: 140px;
    appearance: none;
    border: 1px dashed var(--border-strong);
    background: transparent;
    color: var(--primary-color);
    padding: var(--s-2) var(--s-3);
    font: inherit;
    font-size: 13px;
    font-weight: 500;
    border-radius: var(--r-md);
    cursor: pointer;
    min-height: 40px;
}
.diary-templates-bulk-actions button:hover,
.diary-templates-bulk-actions button:focus-visible {
    background: var(--primary-soft);
    border-color: var(--primary-color);
    outline: none;
}

/* Composed-mode Instructions textarea hint. */
.composed-instructions-label {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 14px;
    font-weight: 500;
    color: var(--text-color);
    line-height: 1.3;
}
.composed-instructions-hint {
    display: block;
    font-size: 12px;
    color: var(--text-muted);
    font-weight: 400;
    margin-top: 2px;
    margin-bottom: 4px;
}
.composed-instructions-label textarea {
    font-size: 16px;
    font-family: inherit;
    line-height: 1.5;
    padding: var(--s-3);
    border: 1px solid var(--border-color);
    border-radius: var(--r-md);
    background: var(--card-bg);
    color: var(--text-color);
    box-sizing: border-box;
    width: 100%;
    min-height: 6rem;
    resize: vertical;
}
.composed-instructions-label textarea:focus {
    outline: 2px solid var(--primary-color);
    outline-offset: -2px;
    border-color: var(--primary-color);
}

/* ════════════════════════════════════════════════════════════════════════
 * QR SHARE MODAL (Phase 6.2)
 * Inline-SVG QR code rendering. Same overlay pattern as the other modals.
 * ════════════════════════════════════════════════════════════════════════ */
.diary-qr-modal[hidden] { display: none; }
.diary-qr-modal {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--s-3);
}
.diary-qr-modal-backdrop {
    position: absolute;
    inset: 0;
    background: var(--overlay-bg);
}
.diary-qr-modal-inner {
    position: relative;
    width: 100%;
    max-width: 360px;
    background: var(--card-bg);
    color: var(--text-color);
    border: 1px solid var(--border-color);
    border-radius: var(--r-lg);
    padding: var(--s-5) var(--s-4) var(--s-4);
    box-shadow: var(--shadow-pop);
    text-align: center;
}
.diary-qr-modal-close {
    position: absolute;
    top: var(--s-2);
    right: var(--s-2);
    width: 36px;
    height: 36px;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--text-light);
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
    padding: 0;
}
.diary-qr-modal-close:hover,
.diary-qr-modal-close:focus-visible {
    background: var(--surface-muted);
    color: var(--text-color);
    outline: none;
}
.diary-qr-modal-title {
    margin: 0 var(--s-8) var(--s-1) 0;
    font-size: 17px;
    font-weight: 600;
    color: var(--text-color);
    line-height: 1.25;
    text-align: left;
}
.diary-qr-modal-hint {
    margin: 0 0 var(--s-3);
    font-size: 13px;
    color: var(--text-muted);
    line-height: 1.4;
    text-align: left;
}
.diary-qr-modal-canvas {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: var(--s-3);
    background: #fff;        /* QR scanners read black-on-white best — fixed regardless of theme */
    border-radius: var(--r-md);
    margin-bottom: var(--s-3);
}
.diary-qr-modal-canvas svg {
    color: #111;
    max-width: 100%;
    height: auto;
}
.diary-qr-modal-meta {
    font-size: 12px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/* ════════════════════════════════════════════════════════════════════════
 * PRINT RECIPE (Phase 6.2)
 * Hidden under @media screen; the recipe-only view is shown under @media
 * print after diary.js sets `body.is-printing-recipe`. Everything else
 * (diary cards, modals, header, footer) is hidden so the user gets a
 * single clean recipe page.
 * ════════════════════════════════════════════════════════════════════════ */
.diary-print-recipe { display: none; }

@media print {
    /* When `is-printing-recipe` is set, hide every direct descendant of
     * the page except the print host. Same trick used by many cookbook
     * print stylesheets. The selectors are intentionally loose so they
     * cover the site header / footer / nav whatever the template uses. */
    body.is-printing-recipe > *:not(.diary-app),
    body.is-printing-recipe .diary-app > *:not(#diary-print-recipe),
    body.is-printing-recipe .diary-templates-modal,
    body.is-printing-recipe .diary-qr-modal,
    body.is-printing-recipe .diary-detail-modal,
    body.is-printing-recipe .diary-scan-modal {
        display: none !important;
    }
    body.is-printing-recipe .diary-print-recipe {
        display: block !important;
    }
    body.is-printing-recipe {
        background: #fff !important;
        color: #111 !important;
    }
    .print-recipe-card {
        max-width: 720px;
        margin: 0 auto;
        padding: 12mm 8mm;
        font-family: Georgia, 'Times New Roman', serif;
        line-height: 1.5;
        color: #111;
    }
    .print-header h1 {
        font-size: 28pt;
        margin: 0 0 4pt;
        line-height: 1.1;
    }
    .print-category {
        margin: 0 0 18pt;
        font-size: 11pt;
        text-transform: uppercase;
        letter-spacing: 0.08em;
        color: #555;
    }
    .print-section {
        page-break-inside: avoid;
        margin-bottom: 18pt;
    }
    .print-section h2 {
        font-size: 14pt;
        margin: 0 0 8pt;
        text-transform: uppercase;
        letter-spacing: 0.06em;
        color: #333;
        border-bottom: 1pt solid #aaa;
        padding-bottom: 3pt;
    }
    .print-ingredients {
        width: 100%;
        border-collapse: collapse;
        font-size: 11pt;
    }
    .print-ingredients td {
        padding: 4pt 0;
        border-bottom: 0.25pt dotted #bbb;
        vertical-align: top;
    }
    .print-ing-portion {
        width: 80pt;
        font-weight: 600;
        white-space: nowrap;
        font-variant-numeric: tabular-nums;
    }
    .print-ing-name { font-weight: 400; }
    .print-ing-kcal {
        width: 70pt;
        text-align: right;
        color: #555;
        font-variant-numeric: tabular-nums;
        white-space: nowrap;
    }
    .print-totals {
        margin: 8pt 0 0;
        font-size: 11pt;
        color: #333;
    }
    .print-instructions {
        font-size: 12pt;
        line-height: 1.6;
        color: #222;
    }
    /* Auto-rendered list inside print instructions (Phase 6.4 — was a
     * white-space:pre-wrap block before; now an actual <ol>/<ul>). */
    .print-instructions .recipe-instructions-list {
        margin: 0;
        padding-left: 18pt;
    }
    .print-instructions .recipe-instructions-list > li {
        margin-bottom: 6pt;
        line-height: 1.55;
    }
    .print-instructions > p {
        margin: 0 0 6pt;
    }
    /* Utensils + notes share the same list typography as instructions in
     * print, just slightly smaller. Notes get a thin left rule to mark
     * them as advisory. */
    .print-utensils, .print-notes {
        font-size: 11pt;
        line-height: 1.5;
        color: #333;
    }
    .print-utensils .recipe-instructions-list,
    .print-notes .recipe-instructions-list {
        margin: 0;
        padding-left: 18pt;
    }
    .print-utensils .recipe-instructions-list > li,
    .print-notes .recipe-instructions-list > li {
        margin-bottom: 4pt;
    }
    .print-notes {
        border-left: 1.5pt solid #aaa;
        padding-left: 8pt;
        font-style: italic;
    }
    .print-footer {
        margin-top: 36pt;
        font-size: 9pt;
        color: #888;
        border-top: 0.5pt solid #ddd;
        padding-top: 6pt;
        text-align: center;
    }
}

/* ════════════════════════════════════════════════════════════════════════
 * MEAL DETAIL MODAL (Group 3)
 * Tap a composed-meal row in today's list → drill in to ingredients and
 * totals. Same overlay/backdrop pattern as .diary-scan-modal so the
 * visual vocabulary is shared. Mobile-first at 375px; max-width 480px on
 * larger viewports so the body still feels like a focused dialog.
 * ════════════════════════════════════════════════════════════════════════ */
.diary-detail-modal[hidden] { display: none; }
.diary-detail-modal {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: flex-start;             /* anchored top so long ingredient lists scroll naturally */
    justify-content: center;
    padding: var(--s-3);
    overflow-y: auto;
}
.diary-detail-modal-backdrop {
    position: fixed;
    inset: 0;
    background: var(--overlay-bg);
}
.diary-detail-modal-inner {
    position: relative;
    width: 100%;
    max-width: 480px;
    background: var(--card-bg);
    color: var(--text-color);
    border: 1px solid var(--border-color);
    border-radius: var(--r-lg);
    padding: var(--s-5) var(--s-4) var(--s-4);
    box-shadow: var(--shadow-pop);
    margin: var(--s-4) auto;             /* breathing room on tall viewports */
}
.diary-detail-close {
    position: absolute;
    top: var(--s-2);
    right: var(--s-2);
    width: 36px;
    height: 36px;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--text-light);
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
    padding: 0;
}
.diary-detail-close:hover,
.diary-detail-close:focus-visible {
    background: var(--surface-muted);
    color: var(--text-color);
    outline: none;
}
.diary-detail-title {
    margin: 0 var(--s-8) var(--s-1) 0;   /* room for the close button */
    font-size: 18px;
    font-weight: 600;
    color: var(--text-color);
    line-height: 1.25;
    overflow-wrap: anywhere;
}
.diary-detail-when {
    margin: 0 0 var(--s-3);
    font-size: 13px;
    color: var(--text-muted);
    line-height: 1.4;
}
.diary-detail-totals {
    /* Inherits gradient + tokens from .diary-totals-card; keep margin tight
     * so the section header below sits close. */
    margin-bottom: var(--s-4);
}
.diary-detail-section-h {
    margin: 0 0 var(--s-2);
    font-size: 13px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    font-weight: 600;
    line-height: 1.2;
    border: 0;
    padding: 0;
}
.diary-detail-ingredients {
    list-style: none;
    margin: 0 0 var(--s-4);
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
}
.diary-detail-ing {
    padding: var(--s-3);
    background: var(--surface-muted);
    border: 1px solid var(--border-color);
    border-radius: var(--r-md);
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.diary-detail-ing .ing-row {
    display: flex;
    align-items: flex-start;
    gap: var(--s-3);
    min-width: 0;
}
.diary-detail-ing .ing-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.diary-detail-ing .ing-name {
    font-size: 14px;
    font-weight: 500;
    color: var(--text-color);
    line-height: 1.3;
    overflow-wrap: anywhere;
}
.diary-detail-ing .ing-portion {
    font-size: 12px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}
.diary-detail-ing .ing-kcal {
    flex: 0 0 auto;
    text-align: right;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.diary-detail-ing .ing-kcal strong {
    display: block;
    font-size: 15px;
    font-weight: 600;
    color: var(--text-color);
}
.diary-detail-ing .ing-kcal small {
    display: block;
    font-size: 10px;
    font-weight: 500;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.diary-detail-ing .ing-kcal-empty {
    font-size: 16px;
    color: var(--text-muted);
}
.diary-detail-ing .ing-macros {
    font-size: 12px;
    color: var(--text-muted);
    line-height: 1.4;
    overflow-wrap: anywhere;
    font-variant-numeric: tabular-nums;
}
.diary-detail-ing .ing-macros .sep {
    color: var(--text-light);
    margin: 0 4px;
}
.diary-detail-empty {
    list-style: none;
    padding: var(--s-4);
    text-align: center;
    color: var(--text-muted);
    font-style: italic;
    font-size: 14px;
    border: 1px dashed var(--border-strong);
    border-radius: var(--r-md);
}

/* Notes block in the meal-detail modal (Phase 6.5). Soft accent-tinted
 * card to mark it as advisory — same visual vocabulary as the recipe
 * notes panel in /my-recipes. */
.diary-detail-notes-wrap[hidden] { display: none; }
.diary-detail-notes-wrap {
    margin-bottom: var(--s-4);
}
.diary-detail-notes {
    background: var(--accent-soft);
    border-left: 3px solid var(--accent-color);
    padding: var(--s-3) var(--s-4);
    border-radius: var(--r-md);
    font-size: 14px;
    line-height: 1.5;
    color: var(--text-color);
    overflow-wrap: anywhere;
}
.diary-detail-notes .recipe-instructions-list {
    margin: 0;
    padding-left: var(--s-5);
}
.diary-detail-notes .recipe-instructions-list > li {
    margin-bottom: 4px;
}
.diary-detail-notes > p {
    margin: 0;
}
.diary-detail-actions {
    display: flex;
    gap: var(--s-2);
    flex-direction: column;
}
@media (min-width: 480px) {
    .diary-detail-actions { flex-direction: row; justify-content: flex-end; }
}
.diary-detail-actions button {
    appearance: none;
    border: 1px solid var(--error-border);
    background: var(--card-bg);
    color: var(--error-strong);
    padding: var(--s-3) var(--s-5);
    font-size: 15px;
    font-weight: 600;
    border-radius: var(--r-md);
    cursor: pointer;
    min-height: 44px;
}
.diary-detail-actions button:hover,
.diary-detail-actions button:focus-visible {
    background: var(--error-soft);
    outline: none;
}

/* Tap-to-open visual affordance on composed-meal rows in today's list.
 * Single-food rows omit .is-tappable so they keep the default appearance
 * (no hover/cursor → not interactive). */
.diary-entries .diary-entry.is-tappable {
    cursor: pointer;
    border-radius: var(--r-sm);
    transition: background 120ms ease;
}
.diary-entries .diary-entry.is-tappable:hover {
    background: var(--surface-muted);
}
.diary-entries .diary-entry.is-tappable:focus-visible {
    outline: 2px solid var(--primary-color);
    outline-offset: -2px;
    background: var(--surface-muted);
}
/* Internal interactive controls (delete button, photo thumb) keep their
 * pointer behaviour; the outer row's pointer still applies elsewhere. */
.diary-entries .diary-entry.is-tappable .entry-delete {
    cursor: pointer;        /* explicit so the cursor doesn't inherit-and-stay as the row's pointer */
}

/* Portion+unit: visually one widget. The number input on the left and
 * unit dropdown on the right share a single rounded border so it reads
 * as one control ("150 g") rather than two stacked fields. The unit
 * dropdown is always visible — never collapsed below the fold. Same
 * pattern will apply to composed-meal ingredient rows in 4.5.C. */
.diary-portion-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.diary-portion-label {
    font-size: 14px;
    font-weight: 500;
    color: var(--text-color);
    line-height: 1.3;
}
.diary-portion-row {
    display: flex;
    border: 1px solid var(--border-color);
    border-radius: var(--r-md);
    background: var(--card-bg);
    overflow: hidden;
    /* Inner shadow on focus-within highlights the whole control. */
    transition: border-color 120ms ease, box-shadow 120ms ease;
    /* Allow this flex container to shrink below its content's intrinsic
     * min-content. Without it, the select's widest option text
     * ("fluid ounces (fl oz)") pins the row above 400px and the page scrolls
     * horizontally on a 360–414px viewport. */
    min-width: 0;
}
.diary-portion-row:focus-within {
    border-color: var(--primary-color);
    box-shadow: inset 0 0 0 1px var(--primary-color);
}
/* Specificity: the generic `.diary-form input/select` block above has the
 * tag-selector advantage; the portion-input/unit overrides need to match
 * that with `.diary-form` prefix to win source-order ties. */
.diary-form .diary-portion-input,
.diary-form .diary-portion-unit {
    /* Strip per-child border + radius so the row's border owns the look.
     * 16px on font-size keeps iOS auto-zoom prevention. */
    border: 0;
    border-radius: 0;
    background: transparent;
    color: var(--text-color);
    font-size: 16px;
    font-family: inherit;
    line-height: 1.4;
    padding: var(--s-3);
    box-sizing: border-box;
    width: auto;
    min-width: 0;
}
.diary-form .diary-portion-input {
    flex: 1 1 auto;
    min-width: 0;
    -moz-appearance: textfield;
}
.diary-form .diary-portion-input::-webkit-outer-spin-button,
.diary-form .diary-portion-input::-webkit-inner-spin-button {
    /* Hide spinner buttons — they visually fight the divider. Up/down
     * arrow keys still increment. */
    -webkit-appearance: none;
    margin: 0;
}
.diary-form .diary-portion-unit {
    flex: 0 1 auto;
    /* min-width: 0 lets the select shrink below the widest <option>'s
     * intrinsic min-width (the row's overflow:hidden does the visual
     * trimming; the dropdown popout still shows the full label). */
    min-width: 0;
    /* Vertical divider between the input and select halves. */
    border-left: 1px solid var(--border-color);
    /* Native arrow stays on the select; the explicit padding-right gives
     * it room. Background-image chevron ensures the arrow is visible even
     * when the platform hides the native one. */
    padding-right: var(--s-8);
    background:
        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>")
        no-repeat right var(--s-3) center;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
}
.diary-form .diary-portion-input:focus,
.diary-form .diary-portion-unit:focus {
    outline: 0;        /* parent .diary-portion-row handles the focus ring */
    border-color: transparent;
    box-shadow: none;
}

/* Belt-and-braces colour binding for portion controls. The earlier
 * `.diary-form .diary-portion-input` rule depended on a `.diary-form`
 * ancestor, which is brittle: if the input is ever rendered outside that
 * context (e.g. a future detail modal that re-uses .diary-portion-row)
 * the colour tokens stop applying and the number renders unstyled —
 * which on some browsers/themes resolves to white-on-white.
 *
 * Anchoring the binding on `.diary-portion-row` itself makes the rule
 * win regardless of what's above it in the DOM. -webkit-text-fill-color
 * additionally defeats Chrome's autofill override, which otherwise paints
 * the number a fixed near-white. */
.diary-portion-row .diary-portion-input,
.diary-portion-row .diary-portion-unit {
    color: var(--text-color);
    background-color: transparent;
    -webkit-text-fill-color: var(--text-color);
}
.diary-portion-row .diary-portion-input::placeholder {
    color: var(--text-muted);
    opacity: 1;
}
/* Chrome's autofill paints with !important inline, only -webkit-text-fill-color
 * + a long box-shadow trick can override. Keep the text colour theme-aware
 * even after autofill; box-shadow stand-in for background-color (which
 * Chrome locks during autofill). */
.diary-portion-row .diary-portion-input:-webkit-autofill,
.diary-portion-row .diary-portion-input:-webkit-autofill:hover,
.diary-portion-row .diary-portion-input:-webkit-autofill:focus {
    -webkit-text-fill-color: var(--text-color);
    -webkit-box-shadow: 0 0 0 1000px var(--card-bg) inset;
    caret-color: var(--text-color);
}

/* Native <option> popups don't reliably inherit our text/background tokens
 * from the parent <select>. On dark theme this leaves the OS popup with a
 * light background BUT our --text-color (near-white) cascading into option
 * text → unreadable white-on-white when the user opens the dropdown.
 * Pin both color and background-color on option/optgroup so the popup
 * follows our theme regardless of OS preference. Modern Chrome/Edge/Firefox
 * all honour option styling now; Safari is more limited but still picks up
 * the colours when explicit. */
.diary-portion-row .diary-portion-unit option,
.diary-portion-row .diary-portion-unit optgroup {
    color: var(--text-color);
    background-color: var(--card-bg);
}
/* Disabled options (rare here, but guard anyway) — keep readable. */
.diary-portion-row .diary-portion-unit option:disabled {
    color: var(--text-muted);
}

/* Chevron stroke is theme-aware via a CSS custom prop so the same rule
 * works in both light and dark themes. The hardcoded grey-500 hex from the
 * earlier rule was visible in light mode but felt washed-out in dark; using
 * currentColor mapping via a token keeps WCAG contrast on both themes. */
.diary-form .diary-portion-unit {
    background-image:
        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
}
[data-theme="dark"] .diary-form .diary-portion-unit {
    background-image:
        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23cbd5e1' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
}

/* Nutrition fieldset — 2-col mobile, 3-col tablet+ */
.diary-form fieldset {
    grid-column: 1 / -1;
    border: 1px solid var(--border-color);
    border-radius: var(--r-md);
    padding: var(--s-3);
    margin: 0;
}
.diary-form fieldset legend {
    padding: 0 var(--s-2);
    color: var(--text-light);
    font-size: 13px;
    font-weight: 500;
}
.diary-form .nutrition-row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--s-2);
}
@media (min-width: 480px) {
    .diary-form .nutrition-row {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}
.diary-form .nutrition-row label {
    font-size: 12px;
    color: var(--text-light);
}

/* Action row — primary + secondary */
.diary-form-actions {
    grid-column: 1 / -1;
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
    margin-top: var(--s-2);
}
@media (min-width: 480px) {
    .diary-form-actions { flex-direction: row; }
    .diary-form-actions button { flex: 1; }
}
.diary-form-actions button {
    appearance: none;
    border: 1px solid var(--primary-color);
    background: var(--primary-color);
    color: var(--card-bg);
    padding: var(--s-3) var(--s-5);
    font-size: 16px;
    font-weight: 600;
    border-radius: var(--r-md);
    cursor: pointer;
    min-height: 48px;
}
.diary-form-actions button.is-secondary {
    background: var(--card-bg);
    color: var(--primary-color);
}
.diary-form-actions button:focus-visible {
    outline: 2px solid var(--primary-color);
    outline-offset: 2px;
}

/* Photo preview — centred below the camera trigger, with a remove button
 * overlaid on the image. The frame is sized to the image so the remove
 * button anchors to the image's top-right rather than the row's. */
.diary-photo-preview {
    grid-column: 1 / -1;
    display: none;
}
.diary-photo-preview.has-photo {
    display: flex;
    justify-content: center;
}
.diary-photo-preview-frame {
    position: relative;
    display: inline-block;
    line-height: 0;                          /* kill the inline-img descender gap */
}
.diary-photo-preview img {
    max-width: 100%;
    max-height: 240px;
    border-radius: var(--r-sm);
    border: 1px solid var(--border-color);
    display: block;
}
.diary-photo-preview-remove {
    position: absolute;
    top: 6px;
    right: 6px;
    width: 32px;
    height: 32px;
    border: 0;
    border-radius: 50%;
    /* Translucent dark plate — works against any photo without a backdrop
     * filter dependency. Slightly more solid on hover/focus for clarity. */
    background: rgba(17, 24, 39, 0.65);
    color: #ffffff;
    cursor: pointer;
    font-size: 18px;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}
.diary-photo-preview-remove:hover,
.diary-photo-preview-remove:focus-visible {
    background: rgba(17, 24, 39, 0.85);
    outline: 2px solid var(--card-bg);
    outline-offset: 1px;
}

/* Reference banner — when the entry came from scanner / encyclopedia */
.diary-ref-banner {
    grid-column: 1 / -1;
    display: none;
    background: var(--accent-soft);
    border: 1px solid var(--accent-color);
    border-radius: var(--r-md);
    padding: var(--s-2) var(--s-3);
    font-size: 13px;
    color: var(--text-color);
}
.diary-ref-banner.visible { display: block; }
.diary-ref-banner button {
    margin-left: var(--s-2);
    background: transparent;
    border: 0;
    color: var(--primary-color);
    text-decoration: underline;
    cursor: pointer;
    font: inherit;
    font-size: 13px;
    padding: 0;
}

/* ════════════════════════════════════════════════════════════════════════
 * COMPOSED-MEAL FORM (Phase 4.5.C)
 * Multi-ingredient meals — list of ingredient rows + meal-totals card.
 * Same `.diary-form` grid as the single-food form, so the visual rhythm
 * (typography, spacing, full-width sections) is shared between modes.
 * ════════════════════════════════════════════════════════════════════════ */
.composed-form .ingredients {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
    /* Hide the list when empty so the empty-state / add button collapse together. */
}
.composed-form .ingredients:empty { display: none; }

/* One ingredient row — three stacked sections so density stays low at
 * 360px width: head (name + badge + remove), portion controls, row totals. */
.composed-form .ingredient {
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
    padding: var(--s-3);
    background: var(--surface-muted);
    border: 1px solid var(--border-color);
    border-radius: var(--r-md);
    min-width: 0;
}
.composed-form .ingredient-head {
    display: flex;
    align-items: flex-start;
    gap: var(--s-2);
    min-width: 0;
}
.composed-form .ingredient-name-line {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: flex-start;
    gap: var(--s-2);
    flex-wrap: wrap;
}
.composed-form .ingredient-name-text {
    font-weight: 500;
    color: var(--text-color);
    font-size: 15px;
    line-height: 1.35;
    /* Wrap freely up to 2 lines; only ellipsis after that. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    overflow-wrap: anywhere;
}
.composed-form .ingredient-remove {
    flex: 0 0 auto;
    background: transparent;
    border: 0;
    cursor: pointer;
    color: var(--text-muted);
    font-size: 22px;
    line-height: 1;
    padding: 4px 8px;
    border-radius: var(--r-sm);
    min-width: 32px;
    min-height: 32px;
}
.composed-form .ingredient-remove:hover,
.composed-form .ingredient-remove:focus-visible {
    background: var(--error-soft);
    color: var(--error-color);
    outline: none;
}

/* Per-ingredient portion + unit — uses the same bordered combo control as
 * the single-food form (.diary-portion-row), inherited from the existing
 * rules above. The row itself sits inside a flex column inside the
 * ingredient card. */
.composed-form .ingredient .diary-portion-row {
    /* Slightly tighter padding inside the ingredient card to keep density
     * sensible — ingredient cards are already nested. */
    background: var(--card-bg);
}

/* Per-row totals — kcal leads visually (16px bold), macros follow as
 * a single muted line beneath. Easier to scan than equal-weight values. */
.composed-form .ingredient-totals {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--s-3);
    padding-top: 2px;
    font-variant-numeric: tabular-nums;
}
.composed-form .ingredient-kcal {
    font-size: 16px;
    font-weight: 600;
    color: var(--text-color);
    white-space: nowrap;
}
.composed-form .ingredient-kcal small {
    font-size: 11px;
    font-weight: 500;
    color: var(--text-muted);
    margin-left: 2px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.composed-form .ingredient-macros {
    font-size: 12px;
    color: var(--text-muted);
    line-height: 1.4;
    overflow-wrap: anywhere;
}
.composed-form .ingredient-macros .sep {
    color: var(--text-light);
    margin: 0 4px;
}
.composed-form .ingredient-pending {
    font-size: 12px;
    color: var(--text-light);
    font-style: italic;
}

/* Empty state — shown when no ingredients added yet. */
.composed-form .empty-ingredients {
    border: 1px dashed var(--border-strong);
    border-radius: var(--r-md);
    padding: var(--s-5) var(--s-4);
    text-align: center;
    color: var(--text-light);
}
.composed-form .empty-ingredients .icon {
    display: block;
    font-size: 32px;
    line-height: 1;
    margin-bottom: var(--s-2);
}
.composed-form .empty-ingredients .title {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-color);
    margin-bottom: 4px;
}
.composed-form .empty-ingredients .hint {
    font-size: 13px;
    color: var(--text-muted);
    line-height: 1.4;
}

/* Add-ingredient button — dashed, primary-coloured, full width. */
.composed-form .add-ingredient {
    width: 100%;
    appearance: none;
    border: 1px dashed var(--primary-color);
    background: transparent;
    color: var(--primary-color);
    font: inherit;
    font-size: 14px;
    font-weight: 500;
    padding: var(--s-3);
    border-radius: var(--r-md);
    cursor: pointer;
    min-height: 48px;
}
.composed-form .add-ingredient:hover,
.composed-form .add-ingredient:focus-visible {
    background: var(--primary-soft);
    outline: none;
}

/* Add-ingredient drawer — inline form revealed by the "+ Add ingredient"
 * button. Sits inside the form grid as a full-width section. */
.composed-form .composed-add-drawer {
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
    padding: var(--s-4);
    border: 1px solid var(--primary-color);
    border-radius: var(--r-md);
    background: var(--card-bg);
    min-width: 0;
}
/* `display: flex` above otherwise wins over the browser default
 * `[hidden] { display: none }`. Same gotcha as `.diary-form[hidden]`. */
.composed-form .composed-add-drawer[hidden] { display: none; }
.composed-form .meal-totals[hidden] { display: none; }
.composed-form .composed-ingredient-label {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 14px;
    font-weight: 500;
    color: var(--text-color);
    line-height: 1.3;
    min-width: 0;
}
.composed-form .composed-portion-field {
    /* Override the default 480px+ 2-col flow — inside the drawer the field
     * always sits full-width below the picker. */
    grid-column: 1 / -1;
}
.composed-form .composed-add-actions {
    display: flex;
    gap: var(--s-2);
    flex-wrap: wrap;
}
.composed-form .composed-add-actions button {
    flex: 1 1 auto;
    appearance: none;
    border: 1px solid var(--primary-color);
    background: var(--primary-color);
    color: var(--card-bg);
    padding: var(--s-3) var(--s-4);
    font: inherit;
    font-size: 15px;
    font-weight: 600;
    border-radius: var(--r-md);
    cursor: pointer;
    min-height: 44px;
    min-width: 0;
}
.composed-form .composed-add-actions button.is-secondary {
    background: var(--card-bg);
    color: var(--primary-color);
}
.composed-form .composed-add-actions button:focus-visible {
    outline: 2px solid var(--primary-color);
    outline-offset: 2px;
}

/* Meal totals — uppercase label + big kcal + breakdown line. Reuses the
 * .diary-totals-card visual language so the shared "totals" gradient
 * appears in both today's-totals and meal-totals. */
.composed-form .meal-totals .label {
    /* Match the today's-totals card's micro-label treatment. */
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--primary-dark);
    font-weight: 600;
    margin-bottom: 4px;
}

/* ════════════════════════════════════════════════════════════════════════
 * TODAY — totals card + entries list
 * Totals card uses the same blue gradient as the meal-totals card from
 * the composed-meal mockup so the visual language is shared.
 * ════════════════════════════════════════════════════════════════════════ */
.diary-totals-card {
    background: linear-gradient(180deg, var(--diary-totals-bg-from), var(--diary-totals-bg-to));
    border: 1px solid var(--diary-totals-border);
    border-radius: var(--r-md);
    padding: var(--s-3) var(--s-4);
    margin-bottom: var(--s-3);
}
.diary-totals-card .label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--primary-dark);
    font-weight: 600;
    margin-bottom: 4px;
}
.diary-totals-card .value {
    font-size: 22px;
    font-weight: 600;
    color: var(--text-color);
    font-variant-numeric: tabular-nums;
    line-height: 1.2;
}
.diary-totals-card .breakdown {
    margin-top: 6px;
    font-size: 13px;
    color: var(--text-light);
    font-variant-numeric: tabular-nums;
    line-height: 1.4;
}
.diary-totals-card .breakdown .sep {
    color: var(--text-muted);
    margin: 0 4px;
}

/* ── Today / Target / % table ─────────────────────────────────────────── */
.diary-totals-card .totals-table-mount { margin-top: 10px; }
.diary-totals-card .totals-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
}
.diary-totals-card .totals-table thead th {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    font-weight: 600;
    text-align: right;
    padding: 4px 6px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}
.diary-totals-card .totals-table thead th:first-child { text-align: left; }
.diary-totals-card .totals-table tbody th {
    text-align: left;
    font-weight: 500;
    color: var(--text-color);
    padding: 6px 6px;
    border-bottom: 1px dotted rgba(0, 0, 0, 0.07);
    background: transparent;
}
.diary-totals-card .totals-table tbody td {
    text-align: right;
    color: var(--text-color);
    padding: 6px 6px;
    border-bottom: 1px dotted rgba(0, 0, 0, 0.07);
}
.diary-totals-card .totals-table tbody tr:last-child th,
.diary-totals-card .totals-table tbody tr:last-child td {
    border-bottom: 0;
}
.diary-totals-card .totals-table .t-now { font-weight: 600; }
.diary-totals-card .totals-table .t-tgt { color: var(--text-light); }
.diary-totals-card .totals-table .t-unit {
    color: var(--text-muted);
    font-weight: 400;
    font-size: 11px;
    margin-left: 2px;
}
.diary-totals-card .t-pct-pill {
    display: inline-block;
    min-width: 42px;
    text-align: center;
    padding: 1px 6px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 700;
    line-height: 1.4;
}
.t-pct-pill--green { background: #dcfce7; color: #166534; }
.t-pct-pill--amber { background: #fef3c7; color: #92400e; }
.t-pct-pill--red   { background: #fee2e2; color: #991b1b; }
/* "over" — a min-target macro that's been exceeded substantially. We tint
 * blue (not red) because going past target on protein/fibre/kcal isn't a
 * health red flag the way over-target salt or sat fat is. */
.t-pct-pill--over  { background: #dbeafe; color: #1e40af; }
.t-pct-pill--blank { background: transparent; color: var(--text-muted); font-weight: 400; }

[data-theme="dark"] .t-pct-pill--green { background: rgba(34, 197, 94, 0.16);  color: #4ade80; }
[data-theme="dark"] .t-pct-pill--amber { background: rgba(217, 119, 6, 0.18);  color: #fbbf24; }
[data-theme="dark"] .t-pct-pill--red   { background: rgba(220, 38, 38, 0.18);  color: #fca5a5; }
[data-theme="dark"] .t-pct-pill--over  { background: rgba(59, 130, 246, 0.18); color: #93c5fd; }

[data-theme="dark"] .diary-totals-card .totals-table thead th,
[data-theme="dark"] .diary-totals-card .totals-table tbody th,
[data-theme="dark"] .diary-totals-card .totals-table tbody td {
    border-color: rgba(255, 255, 255, 0.08);
}

/* "Targets: <profile>" line below the table. The profile name is a button
 * that opens the preferences modal. Tinted to read as actionable but not
 * loud — secondary affordance. */
.diary-totals-card .totals-targets-line {
    margin-top: 10px;
    font-size: 12px;
    color: var(--text-muted);
    display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.diary-totals-card .totals-targets-label { color: var(--text-muted); }
.diary-totals-card .totals-targets-btn {
    appearance: none; background: none;
    border: 0;
    padding: 0;
    color: var(--primary-dark, #1e3a8a);
    text-decoration: underline;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}
.diary-totals-card .totals-targets-btn:hover,
.diary-totals-card .totals-targets-btn:focus-visible {
    color: var(--primary-color, #2563eb);
    outline: none;
}

/* ════════════════════════════════════════════════════════════════════════
 * TARGETS MODAL — sex + age band picker, persisted to localStorage.
 * Shape mirrors the scanner's history modal so users see one pattern.
 * ════════════════════════════════════════════════════════════════════════ */
body.diary-modal-open { overflow: hidden; }
.targets-modal {
    position: fixed; inset: 0;
    z-index: 1000;
    display: flex; align-items: center; justify-content: center;
    padding: 1rem;
}
.targets-modal-backdrop {
    position: absolute; inset: 0;
    background: rgba(17, 24, 39, 0.55);
    cursor: pointer;
}
.targets-modal-panel {
    position: relative;
    width: min(420px, 100%);
    max-height: calc(100vh - 2rem);
    display: flex; flex-direction: column;
    background: var(--card-bg, #ffffff);
    border: 1px solid var(--border-color);
    border-radius: 14px;
    box-shadow: 0 12px 32px rgba(17,24,39,0.18);
    overflow: hidden;
}
.targets-modal-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 0.5rem;
    padding: 0.85rem 1rem;
    border-bottom: 1px solid var(--border-color);
}
.targets-modal-head h2 {
    margin: 0;
    font-size: 16px;
    font-weight: 600;
    color: var(--text-color);
    line-height: 1.2;
}
.targets-modal-close {
    appearance: none;
    background: transparent; border: 0;
    color: var(--text-muted);
    font-size: 24px; line-height: 1;
    padding: 0 4px;
    cursor: pointer;
}
.targets-modal-close:hover, .targets-modal-close:focus-visible {
    color: var(--text-color); outline: none;
}
.targets-modal-meta {
    margin: 0;
    padding: 0.65rem 1rem 0;
    font-size: 12px;
    color: var(--text-muted);
    line-height: 1.5;
}
.targets-modal-form {
    padding: 0.75rem 1rem 1rem;
    display: flex; flex-direction: column; gap: 0.75rem;
}
.targets-field {
    display: flex; flex-direction: column; gap: 4px;
    font-size: 13px;
    color: var(--text-color);
}
.targets-field span {
    font-weight: 600;
    color: var(--text-light);
}
.targets-field select {
    appearance: none;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    padding: 8px 10px;
    background: var(--card-bg, #ffffff);
    font: inherit; font-size: 14px;
    color: var(--text-color);
    line-height: 1.3;
    min-height: 36px;
}
.targets-modal-actions {
    margin-top: 0.5rem;
    display: flex; align-items: center; justify-content: space-between;
    gap: 0.5rem; flex-wrap: wrap;
}
.targets-modal-actions-right {
    display: flex; gap: 0.5rem;
}
.targets-modal-reset {
    appearance: none; background: none; border: 0; padding: 0;
    font: inherit; font-size: 12px; color: var(--text-muted);
    text-decoration: underline; cursor: pointer;
}
.targets-modal-reset:hover, .targets-modal-reset:focus-visible {
    color: var(--text-color); outline: none;
}
.targets-modal-cancel {
    appearance: none;
    background: none;
    border: 1px solid var(--border-color);
    border-radius: 999px;
    padding: 0.35rem 0.85rem;
    font: inherit; font-size: 13px; font-weight: 500;
    color: var(--text-color);
    cursor: pointer;
}
.targets-modal-save {
    appearance: none;
    background: var(--primary-color, #2563eb);
    color: #ffffff;
    border: 1px solid var(--primary-color, #2563eb);
    border-radius: 999px;
    padding: 0.35rem 1rem;
    font: inherit; font-size: 13px; font-weight: 600;
    cursor: pointer;
}
.targets-modal-save:hover, .targets-modal-save:focus-visible {
    background: var(--primary-dark, #1e3a8a); border-color: var(--primary-dark, #1e3a8a);
    outline: none;
}

/* Entries list — Component 4 grid: time | meal | kcal | delete */
.diary-entries {
    list-style: none;
    margin: 0;
    padding: 0;
}
.diary-entries .diary-entry {
    display: grid;
    grid-template-columns: auto 1fr auto auto;
    gap: var(--s-3);
    padding: var(--s-3) 0;
    align-items: center;
    border-bottom: 1px solid var(--border-color);
}
.diary-entries .diary-entry:last-child { border-bottom: 0; }
.diary-entries .time {
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    font-size: 13px;
    min-width: 3.5em;
}
.diary-entries .meal {
    min-width: 0;
}
.diary-entries .meal-name {
    font-weight: 500;
    font-size: 14px;
    color: var(--text-color);
    line-height: 1.3;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    overflow-wrap: anywhere;
}
.diary-entries .meal-meta {
    display: block;
    font-size: 11px;
    color: var(--text-muted);
    margin-top: 2px;
}
.diary-entries .meal .ref-link {
    margin-left: 4px;
    color: var(--primary-color);
    text-decoration: none;
}
.diary-entries .photo-thumb {
    display: block;
    width: 32px;
    height: 32px;
    object-fit: cover;
    border-radius: var(--r-sm);
    border: 1px solid var(--border-color);
    margin-top: 4px;
}
.diary-entries .kcal {
    font-variant-numeric: tabular-nums;
    color: var(--text-color);
    white-space: nowrap;
    text-align: right;
    line-height: 1.1;
}
.diary-entries .kcal strong {
    display: block;
    font-size: 15px;
    font-weight: 600;
}
.diary-entries .kcal small {
    display: block;
    font-size: 10px;
    font-weight: 500;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.diary-entries .kcal-empty {
    font-size: 16px;
    color: var(--text-muted);
}
.diary-entries .entry-delete {
    appearance: none;
    border: 0;
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
    padding: var(--s-2);
    font-size: 18px;
    line-height: 1;
    border-radius: var(--r-sm);
    min-width: 32px;
    min-height: 32px;
}
.diary-entries .entry-delete:hover,
.diary-entries .entry-delete:focus-visible {
    background: var(--surface-muted);
    color: var(--error-color);
    outline: none;
}

.diary-empty {
    color: var(--text-muted);
    text-align: center;
    padding: var(--s-6) var(--s-4);
    font-style: italic;
    font-size: 14px;
}

/* ════════════════════════════════════════════════════════════════════════
 * WEEKLY CHART — hand-rolled SVG, lives inside a card.
 * ════════════════════════════════════════════════════════════════════════ */
.diary-chart svg {
    width: 100%;
    height: 200px;
    display: block;
}
.diary-chart .bar       { fill: var(--primary-color); }
.diary-chart .bar.today { fill: var(--primary-dark); }
.diary-chart .axis      { stroke: var(--border-strong); stroke-width: 1; }
.diary-chart .day-label { fill: var(--text-light); font-size: 11px; }
.diary-chart .val-label { fill: var(--text-color); font-size: 11px; font-variant-numeric: tabular-nums; }
.diary-chart .gridline  { stroke: var(--surface-muted); stroke-width: 1; }

.diary-chart-empty {
    color: var(--text-muted);
    font-style: italic;
    text-align: center;
    padding: var(--s-4);
    font-size: 14px;
}

/* ════════════════════════════════════════════════════════════════════════
 * DIARY TOOLS — export / import / clear
 * ════════════════════════════════════════════════════════════════════════ */
.diary-tools {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-2);
}
.diary-tools button,
.diary-tools label.button {
    appearance: none;
    padding: var(--s-2) var(--s-4);
    font-size: 14px;
    font-weight: 500;
    border: 1px solid var(--border-strong);
    background: var(--card-bg);
    border-radius: var(--r-md);
    cursor: pointer;
    color: var(--text-color);
    min-height: 40px;
}
.diary-tools button:hover,
.diary-tools label.button:hover {
    background: var(--surface-muted);
}
.diary-tools button.is-danger {
    border-color: var(--error-border);
    color: var(--error-strong);
}
.diary-tools button.is-danger:hover {
    background: var(--error-soft);
}
.diary-tools input[type="file"] { display: none; }

.diary-storage-note {
    margin-top: var(--s-4);
    padding-top: var(--s-4);
    border-top: 1px solid var(--border-color);
    color: var(--text-light);
    font-size: 13px;
    line-height: 1.5;
}

/* ════════════════════════════════════════════════════════════════════════
 * SOURCE BADGES (autocomplete results, ingredient rows)
 * ════════════════════════════════════════════════════════════════════════ */
.source-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border-radius: var(--r-pill);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    line-height: 1.5;
}
.source-badge--enc {
    background: var(--source-enc-bg);
    color: var(--source-enc-fg);
}
.source-badge--off {
    background: var(--source-off-bg);
    color: var(--source-off-fg);
}

/* ════════════════════════════════════════════════════════════════════════
 * AUTOCOMPLETE COMPONENT — input + popout + states
 * ════════════════════════════════════════════════════════════════════════ */
.autocomplete {
    position: relative;
    margin-bottom: var(--s-3);
}
.autocomplete-input {
    width: 100%;
    border: 1px solid var(--border-color);
    border-radius: var(--r-md);
    padding: var(--s-3) var(--s-4) var(--s-3) var(--s-10);
    font: inherit;
    font-size: 16px;
    background: var(--card-bg) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='8'/><path d='m21 21-4.3-4.3'/></svg>") no-repeat var(--s-3) center;
    min-height: 48px;
    box-sizing: border-box;
    color: var(--text-color);
}
.autocomplete-input:focus {
    outline: 2px solid var(--primary-color);
    outline-offset: -2px;
    border-color: var(--primary-color);
}
.autocomplete-input.is-open {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
}
.autocomplete-popout {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: var(--card-bg);
    border: 1px solid var(--primary-color);
    border-top: 0;
    border-radius: 0 0 var(--r-md) var(--r-md);
    box-shadow: var(--shadow-pop);
    max-height: 360px;
    overflow-y: auto;
    z-index: 10;
}

/* Close button overlaid in the top-right of the popout. Sibling of the
 * popout (the popout's innerHTML gets replaced on every state change, so
 * a child button would be wiped out). z-index: 11 keeps it above the
 * popout's z-index: 10. */
.autocomplete-close {
    position: absolute;
    top: calc(100% + 4px);
    right: 4px;
    width: 32px;
    height: 32px;
    z-index: 11;
    appearance: none;
    border: 0;
    background: transparent;
    color: var(--text-muted);
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
    display: flex;                 /* shown via JS toggling display:flex/none */
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    padding: 0;
}
.autocomplete-close:hover,
.autocomplete-close:focus-visible {
    background: var(--surface-muted);
    color: var(--text-color);
    outline: none;
}
.autocomplete-result {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: var(--s-3);
    align-items: center;
    padding: var(--s-3) var(--s-4);
    border-bottom: 1px solid var(--border-color);
    cursor: pointer;
}
.autocomplete-result:last-child { border-bottom: 0; }
.autocomplete-result:hover,
.autocomplete-result:focus,
.autocomplete-result.is-active {
    background: var(--primary-soft);
}
.autocomplete-result .name-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--s-2);
    min-width: 0;
}
.autocomplete-result .name {
    font-size: 15px;
    font-weight: 500;
    color: var(--text-color);
    min-width: 0;
    line-height: 1.35;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    overflow-wrap: anywhere;
}
.autocomplete-result .meta {
    display: block;
    font-size: 12px;
    color: var(--text-light);
    margin-top: 2px;
}
.autocomplete-result .kcal {
    font-variant-numeric: tabular-nums;
    color: var(--text-light);
    font-size: 13px;
    white-space: nowrap;
    text-align: right;
}
/* Right column wraps the "+ Shop" chip and the kcal stack so they sit
 * cleanly side-by-side. Phase 5a — diary autocomplete adds-to-shopping. */
.autocomplete-result .autocomplete-result-right {
    display: flex;
    align-items: center;
    gap: var(--s-2);
}
.autocomplete-result .kcal strong {
    display: block;
    font-size: 16px;
    font-weight: 600;
    color: var(--text-color);
}
.autocomplete-result .kcal small {
    font-size: 11px;
    color: var(--text-muted);
}

.autocomplete-state {
    padding: var(--s-6) var(--s-4);
    text-align: center;
    color: var(--text-light);
    font-size: 14px;
}
.autocomplete-state.is-loading::before {
    content: '';
    display: block;
    width: 20px; height: 20px;
    margin: 0 auto var(--s-3);
    border: 2px solid var(--border-strong);
    border-top-color: var(--primary-color);
    border-radius: 50%;
    animation: nfl-autocomplete-spin 0.8s linear infinite;
}
@keyframes nfl-autocomplete-spin { to { transform: rotate(360deg); } }
.autocomplete-state.is-error {
    color: var(--error-color);
}
.autocomplete-state .freetext-cta {
    margin-top: var(--s-3);
    font-size: 13px;
    color: var(--primary-color);
    font-weight: 500;
    cursor: pointer;
    text-decoration: underline;
    background: transparent;
    border: 0;
    font-family: inherit;
}
.autocomplete-state .freetext-cta + .freetext-cta {
    margin-left: var(--s-3);
}

/* Degraded-mode notice — shown above the autocomplete input when the
 * off.db isn't reachable and search has been narrowed to USDA + encyclopedia.
 * Inserted by autocomplete.js once per page-load, keyed on the host
 * container's `has-off-degraded-notice` flag class. */
.autocomplete-degraded-notice {
    margin: 0 0 var(--s-3);
    padding: var(--s-2) var(--s-3);
    display: flex;
    gap: var(--s-2);
    align-items: flex-start;
    font-size: 13px;
    line-height: 1.45;
    color: var(--text-color);
    background: var(--surface-muted);
    border-left: 3px solid var(--text-light);
    border-radius: var(--r-sm);
}
.autocomplete-degraded-icon {
    flex: 0 0 auto;
    color: var(--text-light);
    font-weight: 700;
    line-height: 1.45;
}

/* Defensive: when the host element is a flex or grid parent (as the diary
 * food-row IS), the inserted notice would otherwise become a flex sibling
 * and split the row. Force it onto its own line by claiming the full
 * inline-axis. flex-basis covers flex parents; grid-column: 1/-1 covers
 * grid parents. Block-level fallback works in vanilla flow. */
.autocomplete-degraded-notice {
    width: 100%;
    flex: 1 0 100%;
    grid-column: 1 / -1;
}

/* Phase 5c — "Read more →" link on autocomplete rows whose USDA result
 * has a matching whole-foods encyclopedia entry. Sits inline with the
 * source-badge in the name-row. Tapping it navigates rather than picks. */
.autocomplete-result-encyclopedia {
    font-size: 11px;
    font-weight: 500;
    color: var(--primary-color);
    text-decoration: none;
    border-bottom: 1px dashed currentColor;
    padding-bottom: 1px;
    flex: 0 0 auto;
    line-height: 1.5;
}
.autocomplete-result-encyclopedia:hover,
.autocomplete-result-encyclopedia:focus-visible {
    color: var(--primary-dark);
    border-bottom-style: solid;
    outline: none;
}
