/* Shopping Mode. Designed at 375x667, verified at 320 and 390.
 *
 * Vertical budget at 375x667: 72px header + ~475px list + 64px quick-add + 56px
 * tab area. That yields 9-10 visible rows. A Material list row at 56-72px would
 * give 6-7 — and beating a paper list on density is the entire point.
 */

/* --- header --------------------------------------------------------------- */

.hdr {
    position: sticky; top: 0; z-index: 20;
    background: var(--panel);
    border-bottom: 1px solid var(--border);
    padding: calc(env(safe-area-inset-top) + var(--s2)) var(--s3) var(--s2);
}
.hdr-r1 { display: flex; align-items: center; gap: var(--s2); }
.hdr-title {
    flex: 1 1 auto; min-width: 0; margin: 0;
    font-size: var(--t-xl); font-weight: 600;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hdr-r2 { margin: 2px 0 0; font-size: var(--t-sm); color: var(--muted); }
.hdr-r2 strong { color: var(--text); font-weight: 600; }

/* min-width fixed so the header does not resize as the state changes */
.sync-chip {
    flex: 0 0 auto; min-width: 84px; height: 28px;
    display: inline-flex; align-items: center; justify-content: center; gap: 4px;
    padding: 0 var(--s2);
    font-family: inherit; font-size: var(--t-xs); font-weight: 600; line-height: 1;
    border: 1px solid var(--border); border-radius: var(--r-pill);
    background: var(--panel-2); color: var(--muted);
}
.sync-chip[data-state="synced"]  { color: var(--green); }
.sync-chip[data-state="pending"] { color: var(--orange); }
.sync-chip[data-state="error"]   { color: var(--red); }

/* --- list ----------------------------------------------------------------- */

.list {
    /* Clears the fixed quick-add bar plus the safe area, so the last row is
     * always reachable. */
    padding-bottom: calc(64px + env(safe-area-inset-bottom) + var(--s4));
}
.rows { list-style: none; margin: 0; padding: 0; }

.row {
    display: grid; grid-template-columns: 1fr; min-height: 48px;
    border-bottom: 1px solid var(--border);
    /* Cheap scrolling at 200+ items with no virtualization, and — because the
     * intrinsic size is declared — no geometry change when a row scrolls in. */
    content-visibility: auto;
    contain-intrinsic-size: auto 48px;
}
.row-tick {
    display: grid; grid-template-columns: 44px 1fr; align-items: center;
    min-height: 48px; width: 100%; padding: 0; text-align: left;
    background: none; border: 0; color: inherit; font: inherit; cursor: pointer;
}
.tick-box {
    justify-self: center;
    width: 22px; height: 22px; border-radius: 50%;
    border: 2px solid var(--muted);
    display: grid; place-items: center;
    font-size: 13px; line-height: 1; color: #fff;
}
.row-body { display: flex; align-items: baseline; gap: var(--s2); min-width: 0; padding-right: var(--s1); }
.row-name {
    flex: 0 1 auto; min-width: 0;
    font-size: var(--t-lg); line-height: 1.25;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.row.is-done .tick-box { background: var(--green); border-color: var(--green); }
.row.is-done .row-name { text-decoration: line-through; color: var(--muted); }

/* Saved here, not yet confirmed by the server. A ring, NOT a weaker check: the
 * user tapped it, so the check is real — the ring communicates provenance, not
 * doubt. box-shadow so nothing reflows when it clears. */
.row.is-unsent .tick-box {
    box-shadow: 0 0 0 2px var(--panel), 0 0 0 3px var(--accent);
}

.empty { padding: var(--s5) var(--s3); text-align: center; }

/* --- purchased section ---------------------------------------------------- */

.cat-h { margin: 0; }
.cat-h button {
    display: flex; align-items: center; gap: var(--s2);
    width: 100%; min-height: 36px; padding: 0 var(--s3);
    background: var(--panel-2); border: 0;
    border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
    color: var(--muted);
    font-family: inherit; font-size: var(--t-xs); font-weight: 600; line-height: 1;
    text-transform: uppercase; letter-spacing: .04em; text-align: left;
}
.cat-n { margin-left: auto; min-width: 2.2em; text-align: center; }

/* --- undo ----------------------------------------------------------------- */

.undo-bar {
    /* Horizontal placement is owned by app.css, exactly as for .qa below. A left
     * set here loads later and wins, while app.css's translateX(-50%) still applies
     * — which is how this bar spent a while half off the left edge of every phone,
     * its text out of sight, and over the sidebar on a desktop. */
    position: fixed;
    bottom: calc(56px + 64px + env(safe-area-inset-bottom) + var(--s2));
    z-index: 40;
    display: flex; align-items: center; gap: var(--s2);
    min-height: 44px; padding: 0 var(--s2) 0 var(--s3);
    background: var(--panel-2); color: var(--text);
    border: 1px solid var(--border); border-radius: var(--r-md);
    box-shadow: var(--shadow-2);
}
.undo-text { flex: 1 1 auto; font-size: var(--t-sm); min-width: 0;
             overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.undo-btn {
    flex: 0 0 auto; min-height: 44px; padding: 0 var(--s3);
    background: none; border: 0; color: var(--accent);
    font-family: inherit; font-size: var(--t-lg); font-weight: 600; line-height: 1;
}

/* --- quick add ------------------------------------------------------------ */

.qa {
    /* Sits ABOVE the tab bar, not under it. Both are fixed, and with the tab bar
     * at a higher z-index a bottom:0 quick-add is simply invisible — you cannot
     * add anything, which is the one thing this screen exists to do. */
    /* Horizontal placement is owned by app.css, which pins the fixed bars to the
     * app column rather than the window. Setting left/right here would override
     * that (this file loads later) and strand the bar at the window edge on a
     * desktop. */
    position: fixed; z-index: 30;
    bottom: calc(56px + env(safe-area-inset-bottom));
    display: grid; grid-template-columns: 1fr 48px; gap: var(--s2);
    padding: var(--s2) var(--s3);
    background: var(--panel); border-top: 1px solid var(--border);
}
.qa-input {
    height: 48px; padding: 0 14px;
    /* 16px is a HARD FLOOR. Anything smaller makes iOS zoom the viewport on
     * focus, which wrecks the layout in the middle of a shopping trip. */
    font-size: var(--t-lg);
    background: var(--panel-2); color: var(--text);
    border: 1px solid var(--border); border-radius: var(--r-pill);
}
.qa-add {
    width: 48px; height: 48px; border: 0; border-radius: var(--r-pill);
    background: var(--accent); color: #fff; font-size: 24px; line-height: 1;
}

/* --- login / skeleton / errors -------------------------------------------- */

.login { max-width: 24rem; margin: 0 auto; padding: var(--s6) var(--s4); display: grid; gap: var(--s4); }
.login h1 { font-size: var(--t-2xl); margin: 0; }
.login label { display: grid; gap: var(--s1); font-size: var(--t-sm); color: var(--text-2); }
.login input {
    height: 48px; padding: 0 var(--s3); font-size: var(--t-lg);
    background: var(--panel); color: var(--text);
    border: 1px solid var(--border); border-radius: var(--r-sm);
}
.btn {
    min-height: 48px; padding: 0 var(--s4);
    background: var(--accent); color: #fff; border: 0; border-radius: var(--r-sm);
    font-family: inherit; font-size: var(--t-lg); font-weight: 600; line-height: 1;
}
.flash { padding: var(--s3); border-radius: var(--r-sm); font-size: var(--t-sm); margin: 0; }
.flash-error { background: color-mix(in srgb, var(--red) 12%, transparent); color: var(--red); }

.boot-error { max-width: 32rem; margin: 0 auto; padding: var(--s6) var(--s4); }

.skeleton { padding: var(--s3); }
.sk-hdr { height: 44px; background: var(--panel-2); border-radius: var(--r-sm); margin-bottom: var(--s3); }
.sk-row { height: 48px; background: var(--panel-2); border-radius: var(--r-sm); margin-bottom: var(--s1); opacity: .6; }

/* --- category headings ----------------------------------------------------- */

.cat-chev { flex: 0 0 auto; }
/* Sticks below the header, so you always know which aisle you are looking at. */
.cat-h button { position: sticky; top: 66px; z-index: 10; }

.row-meta {
    flex: 0 0 auto; max-width: 45%;
    font-size: var(--t-sm); color: var(--muted);
    font-variant-numeric: tabular-nums;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.row { grid-template-columns: minmax(0, 1fr) auto auto; }

/* Edit and remove. 44px wide for the thumb, drawn small so a column of them reads
 * as quiet furniture beside the names rather than as a second list. */
.row-icon {
    display: grid; place-items: center;
    width: 44px; min-height: 48px; padding: 0;
    background: none; border: 0; color: var(--muted); cursor: pointer;
}
.row-icon .glyph { width: 20px; height: 20px; display: block; }
.row-edit:hover { color: var(--accent); }
.row-del:hover { color: var(--red); }

/* --- Manage ---------------------------------------------------------------- */

.bulk { display: grid; gap: var(--s2); padding: var(--s3); border-bottom: 1px solid var(--border); }
.bulk-label { font-size: var(--t-sm); color: var(--text-2); }
.bulk-input {
    width: 100%; padding: var(--s2) var(--s3);
    /* 16px floor: anything smaller makes iOS zoom the viewport on focus. */
    font: inherit; font-size: var(--t-lg);
    background: var(--panel); color: var(--text);
    border: 1px solid var(--border); border-radius: var(--r-sm);
    resize: vertical;
}

.mrow {
    display: grid; grid-template-columns: 1fr auto 44px;
    align-items: center; gap: var(--s2);
    min-height: 52px; padding: 0 var(--s2) 0 var(--s3);
    border-bottom: 1px solid var(--border);
}
.mrow-main { min-width: 0; }
.mrow-main { display: flex; align-items: center; gap: var(--s2); }

/* Text you can type into where it stands (InlineInput in ui/bits.js). It looks like
 * the text around it until focused, then like the field it is. The border is always
 * there, transparent, so focusing it moves nothing. 16px: iOS zooms for less. */
.mrow-name, .meal-input, .ing-input {
    flex: 1 1 auto; min-width: 0; width: 100%; height: 44px;
    padding: 0 var(--s2); margin-left: calc(-1 * var(--s2));
    font: inherit; font-size: var(--t-lg); color: var(--text);
    background: transparent;
    border: 1px solid transparent; border-radius: var(--r-sm);
    text-overflow: ellipsis;
}
.mrow-name:hover, .meal-input:hover, .ing-input:hover { border-color: var(--border); }
.mrow-name:focus, .meal-input:focus, .ing-input:focus {
    outline: none; background: var(--panel); border-color: var(--accent);
}
.meal-input::placeholder { color: var(--muted); }
.mrow-cat {
    max-width: 42vw; height: 36px; padding: 0 var(--s2);
    font: inherit; font-size: var(--t-sm);
    background: var(--panel-2); color: var(--text-2);
    border: 1px solid var(--border); border-radius: var(--r-sm);
}
.mrow-del {
    width: 44px; height: 44px;
    background: none; border: 0; color: var(--muted);
    font-size: 22px; line-height: 1; cursor: pointer;
}
.mrow-del:hover { color: var(--red); }

/* --- Meals ----------------------------------------------------------------- */

.meal {
    display: grid; grid-template-columns: 96px 1fr;
    align-items: center; gap: var(--s3);
    min-height: 56px; padding: 0 var(--s3);
    border-bottom: 1px solid var(--border);
}
.meal-day { display: grid; }
.meal-dow { font-size: var(--t-sm); font-weight: 600; }
.meal-date { font-size: var(--t-xs); }
.meal-more { display: flex; gap: var(--s4); padding: var(--s3); }

/* --- List switcher ------------------------------------------------------------ */

/* The header title is a button that changes list. It must not make the header
 * taller, because the category headings stick at a fixed 66px below it. So the
 * 44px hit area comes from padding, and an equal negative margin gives the height
 * back. That needs the title's usual overflow clipping off, since a clipped hit
 * area does not take taps; the name inside truncates instead. */
.hdr-title--pick { overflow: visible; }
.list-pick {
    display: inline-flex; align-items: center; gap: 6px;
    max-width: 100%; min-width: 44px;
    padding: 12px 0; margin: -12px 0;
    background: none; border: 0; color: inherit;
    font: inherit; text-align: left; cursor: pointer;
}
.list-pick-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.list-pick-chev { flex: 0 0 auto; font-size: .75em; color: var(--muted); }

/* --- Lists sheet ---------------------------------------------------------------- */

.lnew {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--s2);
    padding: var(--s3) var(--s4);
    border-bottom: 1px solid var(--border);
}
.lnew-input, .lrename-input, .isheet-name, .isheet-cat, .past-search-input {
    min-width: 0; height: 44px; padding: 0 var(--s3);
    /* 16px floor: anything smaller makes iOS zoom the viewport on focus. */
    font: inherit; font-size: var(--t-lg);
    background: var(--panel-2); color: var(--text);
    border: 1px solid var(--border); border-radius: var(--r-sm);
}
.lnew .btn, .lrename .btn, .ldelete .btn { min-height: 44px; }

.lrows { list-style: none; margin: 0; padding: 0; }
.lrow {
    display: grid; grid-template-columns: 24px minmax(0, 1fr) auto; align-items: center; gap: var(--s2);
    width: 100%; min-height: 48px; padding: 0 var(--s4) 0 var(--s3);
    background: none; border: 0; border-bottom: 1px solid var(--border);
    color: inherit; font: inherit; font-size: var(--t-lg); text-align: left; cursor: pointer;
}
.lrow[aria-current="true"] { color: var(--accent); font-weight: 600; }
.lrow-tick { text-align: center; }
.lrow-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lrow-n { min-width: 2em; text-align: right; font-size: var(--t-sm); font-weight: 400; color: var(--muted); }

.lcur {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0 var(--s5);
    padding: var(--s1) var(--s4) var(--s2);
}
.lcur-rename { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lrename {
    display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; gap: var(--s2);
    width: 100%; padding: var(--s2) 0;
}
.ldelete { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2) var(--s4); width: 100%; padding-bottom: var(--s2); }
.ldelete-q { flex: 1 1 100%; margin: var(--s2) 0 0; font-size: var(--t-md); }

.btn--danger { background: var(--red); }
.btn--danger-outline { background: none; color: var(--red); border: 1px solid currentColor; }

/* --- Item sheet ------------------------------------------------------------------ */

.isheet-field {
    display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: var(--s3);
    padding: var(--s3) var(--s4);
    border-bottom: 1px solid var(--border);
}
.isheet-label { font-size: var(--t-md); color: var(--text-2); }
.isheet-field .isheet-name, .isheet-field .isheet-cat { width: 100%; }
.isheet-actions { display: flex; gap: var(--s3); padding: var(--s4); }
.isheet-actions .btn { flex: 1 1 0; }

/* --- Finish trip, and past trips ------------------------------------------------ */

/* A text-sized button in the header's second line. Its 44px hit area comes from
 * padding with an equal negative margin, like the list switcher's, so the header
 * — and the category headings that stick 66px below its top — keeps its height. */
.hdr-link {
    padding: 12px 2px; margin: -12px 0;
    background: none; border: 0; color: var(--accent);
    font: inherit; font-weight: 600; cursor: pointer;
}

/* The secondary button beside a primary one. */
.btn--quiet { background: var(--panel-2); color: var(--text); border: 1px solid var(--border); }

.empty p { margin: 0; }
.empty .btn { margin-top: var(--s3); }

.trip-summary { padding: var(--s3) var(--s4) 0; }
.trip-line { margin: 0 0 var(--s2); font-size: var(--t-lg); }
.trip-hint { margin: var(--s2) 0 0; }

.past-entry { padding: 0 var(--s3); border-bottom: 1px solid var(--border); }
.past-search { padding: var(--s3) var(--s4); border-bottom: 1px solid var(--border); }
.past-search-input { width: 100%; }
.past-h {
    display: flex; align-items: center; justify-content: space-between; gap: var(--s3);
    min-height: 44px; padding: var(--s2) var(--s4) 0;
}
.past-title {
    margin: 0;
    font-size: var(--t-xs); font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
    color: var(--muted);
}
.past-rows { list-style: none; margin: 0; padding: 0; }
.prow {
    display: grid; grid-template-columns: 28px minmax(0, 1fr) auto; align-items: center; gap: var(--s2);
    min-height: 48px; padding: 0 var(--s4);
    border-bottom: 1px solid var(--border);
    font-size: var(--t-lg); cursor: pointer;
}
.prow-check { width: 22px; height: 22px; margin: 0; accent-color: var(--accent); }
.prow-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.prow.is-on-list { color: var(--muted); cursor: default; }
/* A long history scrolls inside the sheet; the Add button stays in reach. */
.past-actions { position: sticky; bottom: 0; background: var(--panel); border-top: 1px solid var(--border); }

/* --- Quantities ---------------------------------------------------------------- */

/* "6 medium" beside the name. The name gives way first: at 320px a long name
 * ellipsizes before the quantity does, because the quantity is what changes. */
.row-qty { flex: 0 0 auto; max-width: none; }

/* How many, in the Edit sheet: a stepper and what kind. */
/* The picker takes the line below when there is no room beside the stepper — on a
 * 320px phone it would otherwise shrink to its arrow. */
.qty-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2); min-width: 0; }
.qty-step {
    flex: 0 0 44px; height: 44px; padding: 0;
    background: var(--panel-2); color: var(--text);
    border: 1px solid var(--border); border-radius: var(--r-sm);
    font: inherit; font-size: var(--t-xl); line-height: 1; cursor: pointer;
}
.qty-input, .qty-kind {
    min-width: 0; height: 44px; padding: 0 var(--s2);
    /* 16px floor: anything smaller makes iOS zoom the viewport on focus. */
    font: inherit; font-size: var(--t-lg);
    background: var(--panel-2); color: var(--text);
    border: 1px solid var(--border); border-radius: var(--r-sm);
}
.qty-input { flex: 0 0 4.5em; width: 4.5em; text-align: center; }
.qty-kind { flex: 1 1 7em; }

/* Already on the list: what it says, and what the choices would make it say. */
.dup-says {
    display: flex; flex-wrap: wrap; gap: var(--s1) var(--s4);
    margin: 0; padding: var(--s3) var(--s4) 0;
    font-size: var(--t-md); color: var(--text-2);
}
.dup-name { flex-basis: 100%; font-size: var(--t-xl); font-weight: 600; color: var(--text); }
.dup-choices { display: grid; gap: var(--s2); padding: var(--s4); }
.dup-choice { width: 100%; min-height: 48px; justify-content: center; }

.mrow-qty { flex: 0 0 auto; margin-left: 0; }
.merge-notice > span { white-space: normal; text-align: left; }
.merge-notice { padding-block: var(--s2); }

/* Under the category, when Claude chose it: says so, so a wrong one gets corrected. */
.isheet-note { margin: 0; padding: var(--s2) var(--s4) 0; }

/* --- Recipes ---------------------------------------------------------------------- */

.recipes-new { padding: var(--s3); border-bottom: 1px solid var(--border); }
.recipes-new .btn { width: 100%; }
.rrow {
    display: grid; gap: 2px;
    width: 100%; min-height: 56px; padding: var(--s2) var(--s3);
    background: none; border: 0; border-bottom: 1px solid var(--border);
    color: inherit; font: inherit; text-align: left; cursor: pointer;
}
.rrow-name { font-size: var(--t-lg); line-height: 1.25; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rrow-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s1) var(--s2); }
.rrow-meta .pill { margin-left: 0; }

/* The recipe sheet. Sections share the past-trips heading, fields the item sheet's. */
.rsheet-section { padding: var(--s2) 0 var(--s3); border-bottom: 1px solid var(--border); }
.rsheet-section .past-title { padding: 0 var(--s4); margin-bottom: var(--s1); }
/* One text field per ingredient, read like the quick-add; the amount it read beside it. */
.ing {
    display: grid; grid-template-columns: minmax(0, 1fr) auto 44px; align-items: center; gap: var(--s2);
    min-height: 44px; padding: 0 var(--s2) 0 var(--s4);
}
.ing-qty { margin-left: 0; }
.ing-addrow {
    display: grid; grid-template-columns: minmax(0, 1fr) 44px; align-items: center; gap: var(--s2);
    padding: var(--s2) var(--s4) 0;
}
.ing-add {
    min-width: 0; height: 44px; padding: 0 var(--s3);
    /* 16px floor: anything smaller makes iOS zoom the viewport on focus. */
    font: inherit; font-size: var(--t-lg);
    background: var(--panel-2); color: var(--text);
    border: 1px solid var(--border); border-radius: var(--r-pill);
}
.ing-add-btn { width: 44px; height: 44px; font-size: 22px; }

.occ-pills { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2); padding: 0 var(--s4); }
.occ-pill {
    min-height: 36px; padding: 0 var(--s3);
    background: var(--panel-2); color: var(--text-2);
    border: 1px solid var(--border); border-radius: var(--r-pill);
    font: inherit; font-size: var(--t-sm); font-weight: 600; cursor: pointer;
}
.occ-pill[aria-pressed="true"] { background: var(--accent); color: #fff; border-color: var(--accent); }
.occ-add { display: grid; gap: var(--s2); padding: var(--s2) var(--s4) 0; }
.occ-kinds { display: flex; flex-wrap: wrap; gap: var(--s2); }
.occ-kind {
    min-height: 36px; padding: 0 var(--s3);
    background: none; color: var(--accent);
    border: 1px solid var(--border); border-radius: var(--r-pill);
    font: inherit; font-size: var(--t-sm); font-weight: 600; cursor: pointer;
}
.occ-kind[aria-checked="true"] { background: var(--panel-2); color: var(--text); border-color: var(--text-2); }
.occ-holiday, .occ-name { width: 100%; }
.occ-date { display: grid; grid-template-columns: minmax(0, 1fr) 5em; gap: var(--s2); }
.occ-add-actions { display: flex; align-items: center; gap: var(--s4); }
/* The note stacks under its label: a textarea beside a label is a sliver at 320px. */
.rsheet-notefield { grid-template-columns: minmax(0, 1fr); }
.rsheet-note { width: 100%; }

/* --- The planner: picking a recipe for a day, and the checklist ----------------------- */

/* The day cell is the way into the recipe book for that day. A button now, drawn as
 * the label it was, so the input beside it keeps its width at 320px. */
.meal-pick {
    display: grid; align-content: center; gap: 1px;
    min-height: 56px; padding: 0; margin: 0;
    background: none; border: 0; color: inherit; font: inherit; text-align: left; cursor: pointer;
}
.meal-chev { font-size: .7em; color: var(--muted); }
/* An occasion wraps rather than clips: "Emma's birthday" is the whole point of the line. */
.meal-occ { color: var(--accent); font-weight: 600; font-size: var(--t-xs); line-height: 1.2; overflow-wrap: anywhere; }
/* A past-trips row as a button. */
.pick-row {
    width: 100%; background: none; border: 0; border-bottom: 1px solid var(--border);
    color: inherit; font: inherit; text-align: left; cursor: pointer;
}
.pick-row[aria-current="true"] { color: var(--accent); font-weight: 600; }

.check-meals { margin: 0; padding: var(--s2) var(--s4) 0; }
.check-hint { padding-bottom: var(--s2); }
.check-rows .is-on-list .row-name { color: var(--muted); }
.check-rows .is-on-list .row-tick { cursor: default; }
.check-actions .btn { width: 100%; }

@media (max-width: 899px) {
    /* Meals and the recipe book have no quick-add bar for the undo bar to clear. */
    .app[data-route="meals"] .undo-bar, .app[data-route="recipes"] .undo-bar {
        bottom: calc(56px + env(safe-area-inset-bottom) + var(--s2));
    }
}
