/* Related tools — subtle internal links row inside footer (discovery + SEO) */
.related-tools {
    padding-bottom: 7px;
    margin-bottom: 7px;
    border-bottom: 1px solid var(--color-border, #e2e8f0);
    line-height: 1.3;
}
.related-tools-label {
    color: var(--color-text-light, #718096);
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    font-size: 0.7rem;
    margin-right: 12px;
    vertical-align: middle;
}
.related-tools .footer-link {
    color: var(--color-text-medium, #4a5568);
    font-weight: 400;
    font-size: 0.85rem;
    border-bottom: none;
    vertical-align: middle;
}
.related-tools .footer-link:hover {
    color: var(--color-accent, #00a8e8);
    border-bottom: none;
}

/* ============================================================
   ALLERGY DIARY — Try Swiss Knife
   ── "Dusk" ──────────────────────────────────────────────────
   The palette is taken from the tool's own mechanic. This diary
   walks backwards through the hours of a day (§4.2's five fixed
   clock bands), and it is mostly opened at night, after the
   fact. So: a faint violet-grey haze for the page, white cards
   sitting lit on top of it, deep indigo ink, and one saturated
   indigo-violet for anything the user has marked.

   Two colour systems, and they must never be confused:
     · indigo-violet  = interaction and what you filled in
     · the warm ramp  = how bad the reaction got (ordered data)
   Because they sit at opposite temperatures, a severity ramp can
   never be misread as an alert (§2 — data, never alarm).

   The five bands of the day are the one flourish: they appear as
   small nodes on the recall trail and as a five-stop stripe at
   the top of the welcome card. Nothing else in the tool uses
   them, and they are deliberately low-chroma — this is ambience,
   not signal.

   Platform type sizes are unchanged: body is 1rem here exactly
   as on every other tool. Density is bought with structure —
   collapsed steps, one toolbar row — never by shrinking text.
   ============================================================ */

:root {
    --color-primary: #2C2A4A;        /* deep indigo ink — headings, dark bars */
    --color-accent: #4C43A8;
    --color-accent-hover: #3D3690;
    --color-accent-soft: #EFEDFA;
    --color-accent-line: #CFC9EE;
    --color-white: #ffffff;
    --color-background: #F1EFF5;     /* twilight haze — the page ground */
    --color-border: #E4E1EC;
    --color-border-strong: #C9C5D8;
    --color-text-dark: #242235;
    --color-text-medium: #565471;
    --color-text-light: #6B6782;    /* 4.7:1 on the haze, 5.3:1 on white */
    --color-success: #2F9E6E;
    --color-warning: #C99038;
    --color-error: #B3453A;
    --color-danger-light: #FBEFEC;
    --color-danger-line: #F0D9D3;
    --color-danger-ink: #8E2F22;

    /* Severity — one warm hue family, light to dark, so it reads as an
       ordered scale rather than four separate alarms. Mild is a muted
       slate so that "barely" never borrows the weight of a colour. */
    --sev-mild: #8A8AA6;
    --sev-uncomfortable: #C99038;
    --sev-bad: #C0602C;
    --sev-severe: #A33628;

    /* The day, from first light to dark. Trail nodes and the welcome
       stripe only — never a fill, never behind text. */
    --band-morning:   #D9A441;
    --band-midday:    #4E9CC4;
    --band-afternoon: #C98A52;
    --band-evening:   #9A6B94;
    --band-night:     #4C5385;

    /* The analysis hero is the tool's one inverted surface. It is NOT
       --color-primary: same hue (243° vs 244°) but richer and lighter
       (S 41% L 29% against S 28% L 23%), which is what stops it reading as a
       greyed navy. Sid's call, matching the design artefact.
       --hero-quiet carries the eyebrow and the stat labels — it has to sit
       below white without dropping out: 5.3:1 on the hero, AA at any size.
       White is 12.5:1 and --color-accent-line 7.9:1. */
    --hero-bg:    #2F2C68;
    --hero-quiet: #A9A4D6;

    /* ── Type scale: 6 steps, no in-betweens. Anchored on a 1rem body
         so this tool reads at the same size as every other TSK tool.
         The welcome hero sets its own clamp — it is the one display size. ── */
    --fs-micro: 0.75rem;     /* 12px — eyebrows, utility caps */
    --fs-xs:    0.8125rem;   /* 13px — meta, hints */
    --fs-sm:    0.875rem;    /* 14px — secondary body, chips */
    --fs-base:  1rem;        /* 16px — body */
    --fs-md:    1.0625rem;   /* 17px — emphasis, row names */
    --fs-lg:    1.25rem;     /* 20px — panel and lead titles */

    /* ── Spacing: 4px grid ── */
    --s1: 4px;
    --s2: 8px;
    --s3: 12px;
    --s4: 16px;
    --s5: 20px;
    --s6: 24px;
    --s8: 32px;

    /* Shadows are tinted with the ink, not black — a neutral shadow on a
       tinted ground goes grey and muddy where a tinted one stays clean. */
    --shadow-sm: 0 1px 2px rgba(36,34,53,0.07);
    --shadow-md: 0 4px 14px rgba(36,34,53,0.10);
    --shadow-lg: 0 12px 32px rgba(36,34,53,0.16);

    --radius-sm: 6px;
    --radius-md: 8px;
    --radius-lg: 12px;
    --radius-xl: 16px;

    --font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;

    --rail: 15px;          /* x-position of the trail spine */
    --trail-gap: 18px;     /* spine → content gutter */
    --step-gap: 30px;      /* entry-stepper spine → card gutter (wider: bigger marks) */
    --header-h: 57px;
    --control-h: 36px;     /* chips and small controls */

    /* ── Platform chrome — pinned to the shared TSK values ──
       The header band, its icon buttons and the language dropdown must look
       identical to every other tool, so they read from these tokens rather
       than from this tool's tightened density scale. Do not repoint them. */
    --chrome-white: #ffffff;
    --chrome-border: #e0e6ed;
    --chrome-bg: #f5f7fa;
    --chrome-text: #555f6d;
    --chrome-radius: 8px;
}

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

body {
    font-family: var(--font);
    background: var(--color-background);
    min-height: 100vh;
    color: var(--color-text-dark);
    font-size: var(--fs-base);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    padding-bottom: env(safe-area-inset-bottom);
}

.hidden { display: none !important; }

.seo-h1,
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: 0;
    overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
}

/* ─────────────────────────────── HEADER ───────────────────────────────
   Platform chrome — logo 36/34/30px and a 1.5rem title are documented
   TSK standards, so these sizes are deliberately left alone.          */
.header {
    width: 100%;
    background-color: #ffffff;
    border-bottom: 1px solid var(--chrome-border);
    position: sticky;
    top: 0;
    z-index: 1000;
    box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}

.header-inner {
    max-width: 980px;     /* aligned with .container, as on every tool */
    margin: 0 auto;
    padding: 0.5rem 1.5rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.header-left { display: flex; align-items: center; gap: var(--s3); }

.header-logo-link {
    display: flex;
    align-items: center;
    text-decoration: none;
    transition: opacity 0.2s ease;
}
.header-logo-link:hover { opacity: 0.85; }

.logo-image { height: 36px; width: auto; display: block; flex-shrink: 0; }

.tool-name-btn {
    font-size: 1.5rem;
    font-weight: 600;
    color: #1a2332;
    white-space: nowrap;
    line-height: 1.2;
    letter-spacing: -0.015em;
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    font-family: inherit;
    transition: color 0.15s;
}
.tool-name-btn:hover { color: var(--color-accent); }

.header-icons {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
    position: relative;
}

.header-icon-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    padding: 0;
    background: var(--chrome-white);
    border: 1px solid var(--chrome-border);
    border-radius: var(--chrome-radius);
    cursor: pointer;
    transition: all 0.2s ease;
    color: var(--chrome-text);
    font-family: inherit;
}
.header-icon-btn:hover {
    border-color: var(--color-accent);
    background: var(--chrome-bg);
    color: var(--color-accent);
}
.header-icon-btn svg { width: 20px; height: 20px; }

.lang-short {
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--chrome-text);
    letter-spacing: 0.02em;
}
.header-icon-btn:hover .lang-short { color: var(--color-accent); }

/* ─── Language dropdown ───
   The selector lives in the actions menu, as it does on Home Maker Diary.
   `i18n.js` toggles `.active` on #languageDropdown — that class name is the
   contract with the shared engine, so it must not be renamed. */
.language-selector { position: relative; }

.language-dropdown {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    min-width: 150px;
    background: var(--chrome-white);
    border: 1px solid var(--chrome-border);
    border-radius: var(--chrome-radius);
    box-shadow: var(--shadow-md);
    overflow: hidden;
    display: none;
    z-index: 1100;
}
.language-dropdown.active { display: block; }

.lang-option {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    padding: 0.6rem 1rem;
    background: none;
    border: none;
    font-family: inherit;
    font-size: 0.875rem;
    color: var(--color-text-dark);
    text-align: left;
    cursor: pointer;
    transition: background 0.15s;
}
.lang-option:hover { background: var(--color-background); }
.lang-option.active { background: rgba(76,67,168,0.09); color: var(--color-accent); }
.lang-check { font-size: 0.75rem; opacity: 0; transition: opacity 0.15s; }
.lang-option.active .lang-check { opacity: 1; }

/* ─────────────────────────────── LAYOUT ─────────────────────────────── */
.container {
    width: 100%;
    max-width: 980px;
    margin: 0 auto;
    padding: var(--s5) var(--s5) 0;
}

.view { animation: viewIn 0.18s ease; }

@keyframes viewIn {
    from { opacity: 0; transform: translateY(3px); }
    to   { opacity: 1; transform: none; }
}

/* ─── Info banner ─── */
.info-banner {
    display: flex;
    align-items: flex-start;
    gap: var(--s2);
    background: var(--color-white);
    border: 1px solid var(--color-accent-line);
    border-radius: var(--radius-lg);
    padding: var(--s2) var(--s3);
    margin-bottom: var(--s4);
    font-size: var(--fs-xs);
    line-height: 1.45;
    color: var(--color-text-medium);
}
.info-icon { flex-shrink: 0; font-size: var(--fs-sm); line-height: 1.4; }
.info-text strong { color: var(--color-primary); margin-right: var(--s1); }
.info-close {
    margin-left: auto;
    background: none;
    border: none;
    font-size: 1.1rem;
    line-height: 1;
    color: var(--color-text-light);
    cursor: pointer;
    padding: 0 2px;
    flex-shrink: 0;
}
.info-close:hover { color: var(--color-text-dark); }

/* ─────────────────────── TYPE ROLES ───────────────────────
   One family, three jobs: a deep-navy display voice, ordinary
   body text, and a spaced tabular utility voice used for every
   clock value and band name in the tool.                     */
.sheet-eyebrow,
.sheet-section-label,
.slot-band,
.slot-range,
.day-divider span,
.detail-label,
.detail-slot-head,
.anchor-bar-label,
.result-composite-mark,
.related-tools-label {
    font-size: var(--fs-micro);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-variant-numeric: tabular-nums;
    color: var(--color-text-light);
}

/* ─────────────────────────── WELCOME ───────────────────────────
   The first screen explains what the tool is for before asking for
   anything. It shares the card chrome with the entry steps, so the
   welcome and step 1 read as one product.                        */
.welcome {
    position: relative;
    background:
        linear-gradient(180deg, #F4F2FC 0%, rgba(244,242,252,0) 190px),
        var(--color-white);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-xl);
    padding: var(--s6) var(--s6) var(--s5);
    margin-bottom: var(--s4);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}
/* The tool's one flourish, and its thesis: a day, left to right, from
   first light to dark. It is the same five bands the recall trail walks
   backwards through — so the first thing on the first screen is the
   shape of the thing the tool asks you to remember. */
.welcome::before {
    content: '';
    position: absolute;
    inset: 0 0 auto;
    height: 4px;
    /* Hard stops, at each band's real width in §4.2's clock: morning 6h,
       midday 4h, afternoon 3h, evening 4h, night 7h. A blend would read as
       decoration; five measured segments are the day drawn to scale. */
    background: linear-gradient(90deg,
        var(--band-morning)   0      25%,
        var(--band-midday)    25%    41.667%,
        var(--band-afternoon) 41.667% 54.167%,
        var(--band-evening)   54.167% 70.833%,
        var(--band-night)     70.833% 100%);
}

/* The art is decorative — it says what the title already says — so it is
   aria-hidden. It floats rather than sitting in its own column: the copy then
   wraps around it, and on a narrow screen it only has to get smaller instead
   of being dropped. flow-root keeps the float off the how-strip below. */
.welcome-copy { display: flow-root; }
.welcome-art {
    float: right;
    width: 325px;
    height: auto;
    /* Top margin also pulls the art back up past the badge line it now follows
       (≈25px tall + its 12px margin), so it still tucks into the top-right
       corner rather than starting level with the title. */
    margin: -49px calc(-1 * var(--s3)) var(--s4) var(--s6);
    user-select: none;
    pointer-events: none;
}
@media (max-width: 900px) {
    .welcome-art { width: 225px; margin-left: var(--s5); margin-top: calc(-1 * var(--s3)); }
}
@media (max-width: 600px) {
    .welcome-art { width: 130px; margin-left: var(--s4); margin-bottom: var(--s3); }
}
@media (max-width: 380px) {
    .welcome-art { width: 115px; }
}

.welcome-badge {
    display: inline-flex;
    align-items: center;
    margin-bottom: var(--s3);
    padding: 4px 12px;
    border-radius: 999px;
    background: var(--color-accent);
    color: #fff;
    font-size: var(--fs-micro);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    line-height: 1.4;
}
.welcome-title {
    font-size: clamp(1.65rem, 1.2rem + 1.9vw, 2.25rem);
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: -0.028em;
    color: var(--color-primary);
    margin-bottom: var(--s3);
    text-wrap: balance;
}
.welcome-sub {
    font-size: var(--fs-base);
    line-height: 1.65;
    color: var(--color-text-medium);
    max-width: 62ch;
}
.welcome-sub strong { color: var(--color-text-dark); font-weight: 600; }

/* How it works — a real sequence, so it is numbered. */
.how-strip {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: var(--s5);
    list-style: none;
    margin: var(--s6) 0;
    padding: var(--s5) 0 0;
    border-top: 1px solid var(--color-border);
}
.how-step { display: flex; flex-direction: column; gap: 3px; }
.how-num {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px; height: 26px;
    margin-bottom: var(--s2);
    border-radius: 50%;
    background: var(--color-accent);
    color: #fff;
    font-size: var(--fs-xs);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    box-shadow: 0 0 0 4px var(--color-accent-soft);
}
.how-step strong { font-size: var(--fs-base); font-weight: 600; color: var(--color-text-dark); }
.how-step span:not(.how-num) { font-size: var(--fs-sm); line-height: 1.55; color: var(--color-text-medium); }

.welcome-actions {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: var(--s2);
}
.wel-btn {
    display: flex;
    align-items: center;
    gap: var(--s3);
    padding: var(--s3) var(--s4);
    background: var(--color-white);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-lg);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
}
.wel-btn:hover {
    border-color: var(--color-accent);
    background: var(--color-accent-soft);
    transform: translateY(-1px);
    box-shadow: var(--shadow-sm);
}
.wel-btn-glyph { font-size: 1.25rem; line-height: 1; flex-shrink: 0; }
.wel-btn-text {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 1px;
    min-width: 0;
}
.wel-btn-label { font-size: var(--fs-base); font-weight: 600; color: var(--color-text-dark); }
.wel-btn-note { font-size: var(--fs-xs); color: var(--color-text-light); }
.wel-btn-primary {
    background: var(--color-accent);
    border-color: var(--color-accent);
    box-shadow: 0 2px 10px rgba(76,67,168,0.30);
}
.wel-btn-primary:hover {
    background: var(--color-accent-hover);
    border-color: var(--color-accent-hover);
    box-shadow: 0 4px 16px rgba(76,67,168,0.36);
}
.wel-btn-primary .wel-btn-label { color: #fff; }
.wel-btn-primary .wel-btn-note { color: rgba(255,255,255,0.82); }

.welcome-note {
    margin-top: var(--s5);
    padding-top: var(--s4);
    border-top: 1px solid var(--color-border);
    font-size: var(--fs-xs);
    line-height: 1.5;
    color: var(--color-text-light);
    max-width: 78ch;
}

/* ─────────────────────────── DIARY VIEW ───────────────────────────
   The page's job is the list. Everything above it is one row: the count,
   one muted line of meta, and the two actions. An eyebrow, a full-width
   instruction line and a stats card used to sit here and cost roughly
   300px before the first entry — most of a laptop viewport spent on two
   buttons and a sentence. */
.diary-lead {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--s5);
    padding-bottom: var(--s3);
    margin-bottom: var(--s3);
    border-bottom: 1px solid var(--color-border-strong);
}
.diary-lead-text { min-width: 0; }
.lead-title {
    font-size: var(--fs-lg);
    font-weight: 600;
    line-height: 1.25;
    color: var(--color-primary);
    letter-spacing: -0.02em;
}
.lead-meta {
    margin-top: 2px;
    font-size: var(--fs-xs);
    color: var(--color-text-light);
}
.lead-meta:empty { display: none; }

.lead-actions {
    display: flex;
    align-items: center;
    gap: var(--s2);
    flex-shrink: 0;
}

.btn-log {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
    padding: 11px var(--s5);
    background: var(--color-accent);
    color: #fff;
    border: none;
    border-radius: var(--radius-md);
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s, box-shadow 0.15s, transform 0.1s;
    box-shadow: 0 2px 10px rgba(76,67,168,0.30);
}
.btn-log:hover {
    background: var(--color-accent-hover);
    box-shadow: 0 4px 16px rgba(76,67,168,0.36);
    transform: translateY(-1px);
}
.btn-log:active { transform: none; }
.btn-log-mark {
    font-size: var(--fs-md);
    font-weight: 400;
    line-height: 1;
    opacity: 0.85;
}

/* ─── Emergency notice ─── */
.emergency-note {
    display: flex;
    align-items: flex-start;
    gap: var(--s2);
    background: var(--color-danger-light);
    border: 1px solid var(--color-danger-line);
    border-left: 2px solid var(--sev-severe);
    border-radius: var(--radius-md);
    padding: var(--s2) var(--s3);
    margin-bottom: var(--s3);
    font-size: var(--fs-sm);
    line-height: 1.45;
    color: var(--color-danger-ink);
}
.emergency-mark {
    flex-shrink: 0;
    width: 17px; height: 17px;
    margin-top: 2px;
    border-radius: 50%;
    background: var(--sev-severe);
    color: #fff;
    font-size: 0.6875rem;
    font-weight: 700;
    line-height: 17px;
    text-align: center;
}
/* Standing for the whole entry flow. `is-live` is the escalation once a
   breathing or swelling symptom is ticked — a heavier rule and bolder text, not
   a reveal. Wording never changes (§2). */
.emergency-inline { margin: 0 0 var(--s3); }
.emergency-inline.is-live {
    border-left-width: 4px;
    background: #F8DFDA;
    font-weight: 500;
}

/* ─── Episode list ───
   The diary is the same timeline as the recall trail, one level up: a spine
   with a node per reaction, coloured by how bad it got. Reusing the metaphor
   ties the two screens together and is where the colour on this page comes
   from — the severity ramp is data, not decoration. */
/* Two columns from 900px. The sidebar's real job is to stop the entries running
   the full width of the container — the cards it carries are secondary. Left at
   980px: widening would mean widening `.header-inner` too, and that band is
   pinned to the platform (§22.10). */
.diary-grid { display: block; }
.diary-main { min-width: 0; }
.diary-side { display: none; }

@media (min-width: 900px) {
    .diary-grid {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 280px;
        gap: var(--s5);
        align-items: start;
    }
    .diary-side {
        display: flex;
        flex-direction: column;
        gap: var(--s3);
    }
    /* Not sticky: five cards are taller than most viewports, and a sticky
       column that overflows silently clips its last card. */
}

.diary-filters {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s1);
    margin-bottom: var(--s4);
}
.diary-filters:empty { display: none; }

/* Date rail + card. The rail owns the date, so the card no longer repeats it
   and the old `— MONDAY —` divider headings are gone. */
.episode-row {
    display: grid;
    grid-template-columns: 96px minmax(0, 1fr);
    align-items: start;
}
.episode-rail {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 1px;
    padding: var(--s4) var(--s3) 0 0;
    text-align: right;
    min-width: 0;
}
.rail-day {
    font-size: var(--fs-micro);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--color-text-light);
}
.rail-time {
    font-size: var(--fs-sm);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--color-primary);
}

.episode-list {
    position: relative;
    margin-bottom: var(--s5);
}
.episode-list:empty { display: none; }
/* The spine now runs down the card side of the grid, not the page. */
.episode-list::before {
    content: '';
    position: absolute;
    left: calc(96px + var(--rail));
    top: 12px;
    bottom: 14px;
    width: 1px;
    background: linear-gradient(180deg, var(--color-border-strong) 0%, var(--color-border-strong) 82%, transparent 100%);
}

.episode-card {
    position: relative;
    display: block;
    /* Not width:100% — the card is a grid item with a left margin, and 100%
       plus the margin overflows the track. `auto` + the default
       justify-self:stretch fills the column minus the margin. */
    width: auto;
    margin-left: calc(var(--rail) + var(--trail-gap));
    text-align: left;
    background: var(--color-white);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--s4) var(--s4) var(--s4) calc(var(--s4) - 3px);
    margin-bottom: var(--s2);
    font-family: inherit;
    cursor: pointer;
    transition: border-color 0.15s, box-shadow 0.15s, transform 0.1s;
}
.episode-card:hover {
    border-color: var(--color-accent-line);
    box-shadow: var(--shadow-md);
    transform: translateY(-1px);
}
.episode-card:active { transform: none; }

/* A severity-tinted edge, so a scan down the list reads as a ramp.
   A real border rather than an inset pseudo-element bar: the border follows the
   card's own border-radius, so the stripe curves into the top-left and
   bottom-left corners instead of stopping dead as a straight line. */
.episode-card { border-left: 4px solid var(--color-border-strong); }
.episode-card[data-sev="mild"]          { border-left-color: var(--sev-mild); }
.episode-card[data-sev="uncomfortable"] { border-left-color: var(--sev-uncomfortable); }
.episode-card[data-sev="bad"]           { border-left-color: var(--sev-bad); }
.episode-card[data-sev="severe"]        { border-left-color: var(--sev-severe); }

/* Node on the spine, coloured by severity. */
.episode-card::before {
    content: '';
    position: absolute;
    /* An absolutely positioned child is laid out against its ancestor's PADDING
       box, and this card carries a 4px severity border-left — so the offset has
       to pay that back or the node sits 4px right of the spine. It was 1px out
       and unnoticeable until the border went from 1px to 4px (§22.26). Keep the
       `- 4px` in step with `border-left-width`. */
    left: calc(-1 * var(--trail-gap) - 3.5px - 4px);
    top: 22px;
    width: 8px; height: 8px;
    border-radius: 50%;
    background: var(--color-border-strong);
    box-shadow: 0 0 0 3px var(--color-background);
}
.episode-card[data-sev="mild"]::before          { background: var(--sev-mild); }
.episode-card[data-sev="uncomfortable"]::before { background: var(--sev-uncomfortable); }
.episode-card[data-sev="bad"]::before           { background: var(--sev-bad); }
.episode-card[data-sev="severe"]::before        { background: var(--sev-severe); }

.episode-top {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--s3);
    margin-bottom: 3px;
}
.episode-top .sev-pill { margin-left: 0; flex-shrink: 0; }

/* What the entry holds, under a hairline. No onset — the tool never records
   one, and inventing a field for the layout's sake would be a lie on paper. */
.episode-foot {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s1) var(--s4);
    margin-top: var(--s3);
    padding-top: var(--s2);
    border-top: 1px solid var(--color-border);
    font-size: var(--fs-xs);
    color: var(--color-text-light);
}
.ep-meta { display: inline-flex; align-items: center; gap: 5px; }

/* ── Sidebar cards ── */
.side-card {
    background: var(--color-white);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--s4);
}
.side-title {
    font-size: var(--fs-micro);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-text-light);
    margin-bottom: var(--s3);
}
.side-rows { display: flex; flex-direction: column; gap: var(--s2); }
.side-row {
    display: flex;
    align-items: center;
    gap: var(--s2);
    font-size: var(--fs-sm);
    color: var(--color-text-medium);
}
.side-row-label { flex: 1; min-width: 0; display: inline-flex; align-items: center; gap: 6px; }
.side-row-count {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--color-primary);
}
.side-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.side-glyph { font-size: var(--fs-sm); filter: saturate(0.85); }
.side-chips { display: flex; flex-wrap: wrap; gap: 5px; }

.sev-pill {
    display: inline-flex;
    align-items: center;
    height: 24px;
    padding: 0 11px;
    border-radius: 999px;
    font-size: var(--fs-micro);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    margin-left: auto;
    white-space: nowrap;
}
.sev-pill[data-sev="mild"]          { background: #EDECF2; color: #5B5872; }
.sev-pill[data-sev="uncomfortable"] { background: #F8EBD3; color: #87601C; }
.sev-pill[data-sev="bad"]           { background: #F7E3D5; color: #8E4720; }
.sev-pill[data-sev="severe"]        { background: #F8DFDA; color: var(--color-danger-ink); }
.sev-pill[hidden] { display: none; }

.episode-symptoms {
    display: block;
    font-size: var(--fs-md);
    font-weight: 600;
    color: var(--color-primary);
    line-height: 1.4;
}

.episode-items { display: flex; flex-wrap: wrap; gap: 5px; margin-top: var(--s3); }
.ep-chip {
    display: inline-flex;
    align-items: center;
    height: 26px;
    padding: 0 10px;
    background: var(--color-background);
    border: 1px solid var(--color-border);
    border-radius: 999px;
    font-size: var(--fs-xs);
    color: var(--color-text-medium);
    white-space: nowrap;
}
.ep-more { background: none; border-color: transparent; color: var(--color-text-light); padding-left: 2px; }
.episode-none { font-size: var(--fs-xs); color: var(--color-text-light); font-style: italic; }

/* Outlined, not filled. Beside the violet "Log a reaction" a second solid
   button of the same weight read as a second primary — and logging is the
   frequent action, analysis the occasional one. The 1px border replaces
   1px of padding so both buttons keep the same height. */
.btn-analyse {
    padding: 10px var(--s4);
    background: var(--color-white);
    color: var(--color-primary);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: 600;
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s, box-shadow 0.15s;
    flex-shrink: 0;
    white-space: nowrap;
}
.btn-analyse:hover:not(:disabled) {
    border-color: var(--color-accent);
    color: var(--color-accent);
    box-shadow: var(--shadow-sm);
}
.btn-analyse:disabled {
    background: var(--color-white);
    color: var(--color-text-light);
    border-color: var(--color-border);
    cursor: not-allowed;
}
.analyse-hint {
    margin: calc(-1 * var(--s1)) 0 var(--s3);
    font-size: var(--fs-xs);
    color: var(--color-text-light);
}

/* ─────────────────────────── ENTRY VIEW ─────────────────────────── */
.back-link {
    display: inline-flex;
    align-items: center;
    gap: var(--s1);
    background: none;
    border: none;
    padding: 0;
    margin-bottom: var(--s3);
    font-family: inherit;
    font-size: var(--fs-sm);
    color: var(--color-text-light);
    cursor: pointer;
}
.back-link:hover { color: var(--color-accent); }

/* The anchor pins itself under the header once set: every band below is
   derived from it, so it must stay visible and editable while scrolling. */
.anchor-bar {
    position: sticky;
    top: var(--header-h);
    z-index: 900;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--s4);
    background: var(--color-primary);
    color: #fff;
    border-radius: var(--radius-lg);
    padding: var(--s2) var(--s3);
    margin-bottom: var(--s3);
}
.anchor-bar-main { display: flex; align-items: baseline; gap: var(--s2); min-width: 0; flex-wrap: wrap; }
.anchor-bar-label { color: #A9A3D8; }
.anchor-bar-value {
    font-size: var(--fs-md);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.anchor-bar .btn-quiet {
    background: rgba(255,255,255,0.12);
    border-color: transparent;
    color: #DAD6F0;
    flex-shrink: 0;
    padding: 4px 10px;
    font-size: var(--fs-xs);
}
.anchor-bar .btn-quiet:hover { background: rgba(255,255,255,0.22); border-color: transparent; color: #fff; }

/* ─────────────── THE STEPS ARE THE STEPPER ───────────────
   There is no separate breadcrumb. The four step numbers sit on a spine
   running down the left of the cards, and the segment of spine below a
   step turns accent once that step is done — so the progress indicator
   IS the thing you are scrolling through, and cannot scroll away from
   the state it describes.

   This is the tool's third spine, after the recall trail and the diary
   list, and it is built the same way: the list carries the line, each
   child hangs a node off it at a negative offset. Node offsets are
   written against --step-gap alone, so a mark's centre lands on the
   spine for any --rail / --step-gap pair:
       centre = (rail + gap) + (−gap − 12.5) + 13 = rail + 0.5
   which is the centre of a 1px line drawn at left: var(--rail).

   The spine is deliberately quieter than the recall trail's — the trail
   is the signature and lives inside a card; this one is scaffolding in
   the gutter. The card border keeps them from reading as one drawing. */
.step-list {
    position: relative;
    padding-left: calc(var(--rail) + var(--step-gap));
}

/* ─── Panels & steps ─── */
.panel,
.step {
    background: var(--color-white);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-xl);
    padding: var(--s5);
    margin-bottom: var(--s3);
}

/* A collapsed step is a single row; an open one holds the fields. */
.step { position: relative; padding: 0; transition: border-color 0.15s; }
.step.is-open { border-color: var(--color-border-strong); }

/* The spine segment running from this step's mark down to the next one.
   Accent once the step is done, so the line fills in as you work. It
   overshoots the card by two gutters to reach the next mark's top edge. */
.step:not(:last-child)::before {
    content: '';
    position: absolute;
    left: calc(-1 * var(--step-gap));
    top: calc(var(--s3) + 26px);
    bottom: calc(-2 * var(--s3));
    width: 1px;
    background: var(--color-border-strong);
    transition: background 0.2s;
}
.step.is-done::before { background: var(--color-accent-line); }

.step-head {
    display: flex;
    align-items: center;
    gap: var(--s3);
    width: 100%;
    padding: var(--s3) var(--s5);
    min-height: 50px;
    background: none;
    border: none;
    border-radius: var(--radius-xl);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}
.step-head:hover .step-title { color: var(--color-accent); }

/* Absolutely placed into the gutter, but still inside .step-head — so the
   number stays part of the button's hit area and toggles the step. */
.step-mark {
    position: absolute;
    left: calc(-1 * var(--step-gap) - 12.5px);
    top: var(--s3);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px; height: 26px;
    border-radius: 50%;
    background: var(--color-white);
    border: 1px solid var(--color-border-strong);
    color: var(--color-text-light);
    font-size: var(--fs-xs);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
    transition: background 0.15s, color 0.15s, border-color 0.15s, box-shadow 0.15s;
}
.step-head:hover .step-mark { border-color: var(--color-accent); }
.step.is-open .step-mark {
    background: var(--color-accent);
    border-color: var(--color-accent);
    color: #fff;
    box-shadow: 0 0 0 4px var(--color-accent-soft);
}
/* Done stays white-filled with a violet ring: the mark sits in the gutter
   over the page ground, where a soft-tint fill is indistinguishable from it,
   and a solid fill would be confused with the open step above. */
.step.is-done .step-mark {
    background: var(--color-white);
    border-color: var(--color-accent-line);
    font-size: 0;                       /* hides the number */
}
.step.is-done .step-mark::after {
    content: '✓';
    font-size: var(--fs-sm);
    font-weight: 700;
    color: var(--color-accent);
}

.step-heading {
    display: flex;
    align-items: baseline;
    gap: var(--s3);
    flex: 1;
    min-width: 0;
}
.step-title {
    font-size: var(--fs-md);
    font-weight: 600;
    color: var(--color-text-dark);
    transition: color 0.15s;
}
.step.is-open .step-title { color: var(--color-primary); }
.step-summary {
    margin-left: auto;
    font-size: var(--fs-xs);
    color: var(--color-text-light);
    text-align: right;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 48%;
}
.step-chev {
    color: var(--color-text-light);
    font-size: var(--fs-xs);
    flex-shrink: 0;
    transition: transform 0.2s;
}
.step.is-open .step-chev { transform: rotate(180deg); }

.step-body { display: none; padding: 0 var(--s5) var(--s5); }
.step.is-open .step-body { display: block; }
.step-body > .panel-sub:first-child { margin-top: 0; margin-bottom: var(--s2); }
.step-body > .field-label:first-child { margin-top: 0; }

.step-foot {
    margin-top: var(--s5);
    padding-top: var(--s4);
    border-top: 1px solid var(--color-border);
}
.panel-title {
    font-size: var(--fs-lg);
    font-weight: 600;
    color: var(--color-primary);
    letter-spacing: -0.012em;
    line-height: 1.3;
}
.panel-sub {
    margin-top: 3px;
    font-size: var(--fs-sm);
    line-height: 1.5;
    color: var(--color-text-medium);
    max-width: 64ch;
}
.panel-title + .chip-set,
.panel-sub + .chip-set { margin-top: var(--s4); }

/* ─── When ─── */
.when-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
    gap: var(--s2);
    margin-top: var(--s4);
}
.when-btn {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 1px;
    padding: var(--s3);
    background: var(--color-white);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-lg);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
}
.when-btn:hover { border-color: var(--color-accent); background: var(--color-accent-soft); }
.when-btn.selected {
    border-color: var(--color-accent);
    background: var(--color-accent-soft);
}
.when-lead { font-size: var(--fs-base); font-weight: 600; color: var(--color-text-dark); }
.when-sub { font-size: var(--fs-xs); color: var(--color-text-light); }

.when-input-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s2);
    margin-top: var(--s4);
    padding-top: var(--s4);
    border-top: 1px solid var(--color-border);
}
.when-input-row .field-label { width: 100%; margin: 0; }
/* One control in two lengths. Both fields keep the shared input styling below;
   the only difference between them is how many segments they carry, so both
   are sized to their content rather than stretched to the row. A date field
   pulled to the full 980px left its calendar icon stranded at the far edge,
   a screen away from the text it belongs to.

   Scoped by id, not class: the shared `input[type=…] { width: 100% }` block
   below has equal specificity to `.when-input-row input` and comes later in
   the file, so a class selector here loses on source order and both fields
   silently go full width again. Do not "tidy" this back to a class. */
#when-input-row input { flex: 0 0 auto; width: auto; min-width: 0; }

/* ─── Fields ─── */
.field-label {
    display: block;
    margin: var(--s5) 0 var(--s2);
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--color-text-dark);
}
.panel > .field-label:first-of-type { margin-top: 0; }
.field-hint {
    margin: -6px 0 var(--s2);
    font-size: var(--fs-xs);
    color: var(--color-text-light);
}

input[type="text"],
input[type="search"],
input[type="number"],
input[type="datetime-local"],
input[type="time"],
textarea {
    width: 100%;
    padding: 7px var(--s3);
    background: var(--color-white);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    font-family: inherit;
    font-size: var(--fs-base);
    color: var(--color-text-dark);
}
input:focus, textarea:focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 3px rgba(76,67,168,0.14);
}
textarea { resize: vertical; line-height: 1.5; }

.duration-row { display: flex; align-items: center; gap: var(--s2); }
.duration-row input[type="number"] { max-width: 110px; }
.duration-row input[type="text"] { flex: 1; }
.duration-unit { font-size: var(--fs-sm); color: var(--color-text-medium); }

.more-fields {
    margin-top: var(--s5);
    border-top: 1px solid var(--color-border);
    padding-top: var(--s3);
}
.more-fields > summary {
    font-size: var(--fs-sm);
    font-weight: 500;
    color: var(--color-accent);
    cursor: pointer;
    list-style: none;
}
.more-fields > summary::-webkit-details-marker { display: none; }
.more-fields > summary::before { content: '+ '; }
.more-fields[open] > summary::before { content: '− '; }
.more-fields-body { padding-top: var(--s1); }

/* ─── Chips ─── */
.chip-set { display: flex; flex-wrap: wrap; gap: var(--s1); }

.chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: var(--control-h);
    padding: 0 11px;
    background: var(--color-white);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    font-family: inherit;
    font-size: var(--fs-sm);
    color: var(--color-text-medium);
    white-space: nowrap;
    cursor: pointer;
    transition: border-color 0.12s, background 0.12s, color 0.12s;
}
.chip:hover { border-color: var(--color-accent); color: var(--color-accent); }
.chip.on {
    border-color: var(--color-accent);
    background: var(--color-accent);
    color: #fff;
    font-weight: 500;
}
.chip.on:hover { background: var(--color-accent-hover); border-color: var(--color-accent-hover); color: #fff; }

/* Exposure chips carry an object glyph (step 4). Foods never do — the food
   catalogue is 200+ items and a half-illustrated list reads as an accident. */
.chip-glyph { font-size: var(--fs-sm); line-height: 1; flex-shrink: 0; filter: saturate(0.9); }

.chip-custom-dot {
    width: 4px; height: 4px;
    border-radius: 50%;
    background: var(--color-text-light);
    flex-shrink: 0;
}
.chip.on .chip-custom-dot { background: rgba(255,255,255,0.8); }

/* ── Segmented choice (custom editor: one thing / a dish) ── */
.seg {
    display: flex;
    gap: 2px;
    padding: 3px;
    margin-bottom: var(--s4);
    background: var(--color-background);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}
.seg-btn {
    flex: 1;
    padding: 7px var(--s2);
    background: none;
    border: none;
    border-radius: var(--radius-sm);
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: 500;
    color: var(--color-text-medium);
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}
.seg-btn:hover { color: var(--color-text-dark); }
.seg-btn.is-on {
    background: var(--color-white);
    color: var(--color-primary);
    font-weight: 600;
    box-shadow: var(--shadow-sm);
}

/* Parts search inside the custom editor — the picker's result rows, scoped to
   a modal and height-capped so the dialog cannot run off the screen. */
#custom-part-search { margin-top: var(--s2); }
.part-results {
    max-height: 190px;
    overflow-y: auto;
    overscroll-behavior: contain;
}
.part-results:empty { display: none; }
#custom-parts:empty { display: none; }
#custom-parts { margin-bottom: var(--s2); }

/* The 20-group tag grid is a dense checklist, not a set of primary actions. */
.chip-set-tags .chip { height: 26px; padding: 0 9px; font-size: var(--fs-xs); }

/* ─────────────────── THE RECALL TRAIL — signature ───────────────────
   A fine spine that starts at the reaction and runs downward into the
   past. Every band hangs off it; day dividers cut across it.        */
/* Node offsets are written against --trail-gap alone, so a node's centre lands
   on the spine for any --rail / --trail-gap pair and cannot drift at a
   breakpoint: centre = (rail + gap) + (−gap − W/2 + 0.5) + W/2 = rail + 0.5. */
.trail {
    position: relative;
    margin-top: var(--s5);
    padding-left: calc(var(--rail) + var(--trail-gap));
}
.trail::before {
    content: '';
    position: absolute;
    left: var(--rail);
    top: 6px;
    bottom: 8px;
    width: 1px;
    background: linear-gradient(180deg, var(--color-accent) 0%, var(--color-border-strong) 45%, transparent 100%);
}

.trail-anchor {
    position: relative;
    margin-bottom: var(--s4);
}
.trail-anchor::before {
    content: '';
    position: absolute;
    left: calc(-1 * var(--trail-gap) - 4px);
    top: 4px;
    width: 9px; height: 9px;
    border-radius: 50%;
    background: var(--color-accent);
    box-shadow: 0 0 0 3px var(--color-accent-soft);
}
.trail-anchor-label {
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--color-accent);
}
.trail-anchor-time {
    display: block;
    font-size: var(--fs-xs);
    color: var(--color-text-light);
    font-variant-numeric: tabular-nums;
}

.day-divider {
    position: relative;
    margin: var(--s4) 0 var(--s2) calc(-1 * var(--trail-gap) + 5px);
    border-top: 1px solid var(--color-border);
    padding-top: 7px;
}
.day-divider span { color: var(--color-text-medium); }

.slot { position: relative; }
.slot::before {
    content: '';
    position: absolute;
    left: calc(-1 * var(--trail-gap) - 2px);
    top: 12px;
    width: 5px; height: 5px;
    border-radius: 50%;
    background: var(--color-border-strong);
    transition: background 0.15s, box-shadow 0.15s;
}

/* A band you have filled in lights up in that band's own colour, so the
   spine reads as a day walked backwards rather than a checklist. An empty
   band stays grey — nothing here may imply a band was "clear" (§2).
   The same five rules are repeated for .detail-slot further down, where
   the read-back trail is drawn; they cannot be merged here because the
   detail rules come later in the file and would win on source order. */
.slot.has-items::before                     { background: var(--band-night); box-shadow: 0 0 0 2px var(--color-white); }
.slot[data-band="morning"].has-items::before   { background: var(--band-morning); }
.slot[data-band="midday"].has-items::before    { background: var(--band-midday); }
.slot[data-band="afternoon"].has-items::before { background: var(--band-afternoon); }
.slot[data-band="evening"].has-items::before   { background: var(--band-evening); }
.slot[data-band="night"].has-items::before     { background: var(--band-night); }

/* The time-of-day glyph. It is the fastest way to find "evening" in a list
   of five near-identical rows, and it survives translation — the label
   beside it changes language, the sun does not. Desaturated a touch so a
   column of them stays quieter than the severity ramp. */
.slot-glyph,
.detail-slot-glyph {
    font-size: var(--fs-sm);
    flex-shrink: 0;
    filter: saturate(0.85);
}

.slot-head {
    display: flex;
    align-items: baseline;
    gap: var(--s2);
    flex-wrap: wrap;
    width: 100%;
    padding: 6px 0;
    background: none;
    border: none;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}
.slot-band { color: var(--color-text-medium); }
.slot.open .slot-band, .slot.has-items .slot-band { color: var(--color-primary); }
.slot-range { font-weight: 400; letter-spacing: 0.05em; }
.slot-summary {
    margin-left: auto;
    font-size: var(--fs-xs);
    color: var(--color-text-light);
    text-align: right;
    max-width: 55%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.slot.open .slot-summary { display: none; }

.slot-body {
    padding: var(--s1) 0 var(--s3);
}
.slot-items { display: flex; flex-wrap: wrap; gap: var(--s1); margin-bottom: var(--s2); }
.slot-items:empty { margin-bottom: 0; }

/* An item already placed in a slot */
.item-chip {
    display: inline-flex;
    align-items: center;
    height: var(--control-h);
    background: var(--color-accent-soft);
    border: 1px solid var(--color-accent-line);
    border-radius: var(--radius-md);
    padding: 0 2px 0 10px;
    font-size: var(--fs-sm);
    color: var(--color-primary);
}
.item-chip-label { font-weight: 500; }
.item-chip-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px; height: 22px;
    margin-left: 2px;
    background: none;
    border: none;
    border-radius: var(--radius-sm);
    font-family: inherit;
    font-size: var(--fs-sm);
    line-height: 1;
    color: var(--color-text-medium);
    cursor: pointer;
}
.item-chip-btn:hover { background: rgba(44,42,74,0.09); color: var(--color-primary); }
.item-chip.expanded .item-chip-expand { transform: rotate(180deg); }
.item-chip-expand { transition: transform 0.18s; }

.parts-box {
    flex-basis: 100%;
    margin: 2px 0 var(--s1);
    padding: var(--s3);
    background: var(--color-background);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
}
/* The head row owns the spacing below it, so .parts-label no longer does. */
.parts-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--s3);
    margin-bottom: var(--s2);
}
.parts-label {
    font-size: var(--fs-xs);
    color: var(--color-text-medium);
}
/* Quiet by design: this is a shortcut for the checklist below it, not a
   control competing with the chips. */
.parts-toggle {
    flex-shrink: 0;
    padding: 0;
    background: none;
    border: none;
    border-bottom: 1px solid transparent;
    font-family: inherit;
    font-size: var(--fs-xs);
    font-weight: 500;
    color: var(--color-accent);
    cursor: pointer;
}
.parts-toggle:hover { color: var(--color-accent-hover); border-bottom-color: currentColor; }
.parts-list { display: flex; flex-wrap: wrap; gap: var(--s1); }
.part-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 26px;
    padding: 0 9px;
    background: var(--color-white);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-sm);
    font-family: inherit;
    font-size: var(--fs-xs);
    color: var(--color-text-medium);
    white-space: nowrap;
    cursor: pointer;
}
.part-chip:hover { border-color: var(--color-accent); color: var(--color-accent); }
.part-chip.on {
    border-color: var(--color-accent);
    background: var(--color-accent);
    color: #fff;
}
.part-chip-mark { font-size: 0.625rem; opacity: 0.9; }

.btn-add-food {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: var(--control-h);
    padding: 0 11px;
    background: none;
    border: 1px dashed var(--color-border-strong);
    border-radius: var(--radius-md);
    font-family: inherit;
    font-size: var(--fs-sm);
    color: var(--color-text-light);
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s;
}
.btn-add-food:hover {
    border-color: var(--color-accent);
    border-style: solid;
    color: var(--color-accent);
}

.trail-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--s3);
    margin-top: var(--s4);
    padding-top: var(--s3);
    border-top: 1px solid var(--color-border);
}
.trail-foot-note { font-size: var(--fs-xs); color: var(--color-text-light); }
.trail-foot-actions { display: flex; gap: var(--s2); }

/* ─── Severity ─── */
.severity-row {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--s1);
    margin-top: var(--s2);
}
.sev-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    height: 34px;
    padding: 0 var(--s2);
    background: var(--color-white);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    font-family: inherit;
    font-size: var(--fs-sm);
    color: var(--color-text-medium);
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.sev-dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.sev-btn[data-sev="mild"] .sev-dot          { background: var(--sev-mild); }
.sev-btn[data-sev="uncomfortable"] .sev-dot { background: var(--sev-uncomfortable); }
.sev-btn[data-sev="bad"] .sev-dot           { background: var(--sev-bad); }
.sev-btn[data-sev="severe"] .sev-dot        { background: var(--sev-severe); }
.sev-btn:hover { border-color: var(--color-border-strong); background: var(--color-background); }
.sev-btn.on {
    border-color: var(--color-primary);
    background: var(--color-primary);
    color: #fff;
    font-weight: 500;
}

/* ─── Entry actions ───
   The row carries what is still missing, beside the button it governs — and
   nothing at all once Save is pressable. A "ready to save" line next to an
   enabled Save button is the button saying its own name twice. */
.entry-actions {
    display: flex;
    align-items: center;
    gap: var(--s3);
    margin-top: var(--s5);
    margin-bottom: var(--s6);
}
/* Keeps Discard on the right whether or not the message is present, so the
   row does not reflow the moment the last required step is filled. */
#entry-discard { margin-left: auto; }
.entry-missing {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: var(--fs-xs);
    color: var(--color-text-light);
}
.entry-missing::before {
    content: '';
    width: 6px; height: 6px;
    border-radius: 50%;
    background: var(--color-border-strong);
    flex-shrink: 0;
}
.entry-missing:empty { display: none; }
.btn-primary:disabled {
    background: #C6C2D4;
    border-color: #C6C2D4;
    cursor: not-allowed;
}

/* ─────────────────────────── BUTTONS ─────────────────────────── */
.btn-primary {
    padding: 8px var(--s4);
    background: var(--color-accent);
    color: #fff;
    border: 1px solid var(--color-accent);
    border-radius: var(--radius-md);
    font-family: inherit;
    font-size: var(--fs-base);
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
}
.btn-primary:hover { background: var(--color-accent-hover); border-color: var(--color-accent-hover); }
.btn-primary.btn-danger { background: var(--sev-severe); border-color: var(--sev-severe); }
.btn-primary.btn-danger:hover { background: var(--color-danger-ink); border-color: var(--color-danger-ink); }

.btn-quiet {
    padding: 7px var(--s3);
    background: var(--color-white);
    color: var(--color-text-medium);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: 500;
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.btn-quiet:hover { border-color: var(--color-accent); color: var(--color-accent); }
.btn-quiet.btn-danger-quiet:hover { border-color: var(--sev-severe); color: var(--sev-severe); background: var(--color-danger-light); }
.btn-sm { padding: 5px 10px; font-size: var(--fs-xs); }
.btn-block { display: block; width: 100%; margin-top: var(--s2); }

/* ─────────────────────────── ANALYSIS ───────────────────────────
   One dark hero, then a white card grid. The hero is the only inverted
   surface in the tool: it holds the three facts about the record and the
   §2 caveat, so the results below open on clean ground with nothing
   competing for the eye. */
.analysis-hero {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s5) var(--s6);
    /* Tightened once the redundant basis line went: the stat box already says
       "5 Reactions", so a sentence counting the same reactions was the third
       place that number appeared. Three lines of copy do not need 30px sides. */
    padding: var(--s5) var(--s6);
    background: var(--hero-bg);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-md);
}
.hero-copy { flex: 1 1 240px; min-width: 0; }
.hero-eyebrow {
    font-size: var(--fs-micro);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--hero-quiet);
    margin-bottom: var(--s2);
}
.hero-title {
    font-size: 1.9rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1.15;
    color: #fff;
}
.hero-caveat {
    margin-top: var(--s2);
    font-size: var(--fs-sm);
    line-height: 1.55;
    color: var(--color-accent-line);   /* 7.9:1 on --hero-bg */
    max-width: 56ch;
}
/* Below the gate there are no counts, so the sentence that describes them
   would be describing nothing. */
.analysis-hero.is-gated .hero-caveat { display: none; }

/* ── The record, as three facts ──
   Not a chart: a handful of headline numbers is a stat row. Values carry
   proportional figures, not tabular — equal-width digits read loose at this
   size — and the same sans as everything else. */
.hero-stats { display: flex; gap: var(--s2); flex: none; width: 400px; }
.hero-stats:empty { display: none; }
.stat-box {
    flex: 1;
    min-width: 0;
    padding: var(--s3) var(--s4);
    background: rgba(255,255,255,0.08);
    border: 1px solid rgba(255,255,255,0.14);
    border-radius: var(--radius-md);
}
.stat-value {
    display: block;
    font-size: 1.65rem;
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.02em;
    color: #fff;
}
.stat-label {
    display: block;
    margin-top: 5px;
    font-size: 0.7rem;
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--hero-quiet);
}

/* ── Toolbar: which list, and in what order ── */
.an-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--s3);
    margin: var(--s6) 0 var(--s3);
}
/* The segmented control is shared with the custom-item editor; here it sizes to
   its labels instead of filling the row. */
.seg-inline { display: inline-flex; margin-bottom: 0; }
.seg-inline .seg-btn { flex: 0 0 auto; padding-left: var(--s4); padding-right: var(--s4); }
.an-sort { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s2); }
.an-sort-label {
    font-size: var(--fs-micro);
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--color-text-light);
}
.chip-sm { height: 30px; padding: 0 12px; font-size: var(--fs-xs); }

/* ── Hide-by-baseline ──
   A dropdown, not a chip row. The six translated bucket labels run to ~1144px
   as chips in French against 940px of content width, so a chip row was two
   lines on desktop in FR/DE/ES and three or four on a phone. Long labels are a
   wrapping problem laid out across and a non-problem laid down a column — and
   the closed button costs no row at all, because it sits in the toolbar. */
.an-controls { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s3); }
.an-filter { position: relative; }
.an-filter-btn { gap: 7px; }
.an-filter.is-active .an-filter-btn { border-color: var(--color-accent); color: var(--color-accent); }
.an-filter-count {
    display: inline-grid;
    place-items: center;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    background: var(--color-accent);
    border-radius: 999px;
    font-size: 0.6875rem;
    font-weight: 700;
    color: #fff;
}
.an-filter-caret { font-size: 0.65rem; color: var(--color-text-light); }
.an-filter-btn[aria-expanded="true"] .an-filter-caret { transform: rotate(180deg); }

.an-filter-panel {
    position: absolute;
    z-index: 20;
    top: calc(100% + 6px);
    right: 0;
    min-width: 240px;
    max-width: min(320px, calc(100vw - var(--s6)));
    padding: var(--s3);
    background: var(--color-white);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
}
.an-filter-panel[hidden] { display: none; }
.an-filter-title {
    margin-bottom: var(--s2);
    font-size: var(--fs-micro);
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--color-text-light);
}
.an-check {
    display: flex;
    align-items: center;
    gap: var(--s2);
    padding: 7px 6px;
    border-radius: var(--radius-sm);
    font-size: var(--fs-sm);
    color: var(--color-text-dark);
    cursor: pointer;
}
.an-check:hover { background: var(--color-accent-soft); }
.an-check input { width: 16px; height: 16px; flex-shrink: 0; accent-color: var(--color-accent); cursor: pointer; }
/* The label is the long string, so it takes the slack and wraps; the count
   never does. */
.an-check-label { flex: 1; min-width: 0; line-height: 1.35; }
.an-check-count {
    flex-shrink: 0;
    font-size: var(--fs-xs);
    font-variant-numeric: tabular-nums;
    color: var(--color-text-light);
}
.an-filter-panel .link-btn { margin-top: var(--s2); font-size: var(--fs-xs); }

/* Paper only — see the note in freqFilterHtml(). */
.an-filter-print { display: none; }

/* ── Print action ──
   One per view, under the thing it prints, rather than a single kebab item that
   claimed to print the diary from whichever page you happened to be on.
   Outlined like .btn-analyse: printing is an occasional action and must not
   read as the page's primary one. */
.print-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--s2) var(--s3);
    margin-top: var(--s6);
    padding-top: var(--s4);
    border-top: 1px solid var(--color-border);
}
.btn-print {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    min-height: 40px;
    padding: 9px var(--s4);
    background: var(--color-white);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--color-primary);
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s, box-shadow 0.15s;
}
.btn-print:hover {
    border-color: var(--color-accent);
    color: var(--color-accent);
    box-shadow: var(--shadow-sm);
}
.print-hint { font-size: var(--fs-xs); color: var(--color-text-light); }

.an-note {
    margin-bottom: var(--s3);
    font-size: var(--fs-xs);
    color: var(--color-text-light);
}
.an-legend {
    display: flex;
    align-items: center;
    gap: var(--s2);
    margin-bottom: var(--s3);
    font-size: var(--fs-xs);
    line-height: 1.45;
    color: var(--color-text-light);
}
.legend-marks { display: inline-flex; gap: 3px; flex-shrink: 0; }
.legend-marks .presence-cell { width: 11px; height: 11px; }

/* ── One card per thing that reached the gate ──
   Every card is styled identically. There is deliberately no emphasis tier for
   high counts: that would be a confidence indicator (§11.3), and keyed to raw
   count it would shout loudest about whatever the user simply eats most. */
.recur-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
    gap: var(--s3);
}
.recur-card {
    background: var(--color-white);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--s3) var(--s4);
    box-shadow: var(--shadow-sm);
}
.recur-head { display: flex; align-items: center; gap: var(--s2); }
.recur-name {
    flex: 1;
    min-width: 0;
    font-size: var(--fs-sm);
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--color-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* The same count the hidden sentence beside it spells out in full — this is the
   compact form, not an extra claim. */
.recur-badge {
    flex: none;
    padding: 4px 10px;
    background: var(--color-accent-soft);
    border-radius: 999px;
    font-size: var(--fs-micro);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--color-accent);
}
.recur-marks {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 5px var(--s2);
    margin-top: var(--s3);
}
.recur-timing {
    flex: 1;
    min-width: 0;
    font-size: var(--fs-xs);
    color: var(--color-text-light);
}
.recur-note {
    display: block;
    width: 100%;
    margin-top: var(--s2);
    padding: var(--s2) 0 0;
    border: none;
    border-top: 1px solid var(--color-border);
    background: none;
    font-family: inherit;
    font-size: var(--fs-xs);
    text-align: left;
    color: #8A6B3D;                    /* 4.9:1 on white — the stated-baseline aside */
}
/* §10 lives on the card, so it is always reachable: the top prompt can be
   dismissed and a stated frequency can be wrong. Answered, it reads as the
   quiet aside it was before; unanswered, it is the question itself and takes
   the ordinary link colour so it does not masquerade as recorded data. */
.recur-baseline { cursor: pointer; }
.recur-baseline:hover { text-decoration: underline; }
.recur-baseline.is-unset { color: var(--color-text-light); }
.recur-baseline.is-unset:hover { color: var(--color-accent); }

.freq-inline {
    margin-top: var(--s2);
    padding-top: var(--s2);
    border-top: 1px solid var(--color-border);
}
.freq-inline-q {
    margin-bottom: var(--s2);
    font-size: var(--fs-xs);
    color: var(--color-text-medium);
}
/* `:not(.on)` is load-bearing. `.chip.on` and `.freq-inline .chip` are both
   (0,2,0) and this rule is the later one, so without it the selected chip lost
   its accent fill and went white — but only at rest, because `.chip.on:hover`
   is (0,3,0) and did win. Same trap in `.freq-prompt .chip` below. */
.freq-inline .chip:not(.on) { background: var(--color-white); }

/* ── Presence strip ──
   One square per recorded reaction, oldest first. Binary, so one hue plus the
   neutral rule — no ramp, because there is no magnitude here, only whether it
   was recorded. `--eps` is set inline per row and is the same for every row, so
   the columns align down the list and nothing ever scrolls out of step. */
.presence {
    display: grid;
    /* Capped, never stretched. With `1fr`, five episodes became five 90px
       blocks and the strip read as a proportional bar — that is, as a score,
       which §11.3 forbids. Capping the track keeps a cell a discrete unit: one
       square is one reaction. It still shrinks toward 2px when there are many. */
    grid-template-columns: repeat(var(--eps, 1), minmax(2px, 13px));
    gap: 2px;                       /* the surface gap, not a border */
    justify-content: start;
    max-width: 100%;
    flex: none;
}
.presence-cell {
    height: 13px;
    border-radius: 3px;
    background: var(--color-border-strong);
}
.presence-cell.is-on { background: var(--color-accent); }

.recur-advisory {
    margin-top: var(--s2);
    padding: var(--s3);
    background: var(--color-background);
    border-left: 2px solid var(--color-accent-line);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    font-size: var(--fs-xs);
    line-height: 1.5;
    color: var(--color-text-medium);
}

/* §10 — one item at a time, and only when the answer can change the ordering.
   Two columns so the chips sit beside the question rather than under it: the
   answer is one tap and should not need a scroll to reach.

   It renders into #analysis-prompt, between the hero and the toolbar. Under the
   card grid it was past the fold on every diary with more than a few rows, so
   the one question that improves the ordering was the one thing nobody saw. */
.freq-prompt {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s4);
    margin-top: var(--s5);
    padding: var(--s4) var(--s5);
    background: var(--color-accent-soft);
    border: 1px solid var(--color-accent-line);
    border-left: 3px solid var(--color-accent);
    border-radius: var(--radius-lg);
}
/* padding-right keeps the copy clear of the × pinned in the corner. */
.freq-copy { flex: 1 1 220px; min-width: 0; padding-right: var(--s5); }
.freq-eyebrow {
    font-size: var(--fs-micro);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-accent);
    margin-bottom: 5px;
}
.freq-question { font-size: var(--fs-sm); line-height: 1.55; color: var(--color-primary); }
.freq-why { margin-top: 5px; font-size: var(--fs-xs); color: var(--color-text-light); }
.freq-options { display: flex; flex-wrap: wrap; gap: 5px; align-items: flex-start; }
.freq-prompt .chip:not(.on) { background: var(--color-white); }
/* Pinned to the corner rather than sitting in the chip row: among five
   frequency answers, a sixth button reads as a sixth answer. */
.freq-close {
    position: absolute;
    top: 6px;
    right: 8px;
    margin-left: 0;
    font-size: 1.25rem;
    min-width: 28px;
    min-height: 28px;
}

.gate-note {
    padding: var(--s4);
    background: var(--color-background);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    font-size: var(--fs-sm);
    color: var(--color-text-medium);
}
.empty-note {
    padding: var(--s6) 0;
    font-size: var(--fs-sm);
    color: var(--color-text-light);
    text-align: center;
}
.link-btn {
    display: inline-block;
    margin-top: var(--s2);
    padding: 2px 0;
    background: none;
    border: none;
    border-bottom: 1px solid currentColor;
    font-family: inherit;
    font-size: var(--fs-sm);
    color: var(--color-accent);
    cursor: pointer;
}
.link-btn:hover { color: var(--color-accent-hover); }

/* ─────────────────────── ACTIONS MENU ───────────────────────
   Position, size, height cap, scrolling and the open/close transition all come
   from /shared/tsk-menu.css — the one platform implementation. Only this tool's
   look lives below. Do not re-declare .menu-overlay/.menu-content geometry here.
   ──────────────────────────────────────────────────────────── */
:root {
    --tsk-menu-align: 980px;   /* .header-inner max-width */
    --tsk-menu-z: 1400;        /* this tool's modals sit at 1500 */
    --tsk-menu-scrim: rgba(28,26,45,0.50);
}


.menu-header {
    flex-shrink: 0;
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 0.85rem;
    gap: 8px;
}
.menu-header h3 { margin: 0; color: var(--color-text-dark); font-size: 1.1rem; }

.menu-header-right {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}

.close-menu {
    background: var(--chrome-bg);
    border: 1px solid var(--chrome-border);
    border-radius: var(--chrome-radius);
    font-size: 1.25rem;
    color: var(--chrome-text);
    cursor: pointer;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: inherit;
    line-height: 1;
}
.close-menu:hover { background: var(--color-danger-light); color: var(--color-error); border-color: #E0A79C; }

.menu-action {
    width: 100%;
    background: var(--color-background);
    border: 1px solid var(--color-border);
    padding: 11px 14px;
    border-radius: 12px;
    margin-bottom: 8px;
    cursor: pointer;
    transition: all 0.2s;
    display: flex;
    align-items: center;
    gap: 12px;
    font-size: 0.95rem;
    color: var(--color-text-dark);
    font-weight: 500;
    text-align: left;
    font-family: inherit;
}
.menu-action:hover {
    background: var(--color-white);
    border-color: var(--color-accent);
    transform: translateY(-1px);
    box-shadow: var(--shadow-sm);
}
.menu-action.danger { color: var(--color-error); border-color: #E0A79C; }
.menu-action.danger:hover { background: var(--color-danger-light); border-color: var(--color-error); }

.action-icon { font-size: 1.35rem; flex-shrink: 0; }
.action-content { display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0; }
.action-hint { font-size: var(--fs-micro); color: var(--color-text-light); font-weight: 400; font-style: italic; }

.menu-divider {
    height: 1px;
    background: var(--color-border);
    margin: 2px 0 10px;
}

/* ─────────────────────── MODALS ─────────────────────── */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(28,26,45,0.44);
    z-index: 1500;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 88px var(--s4) var(--s6);
    overflow-y: auto;
}
.modal {
    width: 100%;
    max-width: 440px;
    background: var(--color-white);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-lg);
    padding: var(--s5);
    animation: modalIn 0.16s ease;
}
.modal-wide { max-width: 580px; }
@keyframes modalIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* A height-capped modal: head and actions are pinned, only the body scrolls.
   Without this a long recall trail pushed the buttons off the bottom. */
.modal-tall {
    display: flex;
    flex-direction: column;
    max-height: calc(100dvh - 112px);
    padding: 0;
}
.modal-tall .modal-head,
.modal-tall .tabs,
.modal-tall .modal-actions { flex-shrink: 0; }
.modal-tall .modal-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--s4) var(--s5);
}
.modal-tall .modal-actions {
    margin: 0;
    padding: var(--s3) var(--s5);
    border-top: 1px solid var(--color-border);
    background: var(--color-background);
    border-radius: 0 0 var(--radius-xl) var(--radius-xl);
}

.modal-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--s3);
    padding: var(--s5) var(--s5) var(--s3);
}
.modal-head-text { min-width: 0; }
.modal-eyebrow {
    font-size: var(--fs-micro);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-text-light);
    margin-bottom: 2px;
}
.modal-head .modal-title { margin-bottom: 0; }
.modal-head .sev-pill { margin-left: 0; flex-shrink: 0; }

/* ─── Tabs ─── */
.tabs {
    display: flex;
    gap: var(--s1);
    padding: 0 var(--s5);
    border-bottom: 1px solid var(--color-border);
}
.tab {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: var(--s2) var(--s3);
    margin-bottom: -1px;
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--color-text-light);
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s;
}
.tab:hover { color: var(--color-text-medium); }
.tab.is-on { color: var(--color-accent-hover); border-bottom-color: var(--color-accent); }
.tab-count {
    min-width: 20px;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--color-border);
    color: var(--color-text-medium);
    font-size: var(--fs-micro);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    text-align: center;
}
.tab-count[hidden] { display: none; }
.tab.is-on .tab-count { background: var(--color-accent-soft); color: var(--color-accent-hover); }

.modal-title {
    font-size: var(--fs-lg);
    font-weight: 600;
    color: var(--color-primary);
    letter-spacing: -0.012em;
    margin-bottom: var(--s3);
}
.modal p { font-size: var(--fs-sm); line-height: 1.55; color: var(--color-text-medium); margin-bottom: var(--s3); }
.modal-sub { font-size: var(--fs-sm); color: var(--color-text-medium); margin-bottom: var(--s4); }

.modal-consent p { font-size: var(--fs-base); }
.consent-emergency {
    padding: var(--s3);
    background: var(--color-danger-light);
    border-left: 2px solid var(--sev-severe);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    color: var(--color-danger-ink) !important;
}

.modal-actions {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: var(--s2);
    margin-top: var(--s5);
}
.modal-actions-stack { flex-direction: column-reverse; align-items: stretch; }
.modal-actions-stack > * { width: 100%; }
.modal-actions-spread { justify-content: space-between; }
.modal-actions-right { display: flex; gap: var(--s2); flex-wrap: wrap; justify-content: flex-end; }

.confirm-detail:empty { display: none; }
.confirm-detail {
    margin-top: var(--s2);
    padding: var(--s3);
    background: var(--color-background);
    border-radius: var(--radius-lg);
    font-size: var(--fs-xs);
    line-height: 1.5;
    color: var(--color-text-medium);
}

/* ─── Library ─── */
.library-list { max-height: 46vh; overflow-y: auto; }
.library-row {
    display: flex;
    align-items: center;
    gap: var(--s3);
    padding: var(--s2) 0;
    border-bottom: 1px solid var(--color-border);
}
.library-main { flex: 1; min-width: 0; }
.library-name { display: block; font-size: var(--fs-base); font-weight: 500; color: var(--color-text-dark); }
.library-tags { display: block; font-size: var(--fs-xs); color: var(--color-text-light); }
.library-actions { display: flex; gap: var(--s1); flex-shrink: 0; }

/* ─── Episode detail ───
   The "before" tab is the recall trail again, at rest: the same spine, the
   same band headings, the same chips — so reading an old entry looks like
   the screen you filled it in on.                                        */
.detail-block { margin-bottom: var(--s5); }
.detail-block:last-child { margin-bottom: 0; }
.detail-label { margin-bottom: var(--s2); }
.detail-value { font-size: var(--fs-base); color: var(--color-text-dark); }

.detail-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.detail-chip {
    display: inline-flex;
    align-items: center;
    height: 28px;
    padding: 0 11px;
    background: var(--color-accent-soft);
    border: 1px solid var(--color-accent-line);
    border-radius: 999px;
    font-size: var(--fs-sm);
    color: var(--color-accent-hover);
    white-space: nowrap;
}
.detail-chip.is-muted {
    background: var(--color-background);
    border-color: var(--color-border);
    color: var(--color-text-light);
}

/* Severity / where / how long — small, aligned, scannable. */
.detail-facts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: var(--s3);
    padding: var(--s3) var(--s4);
    margin-bottom: var(--s5);
    background: var(--color-background);
    border-radius: var(--radius-lg);
}
.detail-fact { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.detail-fact .detail-label { margin-bottom: 0; }
.detail-fact .detail-value { font-size: var(--fs-sm); font-weight: 600; }

.detail-note {
    padding: var(--s3);
    background: var(--color-background);
    border-left: 3px solid var(--color-accent-line);
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
    font-size: var(--fs-sm);
    line-height: 1.6;
    color: var(--color-text-medium);
    white-space: pre-wrap;
}

.detail-trail {
    position: relative;
    padding-left: calc(var(--rail) + var(--trail-gap));
}
.detail-trail::before {
    content: '';
    position: absolute;
    left: var(--rail);
    top: 8px;
    bottom: 12px;
    width: 1px;
    background: var(--color-border-strong);
}
.detail-day {
    margin: var(--s4) 0 var(--s2) calc(-1 * var(--trail-gap) + 4px);
    font-size: var(--fs-micro);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-text-medium);
    background: var(--color-white);
}
.detail-day:first-child { margin-top: 0; }

.detail-slot {
    position: relative;
    padding: var(--s2) 0 var(--s3);
}
/* Same day-band nodes as the entry trail (see THE RECALL TRAIL above), so
   reading an old entry looks like the screen you filled it in on. */
.detail-slot::before {
    content: '';
    position: absolute;
    left: calc(-1 * var(--trail-gap) - 2.5px);
    top: 13px;
    width: 6px; height: 6px;
    border-radius: 50%;
    background: var(--band-night);
    box-shadow: 0 0 0 3px var(--color-white);
}
.detail-slot[data-band="morning"]::before   { background: var(--band-morning); }
.detail-slot[data-band="midday"]::before    { background: var(--band-midday); }
.detail-slot[data-band="afternoon"]::before { background: var(--band-afternoon); }
.detail-slot[data-band="evening"]::before   { background: var(--band-evening); }
.detail-slot[data-band="night"]::before     { background: var(--band-night); }
.detail-slot.is-empty::before { background: var(--color-border-strong); }
.detail-slot-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--s2);
    margin-bottom: var(--s2);
    color: var(--color-text-medium);
}
.detail-slot-head > span:first-child {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}
.detail-slot-empty { font-size: var(--fs-xs); color: var(--color-text-light); font-style: italic; }
.detail-block .detail-slot-empty { margin-top: var(--s2); }

/* ─────────────────────── PICKER SHEET / DIALOG ───────────────────────
   Two shapes for one component. Below 601px it is a bottom sheet: thumb
   reach matters, and it rises from the edge the keyboard will come from.
   From 601px up it becomes a centred dialog — a panel welded to the
   bottom of a wide screen reads as a mobile app in a browser window, and
   the grab handle promises a drag gesture a mouse cannot perform. The
   desktop variant lives in the RESPONSIVE section at the foot of the
   file, with the other breakpoints.                                    */
.sheet-overlay {
    position: fixed;
    inset: 0;
    background: rgba(28,26,45,0.40);
    z-index: 1600;
    display: flex;
    align-items: flex-end;
    justify-content: center;
}
.sheet {
    width: 100%;
    max-width: 560px;
    max-height: 84vh;
    display: flex;
    flex-direction: column;
    background: var(--color-white);
    border-radius: var(--radius-xl) var(--radius-xl) 0 0;
    box-shadow: 0 -6px 28px rgba(28,26,45,0.20);
    animation: sheetIn 0.2s cubic-bezier(0.2, 0.8, 0.3, 1);
}
@keyframes sheetIn { from { transform: translateY(100%); } to { transform: none; } }
/* Focus lands here on touch instead of the search field (see focusToOpen), so
   it must not draw a ring — it is a reading-order target, not an affordance. */
.sheet:focus { outline: none; }

.sheet-grab {
    width: 32px; height: 3px;
    margin: var(--s2) auto 0;
    border-radius: 2px;
    background: var(--color-border-strong);
}
.sheet-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--s4);
    padding: var(--s2) var(--s5) var(--s3);
}
.sheet-title { font-size: var(--fs-lg); font-weight: 600; color: var(--color-primary); letter-spacing: -0.012em; }
.sheet-eyebrow { margin-bottom: 2px; color: var(--color-accent); }
.sheet-close {
    background: none; border: none;
    font-size: 1.4rem; line-height: 1;
    color: var(--color-text-light);
    cursor: pointer;
    width: 32px; height: 32px;
    flex-shrink: 0;
    margin: -4px -6px 0 0;
}
.sheet-close:hover { color: var(--color-text-dark); }

.sheet-search {
    padding: 0 var(--s5) var(--s3);
    border-bottom: 1px solid var(--color-border);
}
.sheet-body {
    flex: 1;
    overflow-y: auto;
    padding: var(--s4) var(--s5) var(--s5);
    -webkit-overflow-scrolling: touch;
}
.sheet-section-label { margin-bottom: var(--s2); }

.picker-results:empty { display: none; }

.result-row {
    display: flex;
    align-items: center;
    gap: var(--s3);
    width: 100%;
    padding: var(--s2) var(--s1);
    background: none;
    border: none;
    border-bottom: 1px solid var(--color-border);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}
.result-row:hover { background: var(--color-accent-soft); }
.result-main { flex: 1; min-width: 0; }
.result-name {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: var(--fs-base);
    font-weight: 500;
    color: var(--color-text-dark);
}
.result-tags {
    display: block;
    margin-top: 1px;
    font-size: var(--fs-xs);
    color: var(--color-text-light);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.result-composite-mark { color: var(--color-accent); }
.result-add {
    flex-shrink: 0;
    font-size: var(--fs-md);
    color: var(--color-text-light);
    line-height: 1;
}
.result-row:hover .result-add { color: var(--color-accent); }
/* §8.1 — this row is an action, not another suggestion. A dashed grey outline
   was the only thing separating it from the foods above it: same ink, same
   weight, same trailing +, so in a long result list it scanned as a food
   literally called Add "…" as a new food. It now carries the accent — tinted
   ground, accent rule, accent ink, and a filled + badge — none of which any
   result row uses, so the difference survives a glance. */
.result-row-new {
    border-bottom: none;
    margin-top: var(--s3);
    border: 1px solid var(--color-accent-line);
    border-radius: var(--radius-lg);
    padding: var(--s3);
    background: var(--color-accent-soft);
}
.result-row-new:hover {
    background: #E5E2F6;
    border-color: var(--color-accent);
}
.result-row-new .result-name { color: var(--color-accent); font-weight: 600; }
.result-row-new .result-tags { color: var(--color-text-medium); }
.result-row-new .result-add,
.result-row-new:hover .result-add {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px; height: 24px;
    border-radius: 50%;
    background: var(--color-accent);
    color: var(--color-white);
    font-size: var(--fs-sm);
}
.result-empty { padding: var(--s5) var(--s1); font-size: var(--fs-sm); color: var(--color-text-light); }

/* ─────────────────────────── TOAST ─────────────────────────── */
.toast {
    position: fixed;
    left: 50%;
    bottom: 20px;
    transform: translate(-50%, 16px);
    max-width: min(400px, 90vw);
    padding: var(--s2) var(--s4);
    background: var(--color-text-dark);
    color: #fff;
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    font-size: var(--fs-sm);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s, transform 0.2s;
    z-index: 1800;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
.toast.error { background: var(--sev-severe); }

/* ─────────────────────── ABOUT SECTION (SEO) ───────────────────────
   Help content, not headline content. It is deliberately quieter than
   the tool above it — one step down in size and in colour, so it never
   competes with the diary for attention.                            */
.about-section {
    background: var(--color-white);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    margin: var(--s5) 0;
    overflow: hidden;
}
.about-toggle {
    display: flex;
    align-items: center;
    gap: var(--s3);
    width: 100%;
    padding: var(--s3) var(--s4);
    background: none;
    border: none;
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: 500;
    color: var(--color-text-medium);
    text-align: left;
    cursor: pointer;
}
.about-toggle:hover { background: var(--color-background); color: var(--color-text-dark); }
.about-icon { font-size: var(--fs-sm); }
.about-title { flex: 1; }
.toggle-icon { color: var(--color-text-light); font-size: var(--fs-xs); transition: transform 0.2s; }
.about-toggle[aria-expanded="true"] .toggle-icon { transform: rotate(180deg); }

.about-content { padding: 0 var(--s5) var(--s5); border-top: 1px solid var(--color-border); }
.about-content h2 {
    font-size: var(--fs-lg);
    font-weight: 600;
    color: var(--color-primary);
    margin: var(--s5) 0 var(--s3);
}
.about-content h3 {
    font-size: var(--fs-md);
    font-weight: 600;
    color: var(--color-primary);
    margin: var(--s5) 0 var(--s2);
}
.about-content p { font-size: var(--fs-sm); line-height: 1.55; color: var(--color-text-medium); margin-bottom: var(--s2); }
.about-content ul, .about-content ol { margin: 0 0 var(--s3) var(--s4); }
.about-content li { font-size: var(--fs-sm); line-height: 1.55; color: var(--color-text-medium); margin-bottom: 5px; }
.about-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); gap: var(--s5); }
.how-to-steps li { margin-bottom: var(--s2); }
.how-to-steps p { margin: 2px 0 0; }
.features-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--s3); }
.feature-item {
    padding: var(--s3);
    background: var(--color-background);
    border-radius: var(--radius-lg);
}
.feature-item strong { display: block; font-size: var(--fs-sm); color: var(--color-primary); margin-bottom: 2px; }
.feature-item p { font-size: var(--fs-xs); margin: 0; }
.keywords-section { margin-top: var(--s5); color: var(--color-text-light); }
.keywords-section p { font-size: var(--fs-xs); }

/* ─────────────────────────── FOOTER ─────────────────────────── */
.app-footer {
    padding: var(--s4) 0 var(--s8);
    text-align: center;
    font-size: var(--fs-xs);
    color: var(--color-text-light);
}
.app-footer p { margin-bottom: 3px; }
.footer-link {
    color: var(--color-text-medium);
    text-decoration: none;
    border-bottom: 1px solid transparent;
}
.footer-link:hover { color: var(--color-accent); border-bottom-color: var(--color-accent); }
.footer-separator { margin: 0 var(--s2); color: var(--color-border-strong); }
.version-badge {
    background: none;
    border: none;
    padding: 0;
    font-family: inherit;
    font-size: var(--fs-xs);
    color: var(--color-text-medium);
    cursor: pointer;
    border-bottom: 1px solid transparent;
}
.version-badge:hover { color: var(--color-accent); border-bottom-color: var(--color-accent); }

/* ─────────────────────────── RESPONSIVE ───────────────────────────
   Note the one min-width block below: the food picker is a bottom sheet
   on phones and a centred dialog everywhere else.                     */

/* ─── Desktop: the picker is a dialog, not a sheet ─── */
@media (min-width: 601px) {
    .sheet-overlay {
        align-items: center;
        padding: var(--s6);
    }
    .sheet {
        max-height: min(660px, calc(100dvh - 96px));
        border-radius: var(--radius-xl);
        box-shadow: var(--shadow-lg);
        animation: modalIn 0.16s ease;
    }
    /* A drag affordance a mouse can never use. */
    .sheet-grab { display: none; }
    .sheet-head { padding-top: var(--s5); }

    /* Rows are pointer targets here, so the hover tint gets room to breathe.
       No corner radius — the dividers make it a list, and rounded corners
       fight a border-bottom. */
    .result-row { padding: var(--s2) var(--s3); }
}

/* ─── Phones: the step marks come back inside the cards ───
   The spine gutter costs ~45px, and step 3 already carries the recall
   trail's own spine inside it. Two nested spines on a 375px screen is
   both cramped and visually noisy, so below 601px the marks return to
   the head row and the progress line is dropped. Each mark still shows
   its number, its tick and its open state — only the connector goes. */
@media (max-width: 600px) {
    /* No side rail on a phone. The longest label is `Aujourd'hui` at eleven
       characters — `Donnerstag`, `Wednesday` and `Miércoles` are not far behind
       — and a column wide enough for them would take a third of a 390px screen
       from the card. The rail becomes one line above the card instead, indented
       to the card's own left edge so the spine still runs behind it. */
    .episode-row { display: block; }
    .episode-rail {
        flex-direction: row;
        align-items: baseline;
        justify-content: flex-start;
        gap: var(--s2);
        padding: var(--s4) 0 var(--s1) calc(var(--rail) + var(--trail-gap));
        text-align: left;
    }
    .episode-list::before { left: var(--rail); }

    .step-list { padding-left: 0; }
    .step-mark { position: static; width: 24px; height: 24px; }
    .step.is-open .step-mark { box-shadow: none; }
    .step:not(:last-child)::before { display: none; }
}

@media (max-width: 768px) {
    .header-inner { padding: 0.5rem 1rem; }
    .logo-image { height: 34px; }
    .container { padding: var(--s4) var(--s4) 0; }

    .diary-lead { flex-direction: column; align-items: stretch; gap: var(--s3); }
    .btn-log { justify-content: center; width: 100%; height: 44px; }
    .lead-title { font-size: 1.375rem; }
    .panel { padding: var(--s4); }
    .welcome { padding: var(--s5); }
    .step-head { padding: var(--s3) var(--s4); }
    .step-body { padding: 0 var(--s4) var(--s4); }

    /* The hero stacks: copy first, then the three boxes across the full width.
       `flex: none; width: 400px` would otherwise hold a 400px column on a
       375px screen and push the page sideways. */
    .analysis-hero { gap: var(--s5); padding: var(--s5); }
    .hero-title { font-size: 1.45rem; }
    .hero-stats { flex: 1 1 100%; width: auto; }
    .an-toolbar { gap: var(--s2); position: relative; }
    .seg-inline { width: 100%; }
    /* Three segments, not two, since exposures got their own list. `flex: 1 1 0`
       gave every button an identical third of ~343px, which is not enough for
       "Exposiciones · 3" while "Grupos · 5" sits on spare room it cannot give
       back. Sizing from content and sharing the slack keeps the longest
       translated label on one line in all four languages. */
    .seg-inline .seg-btn {
        flex: 1 1 auto;
        min-width: 0;
        padding-left: var(--s2);
        padding-right: var(--s2);
        font-size: var(--fs-xs);
    }
    /* The segmented control takes the whole first row here, so `.an-controls`
       drops to its own row and the Hide button becomes the leftmost thing on
       the page rather than the rightmost. A panel anchored `right: 0` then
       reaches its 240px minimum leftwards from a button that starts one
       container padding in — off the left edge of the screen. Anchor it to the
       toolbar instead of to the button: it drops the full content width, below
       the whole toolbar, so it cannot be clipped on either side whatever the
       button ends up next to or how long the translated labels run. */
    .an-filter { position: static; }
    .an-filter-panel {
        top: calc(100% + 6px);
        left: 0;
        right: 0;
        min-width: 0;
        max-width: none;
    }
    /* One column below the grid's 268px track — auto-fill already does this,
       but the explicit rule keeps long names from forcing a second track. */
    .recur-grid { grid-template-columns: minmax(0, 1fr); }

    /* German runs to "Meine Aufzeichnungen auswerten" — 29 characters. With
       `white-space: nowrap` on .btn-analyse and `flex-shrink: 0` on .btn-log
       that forced the row wider than the screen and put a horizontal scrollbar
       on the whole page. Both buttons wrap and shrink here; 44px becomes a
       floor rather than a fixed height. */
    .lead-actions { width: 100%; }
    .lead-actions > * {
        flex: 1 1 0;
        min-width: 0;
        height: auto;
        min-height: 44px;
        justify-content: center;
        text-align: center;
    }
    .btn-analyse, .btn-log { white-space: normal; flex-shrink: 1; }
}

@media (max-width: 480px) {
    :root { --rail: 12px; --trail-gap: 14px; --header-h: 53px; }
    .header-inner { padding: 0.4rem 0.75rem; }
    .logo-image { height: 30px; }
    .tool-name-btn { font-size: 1.25rem; }
    .header-icon-btn svg { width: 18px; height: 18px; }

    .container { padding: var(--s3) var(--s3) 0; }
    .panel { padding: var(--s4) var(--s3); }
    .welcome { padding: var(--s4) var(--s3); }
    .how-strip { gap: var(--s4); margin: var(--s5) 0; }
    .step-head { padding: var(--s3); gap: var(--s2); }
    .step-body { padding: 0 var(--s3) var(--s4); }
    .step-heading { flex-wrap: wrap; gap: 0 var(--s2); }
    .step-summary { max-width: 100%; margin-left: 0; text-align: left; flex-basis: 100%; }
    .entry-actions { flex-wrap: wrap; }
    .entry-missing { order: 3; flex-basis: 100%; }

    .severity-row { grid-template-columns: repeat(2, 1fr); }
    .when-grid { grid-template-columns: 1fr 1fr; }
    .slot-summary { max-width: 100%; margin-left: 0; flex-basis: 100%; text-align: left; }

    .modal-overlay { padding: 68px var(--s3) var(--s5); }
    .modal { padding: var(--s4); }
    .modal-tall { padding: 0; max-height: calc(100dvh - 88px); }
    .modal-tall .modal-body { padding: var(--s3) var(--s4); }
    .modal-tall .modal-actions { padding: var(--s3) var(--s4); }
    .modal-head { padding: var(--s4) var(--s4) var(--s2); }
    .tabs { padding: 0 var(--s4); }
    .modal-actions { flex-direction: column-reverse; align-items: stretch; }
    .modal-actions > * { width: 100%; }
    .modal-actions-spread { flex-direction: column-reverse; }
    .modal-actions-right { flex-direction: column-reverse; }
    .modal-actions-right > * { width: 100%; }
    .modal-actions .btn-primary,
    .modal-actions .btn-quiet { height: 40px; }

    .sheet-head, .sheet-search { padding-left: var(--s4); padding-right: var(--s4); }
    .sheet-body { padding-left: var(--s4); padding-right: var(--s4); }

    .entry-actions { flex-direction: column-reverse; align-items: stretch; }
    .entry-actions > * { width: 100%; height: 40px; }

    .trail-foot { flex-direction: column; align-items: flex-start; }
    .trail-foot-actions { width: 100%; }
    .trail-foot-actions > * { flex: 1; height: 36px; }

    .analysis-hero { padding: var(--s4); }
    .stat-box { padding: var(--s3) var(--s2); }
    .stat-value { font-size: 1.4rem; }
    .stat-label { font-size: 0.65rem; letter-spacing: 0.03em; }
    .freq-prompt { padding: var(--s4); }
    .about-content { padding: 0 var(--s4) var(--s4); }
}

/* Touch devices get full-size hit areas regardless of viewport width. */
@media (hover: none) and (pointer: coarse) {
    :root { --control-h: 38px; }
    .item-chip-btn { width: 28px; height: 28px; }
    .part-chip { height: 34px; }
}

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

/* ─────────────────────────── PRINT ───────────────────────────
   The diary must be readable on paper — people take this to an
   appointment. Print the episode list, nothing else.          */
@media print {
    body { background: #fff; font-size: 10pt; }

    /* Where this page came from. The browser's own header prints the URL only
       when the user has that option switched on, and it is off by default in
       Chrome's "Headers and footers" — so the page has to carry it itself. */
    .print-masthead {
        display: flex !important;
        align-items: center;
        gap: 7pt;
        margin-bottom: 8pt;
        padding-bottom: 4pt;
        border-bottom: 1px solid #999;
    }
    /* An <img>, not a CSS background: Chrome's "Background graphics" print
       option is off by default and would silently drop a background. Height
       only, width auto — the platform logo rule, and the source is 107×60. */
    .print-masthead-logo { height: 8mm; width: auto; }
    .print-masthead-name { font-size: 11pt; font-weight: 700; color: #000; }
    /* Underlined and inked in the brand indigo: a PDF is read on a screen as
       often as on paper, and there it has to look like the link it is. The
       indigo still reads as near-black in greyscale. */
    /* Pushed right by `margin-left: auto` rather than `space-between` on the
       parent, which with three children would have spread the logo and the
       tool name apart instead of keeping them as one lockup. */
    .print-masthead-url {
        margin-left: auto;
        font-size: 8.5pt;
        color: #2F2C68;
        text-decoration: underline;
    }
    .header, .info-banner, .about-section, .app-footer,
    .diary-lead .lead-actions, .analyse-hint, .emergency-note,
    .menu-overlay, .modal-overlay, .sheet-overlay, .toast,
    .episode-items, .diary-side, .diary-filters, .episode-foot,
    .print-row, #tsk-feedback-button { display: none !important; }

    /* The rail is a screen device — on paper the date belongs in the entry, and
       .print-detail already opens with it. */
    .diary-grid { display: block !important; }
    .episode-row { display: block !important; }
    .episode-rail { display: none !important; }
    .episode-card { margin-left: 0 !important; }

    /* The spine and its nodes are screen furniture — paper wants a plain list. */
    .episode-list { padding-left: 0; }
    .episode-list::before,
    .episode-card::before { display: none; }
    .sev-pill { border: 1px solid #999; background: none !important; color: #333 !important; }

    .container { max-width: none; padding: 0; }
    .diary-lead { border-bottom: 2px solid #333; padding-bottom: 8pt; }
    .lead-title { font-size: 14pt; }

    .episode-card {
        break-inside: avoid;
        border: none;
        border-bottom: 1px solid #ccc;
        border-radius: 0;
        padding: 6pt 0;
        margin: 0;
    }
    .print-detail { display: block !important; margin-top: 3pt; font-size: 9pt; color: #333; }
    /* The date is a heading for the rows under it, not the first word of them. */
    .print-when { display: block; margin-bottom: 1.5pt; font-weight: 600; color: #000; }
    /* Hanging indent: a band with a long item list wraps under its own text
       rather than back under the clock range, so the ranges stay a column. */
    .print-slot { display: block; padding-left: 10pt; text-indent: -10pt; line-height: 1.4; }

    /* The analysis page is a second thing people take to an appointment. The
       hero is an inverted screen surface — on paper it is a full-bleed ink
       block, so it prints as plain text. */
    .analysis-hero {
        background: none !important;
        box-shadow: none;
        padding: 0 0 6pt;
        border-bottom: 2px solid #333;
        border-radius: 0;
        gap: 8pt;
    }
    .hero-title, .stat-value { color: #000 !important; }
    .hero-eyebrow, .hero-caveat, .stat-label { color: #333 !important; }
    .hero-title { font-size: 14pt; }
    .stat-box { background: none !important; border: 1px solid #999; }
    #analysis-prompt, .back-link, .an-legend { display: none !important; }

    /* The toolbar cannot be hidden wholesale: the Hide control lives inside it,
       and while the *control* is screen furniture, the fact that the list is
       filtered is not. The page shows fewer foods than the record holds, and
       paper that does not say so is the unsafe version of this feature (§12).
       So the toolbar stays in flow and only its screen parts go. */
    .an-toolbar { display: block; margin: 0; }
    .an-toolbar .seg,
    .an-sort,
    .an-filter-btn,
    .an-filter-panel,
    .an-filter:not(.is-active) { display: none !important; }
    .an-filter { position: static; }
    .an-filter-print {
        display: block !important;
        margin-bottom: 6pt;
        font-size: 9pt;
        font-style: italic;
        color: #333;
    }
    .recur-grid { display: block; }
    .recur-card { break-inside: avoid; border: none; border-bottom: 1px solid #ccc; border-radius: 0; box-shadow: none; padding: 5pt 0; }

    /* An unanswered baseline is a question the tool is asking, not something
       the user recorded — on paper it is a prompt with no way to respond, and
       it reads as a gap in the record rather than as a control. Only the
       answered state carries data, so only it prints. `.freq-inline` is the
       same control mid-edit. */
    .recur-baseline.is-unset,
    .freq-inline { display: none !important; }
    /* Answered, it is a plain line of text — the hairline above it was there to
       separate a tappable control from the card body. */
    .recur-baseline { border-top: none; padding-top: 2pt; color: #333 !important; }
}

.print-detail { display: none; }
.print-masthead { display: none; }
