@font-face {
    font-family: "Source Sans 3";
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url("../fonts/source-sans-3-latin-wght.9ef356ea553a.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "Source Sans 3";
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url("../fonts/source-sans-3-latin-ext-wght.c6ba61588d7d.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: "JetBrains Mono";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("../fonts/jetbrains-mono-latin-400.caf0dfde4e44.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "JetBrains Mono";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("../fonts/jetbrains-mono-latin-ext-400.443d1c3be5b2.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: "JetBrains Mono";
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("../fonts/jetbrains-mono-latin-500.a21e038a03f7.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "JetBrains Mono";
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("../fonts/jetbrains-mono-latin-ext-500.311b1217e9b0.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

html {
    font-size: 16px;
}

body {
    font: var(--text-body);
    color: var(--ink);
    background: var(--page);
}

/* Nothing on a page widens it past the screen: wide content scrolls in its own box. */
main {
    min-width: 0;
    overflow-x: clip;
}

/* A layer open on touch (helpers.js openLayer): the page under it neither scrolls nor pulls to refresh. */
html.layer-open {
    overflow: hidden;
    overscroll-behavior: none;
}

.mono {
    font-family: var(--font-mono);
    font-size: 0.9em;
}

.micro {
    font: var(--text-micro);
    letter-spacing: var(--micro-tracking);
    text-transform: uppercase;
    color: var(--ink-2);
}

.text-display { font: var(--text-display); }
.text-heading { font: var(--text-heading); }
.text-section { font: var(--text-section); }
.text-small { font: var(--text-small); }

/* === Shell: a left rail from 1024px; below it a top bar and a bottom tab bar === */
/* The menu and More (03-design-system.md). --shell-bottom: what the tab bar covers. */
:root {
    --shell-bottom: 0rem;
    --rail-motion: 0.2s ease;
    --rail-pad-x: 0.625rem;
    --rail-mark: 1.625rem;
    --rail-toggle: 1.875rem;
    --rail-item-h: 2.25rem;
    --rail-item-h-compact: 2.5rem;
    --rail-picker-h: 2.125rem;
    --rail-radius: 0.5rem;
    --new-dot: #D92D20;
    /* The collapsed content width, and what centres an 18px icon, the flower and the avatar in it. */
    --rail-inner: calc(var(--rail-w-compact) - 2 * var(--rail-pad-x) - 1px);
    --rail-icon-pad: calc((var(--rail-inner) - 1.125rem) / 2);
    --rail-mark-pad: calc((var(--rail-inner) - var(--rail-mark)) / 2);
    --rail-avatar-pad: calc((var(--rail-inner) - 1.75rem) / 2);
}

/* The menu never scrolls: on a short window its rows tighten so it fits (to ~600px tall). */
@media (max-height: 760px) {
    :root { --rail-item-h: 2.125rem; --rail-item-h-compact: 2.25rem; }
}
@media (max-height: 660px) {
    :root { --rail-item-h: 1.875rem; --rail-item-h-compact: 1.875rem; }
}

/* The header and <main> under one hx-history-elt (base.html); no box of its own. */
.app-page {
    display: contents;
}

/* Above the page's own layers (Leaflet 1000, toolbars 1030), below offcanvas and modals. */
.app-rail,
.app-header,
.app-tabbar,
.app-env-strip {
    z-index: var(--z-sticky);
}

.app-rail {
    position: fixed;
    inset: 0 auto 0 0;
    width: var(--rail-w);
    display: flex;
    flex-direction: column;
    padding: 0.875rem var(--rail-pad-x) var(--space-3);
    overflow: hidden;
    background: var(--rail);
    border-right: thin solid var(--rail-line);
    color: var(--rail-ink);
}

/* A non-production deploy: its colour across the top and its name under "Zuko". Production has
   no colour and shows neither (apps/core/shell.py). */
.app-rail--env {
    box-shadow: inset 0 var(--space-1) 0 var(--env-color);
}

.app-rail-env {
    grid-area: 2 / 2 / 3 / 4;
    justify-self: start;
    align-self: end;
    margin-bottom: 2px;
    padding: 1px 7px;
    border-radius: var(--radius-pill);
    background: var(--env-color);
    font: var(--text-micro);
    color: var(--surface);
    white-space: nowrap;
}

/* One row: the flower, "Zuko" and «. A second holds the env badge, or collapsed, the » under
   the flower. */
.app-rail-head {
    display: grid;
    grid-template-columns: var(--rail-mark) 1fr auto;
    grid-template-rows: var(--rail-toggle) 0;
    column-gap: 9px;
    align-items: center;
    padding: 2px 4px 0.875rem var(--rail-mark-pad);
}

.app-rail--env .app-rail-head {
    grid-template-rows: var(--rail-toggle) 1.75rem;
    padding-bottom: var(--space-3);
}

.app-rail-brand {
    grid-area: 1 / 1 / 2 / 3;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 9px;
    font: 700 1.1875rem/1.5rem var(--font-sans);
    letter-spacing: -0.01em;
    color: var(--ink);
    text-decoration: none;
}

.app-rail-brand:hover {
    color: var(--ink);
}

.app-rail-brand img {
    flex: none;
    width: var(--rail-mark);
    height: auto;
}

.app-rail-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--rail-toggle);
    height: var(--rail-toggle);
    padding: 0;
    border: 0;
    border-radius: var(--radius-control);
    background: none;
    color: var(--ink-2);
}

.app-rail-toggle .icon {
    font-size: 1rem;
}

.app-rail-toggle:hover {
    background: var(--rail-line);
    color: var(--ink);
}

.app-rail-collapse {
    grid-area: 1 / 3;
}

.app-rail-expand {
    grid-area: 2 / 1;
    justify-self: center;
    align-self: end;
    display: none;
}

.app-rail-nav {
    display: flex;
    flex-direction: column;
    gap: calc(var(--space-1) / 2);
    margin-bottom: var(--space-4);
}

.app-rail-link {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    width: 100%;
    min-height: var(--rail-item-h);
    padding: 0 var(--rail-pad-x);
    border: 0;
    border-radius: var(--rail-radius);
    background: none;
    font: 400 0.875rem/1.25rem var(--font-sans);
    color: var(--rail-ink);
    text-align: left;
    text-decoration: none;
    white-space: nowrap;
}

.app-rail-link > .icon {
    width: 1.125rem;
    height: 1.125rem;
    color: var(--ink-2);
}

.app-rail-link:hover,
.app-rail-link:focus-visible {
    background: var(--rail-line);
    color: var(--ink);
}

.app-rail-link.active {
    background: var(--rail-active);
    color: var(--surface);
    font-weight: 600;
}

.app-rail-link.active > .icon {
    color: var(--surface);
}

.app-rail-label {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.app-rail-foot {
    margin-top: auto;
    padding-top: var(--space-3);
    border-top: thin solid var(--rail-line);
    display: flex;
    flex-direction: column;
    gap: calc(var(--space-1) / 2);
}

.app-rail-user {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    min-width: 0;
    min-height: calc(var(--rail-item-h) + var(--space-1));
    padding: 0 var(--rail-pad-x) 0 var(--rail-avatar-pad);
    font: 600 0.875rem/1.125rem var(--font-sans);
    color: var(--ink);
    white-space: nowrap;
}

/* Impersonate (impersonate_user.html, superusers): the shared searchable picker with the icon
   inside it and a down chevron. --imp-* lay it out; More sets its own. */
.impersonate-picker {
    --imp-h: min(var(--rail-picker-h), var(--rail-item-h));
    --imp-pad: 0.625rem;
    --imp-icon: 1rem;
    --imp-gap: var(--space-2);
    --imp-chevron: 0.875rem;
    --imp-radius: var(--radius-control);
    position: relative;
    display: flex;
    align-items: center;
    height: var(--imp-h);
    margin: 0 2px 6px;
}

.impersonate-picker > .icon {
    position: absolute;
    left: calc(var(--imp-pad) + 1px);
    width: var(--imp-icon);
    height: var(--imp-icon);
    z-index: 1;
    color: var(--ink-2);
    pointer-events: none;
}

.impersonate-picker > select[data-picker] + .select2-container .select2-selection {
    min-height: 0;
    height: var(--imp-h);
    border-radius: var(--imp-radius);
    font-size: 0.84375rem;
}

.impersonate-picker > select[data-picker] + .select2-container .select2-selection--single .select2-selection__rendered {
    padding-left: calc(var(--imp-pad) + var(--imp-icon) + var(--imp-gap));
    padding-right: calc(var(--imp-pad) + var(--imp-chevron) + var(--imp-gap));
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.impersonate-picker > select[data-picker] + .select2-container .select2-selection__arrow {
    right: var(--imp-pad);
    width: var(--imp-chevron);
    mask-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3e%3cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m6 9 6 6 6-6'/%3e%3c/svg%3e");
}

/* Its list is wider than the menu, the collapsed one's icon above all. */
.select2-container .select2-dropdown.impersonate-dropdown {
    min-width: 16rem;
}

/* "Viewing as" over the name, Stop at the right. */
.impersonate-note {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin: 0 2px 6px;
    padding: var(--space-2) var(--rail-pad-x);
    border-radius: var(--rail-radius);
    background: var(--tone-pending-fill);
    font: 400 0.8125rem/1rem var(--font-sans);
    color: var(--tone-pending-ink);
    white-space: nowrap;
}

/* Fixed, so the collapse can animate it: two lines of 1rem. */
.app-rail .impersonate-note {
    height: calc(2rem + 2 * var(--space-2));
}

.impersonate-note > .icon {
    width: 1rem;
    height: 1rem;
}

.impersonate-note-text {
    flex: 1;
    min-width: 0;
}

.impersonate-note-text strong {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    font-weight: 700;
}

/* × stops impersonating: red, so it reads as stop on the amber note. */
.stop-impersonating-btn {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    width: var(--space-6);
    height: var(--space-6);
    padding: 0;
    border: 0;
    border-radius: var(--radius-control);
    background: none;
    color: var(--danger);
}
.stop-impersonating-btn:hover {
    background: var(--tone-refused-fill);
}
.stop-impersonating-btn > .icon {
    width: 1.125rem;
    height: 1.125rem;
}

/* A 44px target on touch (More's ×); the negative margin keeps the note's height. */
@media (pointer: coarse) {
    .stop-impersonating-btn {
        min-width: var(--control-h);
        min-height: var(--control-h);
        margin-block: calc(var(--space-2) * -1);
    }
}

.impersonate-user-loading-overlay {
    position: fixed;
    inset: 0;
    z-index: var(--z-toast);
    background: rgba(0, 0, 0, .5);
}

.impersonate-user-loading-overlay > div {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    padding: var(--space-7);
    border-radius: var(--radius-card);
    background: var(--surface);
    color: var(--ink);
    text-align: center;
}

.impersonate-user-loading-label {
    margin-top: var(--space-6);
}

.app-header {
    overflow: hidden;
    font: var(--text-section);
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* The phone tab bar: 22px icons over 10.5px labels; the current tab is the accent. */
.app-tab {
    position: relative;
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: calc(var(--space-1) / 2);
    border: 0;
    background: none;
    font: 600 0.65625rem/0.875rem var(--font-sans);
    color: var(--tab-ink);
    text-decoration: none;
}

.app-tab:hover {
    color: var(--ink);
}

.app-tab .icon {
    font-size: 1.375rem;
}

.app-tab.active,
.app-tab.active:hover,
body.more-open .app-tab-more {
    color: var(--accent);
    font-weight: 700;
}

/* While More is open, it is the current tab. */
body.more-open .app-tab.active:not(.app-tab-more) {
    color: var(--tab-ink);
    font-weight: 600;
}

/* Something you haven't seen yet (What's new): a red dot, on the More tab, its row and Today's
   head. */
.new-dot {
    display: inline-block;
    flex: none;
    width: var(--space-2);
    height: var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--new-dot);
}

.app-tab-dot {
    position: absolute;
    top: var(--space-2);
    left: calc(50% + var(--space-2));
    box-shadow: 0 0 0 calc(var(--space-1) / 2) var(--surface);
}

/* More (phone): a screen above the tab bar, which stays live (no backdrop): Apps, What's new,
   then Account, each a card of rows. --more-pad: a row's side padding. */
.app-more.offcanvas-bottom {
    --bs-offcanvas-bg: var(--page);
    --more-pad: 0.875rem;
    top: 0;
    bottom: var(--shell-bottom, 0);
    height: auto;
    max-height: none;
    border-top: 0;
}

.app-more .offcanvas-header {
    padding: calc(var(--more-pad) + env(safe-area-inset-top)) var(--more-pad) var(--space-3);
    background: var(--surface);
    border-bottom: thin solid var(--line);
}

.app-more-title {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    font: var(--text-heading);
    font-weight: 700;
}

.app-more-title img {
    width: 1.5rem;
    height: auto;
}

.app-more .offcanvas-body {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-3);
}

.app-more-heading {
    margin: 6px 2px calc(-1 * var(--space-1));
}

/* flex: none, or a card shorter than the screen would shrink and clip its last rows; the body scrolls. */
.app-more-card {
    flex: none;
    overflow: hidden;
    border: thin solid var(--line);
    border-radius: var(--radius-card);
    background: var(--surface);
}

/* :not(), to outweigh .app-more-link's border: 0. */
.app-more-card > :not(:first-child) {
    border-top: thin solid var(--sunken);
}

.app-more-link {
    display: flex;
    align-items: center;
    gap: var(--more-pad);
    width: 100%;
    min-height: 3.125rem;
    padding: 0 var(--more-pad);
    border: 0;
    background: none;
    font-size: 1rem;
    color: var(--ink);
    text-align: left;
    text-decoration: none;
}

.app-more-link > .icon:first-child {
    font-size: 1.25rem;
    color: var(--ink-2);
}

.app-more-link:hover {
    color: var(--ink);
    background: var(--page);
}

.app-more-link.active {
    background: var(--accent-wash);
    color: var(--accent);
    font-weight: 600;
}

.app-more-link.active > .icon:first-child {
    color: var(--accent);
}

.app-more-label {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.app-more-chevron {
    font-size: 1rem;
    color: var(--ink-3);
}

.app-more-impersonate {
    padding: var(--space-3) var(--more-pad);
}

.app-more-impersonate > :is(.impersonate-picker, .impersonate-note) {
    margin: 0;
}

.app-more-impersonate .impersonate-picker {
    --imp-h: var(--control-h);
    --imp-pad: var(--space-3);
    --imp-icon: 1.125rem;
    --imp-gap: 0.625rem;
    --imp-chevron: 1rem;
    --imp-radius: var(--rail-radius);
}

.app-more-impersonate .impersonate-picker > select[data-picker] + .select2-container .select2-selection {
    font-size: 1rem;
}

.app-more-user {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--more-pad);
    font-size: 1rem;
    font-weight: 600;
}

@media (min-width: 1024px) {
    body {
        padding-left: var(--rail-w);
    }

    .app-header {
        min-height: var(--topbar-h);
        padding: 0 var(--space-4);
        line-height: var(--topbar-h);
    }

    .app-header:empty,
    .app-tabbar,
    .app-env-strip {
        display: none;
    }

    /* Collapsed to icons: body.shell-collapsed (the user's choice) or body.shell-compact (the page's). */
    body:is(.shell-collapsed, .shell-compact) {
        padding-left: var(--rail-w-compact);
    }

    :is(.shell-collapsed, .shell-compact) .app-rail {
        width: var(--rail-w-compact);
    }

    /* Slide only while toggling (shell.js), never on load. */
    body.shell-animating,
    .shell-animating .app-rail {
        transition: padding-left var(--rail-motion), width var(--rail-motion);
    }

    .shell-animating :is(.app-rail-label, .app-rail-env, .app-rail-collapse, .impersonate-note-text, .stop-impersonating-btn, .impersonate-picker > .select2-container) {
        transition: opacity var(--rail-motion);
    }

    /* The rows and the head take their collapsed size as the menu slides, not after it. */
    .shell-animating .app-rail :is(.app-rail-head, .app-rail-link, .impersonate-picker, .impersonate-note, .impersonate-picker > .icon) {
        transition: grid-template-rows var(--rail-motion), min-height var(--rail-motion), height var(--rail-motion),
                    padding var(--rail-motion), margin var(--rail-motion), left var(--rail-motion);
    }

    .shell-animating .app-rail :is(.app-rail-brand, .app-rail-user) {
        white-space: nowrap;
    }

    body.shell-collapsing {
        padding-left: var(--rail-w-compact);
    }

    .shell-collapsing .app-rail {
        width: var(--rail-w-compact);
    }

    .shell-collapsing :is(.app-rail-label, .app-rail-env, .app-rail-collapse, .impersonate-note-text, .stop-impersonating-btn, .impersonate-picker > .select2-container) {
        opacity: 0;
    }

    :is(.shell-collapsed, .shell-compact) :is(.app-rail-label, .app-rail-env, .app-rail-collapse, .impersonate-note-text) {
        display: none;
    }

    .shell-collapsed:not(.shell-compact) .app-rail-expand {
        display: inline-flex;
    }

    /* Collapsed: the flower over », and taller rows with each icon centred. */
    :is(.shell-collapsed, .shell-compact, .shell-collapsing) .app-rail-head {
        grid-template-rows: 1.75rem calc(var(--space-2) + var(--rail-toggle));
        padding-bottom: var(--space-3);
    }

    .shell-compact:not(.shell-collapsed) .app-rail-head {
        grid-template-rows: 1.75rem 0;
    }

    :is(.shell-collapsed, .shell-compact, .shell-collapsing) .app-rail-link {
        min-height: var(--rail-item-h-compact);
        padding-left: var(--rail-icon-pad);
    }

    :is(.shell-collapsed, .shell-compact, .shell-collapsing) .app-rail :is(.impersonate-picker, .impersonate-note) {
        --imp-h: var(--rail-item-h-compact);
        height: var(--rail-item-h-compact);
        margin: 0;
        padding-block: 0;
        padding-left: var(--rail-icon-pad);
        border-radius: var(--rail-radius);
    }

    :is(.shell-collapsed, .shell-compact, .shell-collapsing) .app-rail .impersonate-picker > .icon {
        left: var(--rail-icon-pad);
    }

    :is(.shell-collapsed, .shell-compact, .shell-collapsing) .app-rail :is(.impersonate-picker, .impersonate-note) > .icon {
        width: 1.125rem;
        height: 1.125rem;
    }

    /* Collapsed, the picker's box lies invisibly over its icon, so a click still opens the list;
       the note's × fills its slot. */
    :is(.shell-collapsed, .shell-compact) .app-rail .impersonate-picker:hover {
        background: var(--rail-line);
    }

    /* Clipped to the icon: an icon-wide pick would wrap into a column reaching up the menu, and
       its invisible box would take the hover and clicks meant for the space above. */
    :is(.shell-collapsed, .shell-compact) .app-rail .impersonate-picker > .select2-container {
        position: absolute;
        inset: 0;
        overflow: hidden;
        opacity: 0;
    }

    /* Collapsed, the note is its red × on the amber, filling the slot. */
    :is(.shell-collapsed, .shell-compact) .app-rail .impersonate-note > .icon {
        visibility: hidden;
    }
    :is(.shell-collapsed, .shell-compact) .app-rail .stop-impersonating-btn {
        position: absolute;
        inset: 0;
        width: auto;
        height: auto;
        border-radius: inherit;
    }
}

@media (max-width: 1023.98px) {
    :root {
        --shell-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
    }

    body {
        padding: var(--topbar-h) env(safe-area-inset-right) var(--shell-bottom) env(safe-area-inset-left);
    }

    .app-rail {
        display: none;
    }

    /* Over the top bar's top edge: transparent unless the env tint paints it. */
    .app-env-strip {
        position: fixed;
        inset: 0 0 auto 0;
        height: var(--space-1);
        background: transparent;
        pointer-events: none;
    }

    .app-header {
        position: fixed;
        inset: 0 0 auto 0;
        z-index: calc(var(--z-sticky) - 1);
        height: var(--topbar-h);
        padding: 0 calc(var(--space-3) + env(safe-area-inset-right)) 0 calc(var(--space-3) + env(safe-area-inset-left));
        line-height: var(--topbar-h);
        background: var(--surface);
        border-bottom: thin solid var(--line);
    }

    /* A page that names itself (components/page_head.html) leaves page_title empty: no bar. */
    .app-header:empty {
        display: none;
    }

    body:has(.app-header:empty) {
        padding-top: env(safe-area-inset-top);
    }

    .app-tabbar {
        position: fixed;
        inset: auto 0 0 0;
        display: flex;
        height: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
        padding: 0 env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
        background: var(--surface);
        border-top: thin solid var(--line);
    }
}

/* === Toasts === */
/* --toast-top is the header's height, measured by js/toasts.js. pointer-events: none lets clicks
   through the gaps; each toast takes them back. Above every overlay. */
#toast-container {
    top: var(--toast-top, 3rem);
    z-index: var(--z-toast);
    max-width: 22rem;
    pointer-events: none;
}

#toast-container .app-toast {
    pointer-events: auto;
}

#toast-container .toast-link {
    color: var(--accent);
    text-decoration: none;
}

#toast-container .toast-link:hover,
#toast-container .toast-link:focus-visible {
    color: var(--accent-hover);
    text-decoration: underline;
}

/* A phone-wide container at the top would bury the page's first header: dock it above the tab bar. */
@media (max-width: 767.98px) {
    #toast-container {
        top: auto;
        bottom: var(--shell-bottom);
        left: 0;
        max-width: none;
    }
}

/* === Attachments === */
.attachment-delete {
    opacity: 0;
    transition: opacity 0.12s ease;
}

.attachment-card:hover .attachment-delete,
.attachment-delete:focus-visible {
    opacity: 1;
}

@media (hover: none) {
    .attachment-delete {
        opacity: 1;
    }
}

/* Timeline sections double as attachment drop targets. */
.documents-dropzone.drop-active {
    outline: calc(var(--space-1) / 2) dashed var(--accent);
    outline-offset: var(--space-2);
    border-radius: var(--radius-control);
    background: var(--accent-wash);
}

@media print {
    body {
        padding: 0;
    }

    .app-rail,
    .app-header,
    .app-tabbar,
    .app-env-strip,
    .app-more {
        display: none;
    }
}
