/* ============================================================
   BarkBoard - mobile app kit ("app-ui")
   ------------------------------------------------------------
   The shared look of the phone app: cards, tiles, avatars, lists,
   bottom sheets, toasts, install prompts, page transitions, plus the
   phone header fix. Loaded by layouts/app right after
   mobile-polish.css and before @stack('styles'), so page CSS can
   override any of it with a selector of the same weight.

   Rules (docs/modules/pwa/app-kit.md, docs/theme-guide.md):
   - Every selector is namespaced .app-* (the only .app- class that
     existed before is .app-footer, which the kit never touches), so
     nothing here reaches existing markup. The exceptions are the
     phone header fix (section 14) and the page transitions
     (section 15), both inside the phone layout media query, and
     never on a desktop mouse.
   - Colours are --bb-* tokens or the derived --app-* tokens below;
     no hex outside the two token blocks. Logical properties only.
   - Dark mode is html.dark-theme. dark-theme.css forces
     `html.dark-theme p { color:#fff !important }` and recolours
     headings, so kit markup never uses <p> for text whose colour
     matters, and heading colours are doubled with html.dark-theme.
   - Motion respects prefers-reduced-motion: no slide, no press
     scale, no pulse, no page transition.

   Phone layout query (PLAN §2, bbAppUi.LAYOUT_QUERY):
     (max-width: 767.98px), (pointer: coarse) and (max-height: 540px)
   Feature surface (bbAppUi.FEATURE_QUERY): standalone OR (pointer: coarse);
   it only decides where the inline install CTAs show.

   Contents
     1. Tokens              9. Empty state, skeleton, progress
     2. Visibility gates   10. Segmented control
     3. Screen, sections   11. Buttons, install prompts
     4. Cards, hero, chips 12. Bottom sheet
     5. Tiles              13. Toast, live region
     6. Avatars            14. Phone header fix
     7. Lists              15. Page transitions
     8. Sheet actions
   ============================================================ */

/* ------------------------------------------------------------
   1. Tokens (derived only - change the --bb-* source instead)
   ------------------------------------------------------------ */
:root {
    --app-gutter: 12px;
    --app-gap: 12px;
    --app-radius: var(--bb-radius-xl);
    --app-radius-lg: 20px;
    --app-radius-sm: 12px;
    --app-tap: 44px;
    --app-tile-h: 84px;
    --app-avatar-sm: 32px;
    --app-avatar-md: 40px;
    --app-avatar-lg: 64px;
    --app-avatar-xl: 72px;
    --app-dot: 14px;

    /* Brand hero: white on the brand teal is 5.47:1. Muted text is 90% white
       and secondary buttons darken the card (a white wash measured about
       4.1-4.2:1, under 4.5:1): both keep AA on the light-mode teal */
    --app-hero-bg: var(--bb-primary);
    --app-hero-fg: var(--bb-on-primary);
    --app-hero-muted: color-mix(in srgb, var(--bb-on-primary) 90%, transparent);
    --app-hero-chip-bg: color-mix(in srgb, #000 22%, transparent);
    --app-hero-btn-bg: color-mix(in srgb, #000 16%, transparent);

    /* Filled brand controls (primary buttons, primary tile) */
    --app-fill: var(--bb-primary);
    --app-fill-hover: var(--bb-primary-hover);
    --app-fill-active: var(--bb-primary-active);
    --app-on-fill: var(--bb-on-primary);
    /* Brand-coloured text on a soft brand tint (pill, accent chip, initial) */
    --app-accent-text: var(--bb-primary);

    /* Press feedback and motion */
    --app-press: .97;
    --app-press-bg: color-mix(in srgb, var(--bb-text) 6%, transparent);
    --app-dur: var(--bb-base);
    --app-sheet-dur: .28s;
    --app-ease-out: cubic-bezier(.22, .9, .3, 1);

    /* Soft elevation for things that sit on the canvas (cards, tiles) and
       for things that genuinely float (toast, sheet) */
    --app-shadow-rest: 0 1px 2px rgba(15, 23, 42, .04), 0 1px 1px rgba(15, 23, 42, .02);
    --app-shadow-float: 0 12px 32px -8px rgba(15, 23, 42, .28), 0 2px 6px rgba(15, 23, 42, .08);
    --app-shadow-sheet: 0 -8px 32px -8px rgba(15, 23, 42, .22);
    --app-shadow-seg: 0 1px 3px rgba(15, 23, 42, .12);
    --app-press-surface: color-mix(in srgb, var(--bb-surface), var(--bb-text) 6%);

    /* Chip text: dashboard-ui.css's AA-measured tones when that sheet is on
       the page, the same mixes otherwise */
    --app-chip-danger-text: var(--chip-danger-text, color-mix(in srgb, var(--bb-danger), #000 8%));
    --app-chip-warning-text: var(--chip-warning-text, color-mix(in srgb, var(--bb-warning), #000 28%));
    --app-chip-success-text: var(--chip-success-text, color-mix(in srgb, var(--bb-success), #000 22%));
    --app-chip-info-text: var(--chip-info-text, color-mix(in srgb, var(--bb-info), #000 28%));
    --app-chip-neutral-text: var(--chip-neutral-text, color-mix(in srgb, var(--bb-text-muted), #000 8%));

    /* Toast: an inverse surface, so it reads as "on top" in both themes */
    --app-toast-bg: color-mix(in srgb, var(--bb-text), #000 10%);
    --app-toast-fg: var(--bb-surface);
    --app-toast-action: color-mix(in srgb, var(--bb-accent), #fff 55%);
    --app-toast-success: color-mix(in srgb, var(--bb-success), #fff 45%);
    --app-toast-danger: color-mix(in srgb, var(--bb-danger), #fff 45%);
}

html.dark-theme {
    /* The dark accent (#14b8a6) gives white text only ~2.5:1: darken it */
    --app-hero-bg: color-mix(in srgb, var(--bb-accent), #000 52%);
    --app-fill: color-mix(in srgb, var(--bb-accent), #000 40%);
    --app-fill-hover: color-mix(in srgb, var(--bb-accent), #000 48%);
    --app-fill-active: color-mix(in srgb, var(--bb-accent), #000 56%);
    --app-accent-text: color-mix(in srgb, var(--bb-accent), #fff 35%);
    --app-press-bg: color-mix(in srgb, #fff 7%, transparent);
    --app-shadow-rest: 0 1px 2px rgba(0, 0, 0, .25);
    --app-shadow-float: 0 16px 40px -8px rgba(0, 0, 0, .6), 0 2px 8px rgba(0, 0, 0, .35);
    --app-shadow-sheet: 0 -8px 32px -8px rgba(0, 0, 0, .6);
    --app-shadow-seg: 0 1px 3px rgba(0, 0, 0, .4);
    --app-press-surface: color-mix(in srgb, var(--bb-surface), #fff 6%);

    --app-chip-danger-text: var(--chip-danger-text, color-mix(in srgb, var(--bb-danger), #fff 45%));
    --app-chip-warning-text: var(--chip-warning-text, color-mix(in srgb, var(--bb-warning), #fff 45%));
    --app-chip-success-text: var(--chip-success-text, color-mix(in srgb, var(--bb-success), #fff 40%));
    --app-chip-info-text: var(--chip-info-text, color-mix(in srgb, var(--bb-info), #fff 45%));
    --app-chip-neutral-text: var(--chip-neutral-text, var(--bb-text-muted));

    --app-toast-bg: var(--bb-text);
    --app-toast-fg: var(--bb-bg);
    --app-toast-action: color-mix(in srgb, var(--bb-accent), #000 45%);
    --app-toast-success: color-mix(in srgb, var(--bb-success), #000 25%);
    --app-toast-danger: color-mix(in srgb, var(--bb-danger), #000 10%);
}

/* ------------------------------------------------------------
   2. Visibility gates
   ------------------------------------------------------------
   Layout: .app-viewport-only / .desktop-viewport-only go on BLOCK
   wrappers only (they set display:block). .bb-pwa-phone-only is a
   marker only (feature entry points show everywhere). */
.app-viewport-only {
    display: none !important;
}

@media (max-width: 767.98px), (pointer: coarse) and (max-height: 540px) {
    .app-viewport-only {
        display: block !important;
    }

    .desktop-viewport-only {
        display: none !important;
    }
}

html:not(.bb-standalone) .app-installed-only {
    display: none !important;
}

html.bb-standalone .app-browser-only {
    display: none !important;
}

/* Feature entry points (.bb-pwa-phone-only) show everywhere, desktop
   included: the features run in a browser tab too. The class stays as a
   marker only. */

/* "באפליקציה": marks a feature that needs the installed app on this device
   (only client alerts on iOS) */
.app-pill-app {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    block-size: 18px;
    padding-inline: 7px;
    border-radius: var(--bb-radius-pill);
    background: var(--bb-primary-soft-2);
    color: var(--bb-primary);
    font-size: .625rem;
    font-weight: var(--bb-fw-bold);
    line-height: 1;
    white-space: nowrap;
    vertical-align: middle;
}

html.dark-theme .app-pill-app {
    color: var(--app-accent-text);
}

html.bb-standalone .app-pill-app {
    display: none !important;
}

/* ------------------------------------------------------------
   3. Screen and sections
   ------------------------------------------------------------ */
.app-screen {
    display: flex;
    flex-direction: column;
    gap: 20px;
    inline-size: 100%;
    max-inline-size: 560px;
    margin-inline: auto;
    color: var(--bb-text-body);
    font-size: var(--bb-fs-base);
}

.app-section {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-inline-size: 0;
}

.app-section-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    min-block-size: 32px;
}

.app-section-title,
html.dark-theme .app-section-title {
    margin: 0;
    color: var(--bb-text);
    font-size: 1rem;
    font-weight: var(--bb-fw-bold);
    line-height: var(--bb-lh-tight);
    letter-spacing: 0;
}

/* 32px row, 44px tap area */
.app-section-link {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    min-block-size: var(--app-tap);
    margin-block: -6px;
    margin-inline-end: -8px;
    padding-inline: 8px;
    border-radius: var(--bb-radius-sm);
    color: var(--bb-primary);
    font-size: var(--bb-fs-sm);
    font-weight: var(--bb-fw-semibold);
    white-space: nowrap;
}

.app-section-link:hover {
    color: var(--bb-primary-hover);
}

.app-section-link:active {
    background: var(--app-press-bg);
}

.app-section-link .bi {
    font-size: .75rem;
}

/* ------------------------------------------------------------
   4. Cards, hero, chips
   ------------------------------------------------------------ */
.app-card {
    position: relative;
    display: block;
    padding: 14px 16px;
    border: 1px solid var(--bb-border);
    border-radius: var(--app-radius);
    background: var(--bb-surface);
    box-shadow: var(--app-shadow-rest);
    color: var(--bb-text-body);
}

.app-card--tint {
    border-color: color-mix(in srgb, var(--bb-primary) 20%, transparent);
    background: var(--bb-primary-soft);
    box-shadow: none;
}

/* A tone bar on the inline-start edge; the tone is --app-card-tone */
.app-card--attention {
    border-inline-start: 4px solid var(--app-card-tone, var(--bb-warning));
}

.app-card--flush {
    padding: 0;
    overflow: hidden;
}

.app-card-title,
html.dark-theme .app-card-title {
    margin: 0;
    color: var(--bb-text);
    font-size: .9375rem;
    font-weight: var(--bb-fw-bold);
    line-height: var(--bb-lh-tight);
}

.app-card-text {
    color: var(--bb-text-muted);
    font-size: var(--bb-fs-sm);
    line-height: var(--bb-lh-base);
}

.app-hero {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 18px;
    border-radius: var(--app-radius-lg);
    background: var(--app-hero-bg);
    color: var(--app-hero-fg);
    box-shadow: 0 10px 24px -14px color-mix(in srgb, var(--bb-primary) 70%, transparent);
    overflow: hidden;
}

.app-hero-label {
    color: var(--app-hero-muted);
    font-size: var(--bb-fs-sm);
    font-weight: var(--bb-fw-semibold);
    line-height: 1.3;
}

.app-hero h2,
.app-hero h3,
html.dark-theme .app-hero h2,
html.dark-theme .app-hero h3 {
    margin: 0;
    color: var(--app-hero-fg);
}

.app-hero-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    block-size: 26px;
    padding-inline: 10px;
    border-radius: var(--bb-radius-pill);
    background: var(--app-hero-chip-bg);
    color: var(--app-hero-fg);
    font-size: var(--bb-fs-xs);
    font-weight: var(--bb-fw-semibold);
    white-space: nowrap;
}

.app-hero-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-block-size: var(--app-tap);
    padding: 0 16px;
    border: 0;
    border-radius: var(--app-radius-sm);
    background: var(--app-hero-btn-bg);
    color: var(--app-hero-fg);
    font: inherit;
    font-size: .9rem;
    font-weight: var(--bb-fw-semibold);
    text-decoration: none;
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    transition: transform 80ms var(--bb-ease), background-color var(--bb-fast) var(--bb-ease);
}

.app-hero-btn:hover {
    color: var(--app-hero-fg);
}

/* The primary hero action: surface fill, brand text */
.app-hero-btn--primary,
.app-hero-btn--primary:hover {
    background: var(--bb-surface);
    color: var(--bb-primary);
}

.app-hero-btn:focus-visible {
    outline: 2px solid var(--app-hero-fg);
    outline-offset: 2px;
}

.app-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    block-size: 24px;
    padding-inline: 9px;
    border-radius: var(--bb-radius-pill);
    background: var(--bb-surface-3);
    color: var(--app-chip-neutral-text);
    font-size: var(--bb-fs-xs);
    font-weight: var(--bb-fw-semibold);
    line-height: 1;
    white-space: nowrap;
}

.app-chip .bi {
    font-size: .8em;
}

.app-chip--success { background: var(--bb-success-soft); color: var(--app-chip-success-text); }
.app-chip--warning { background: var(--bb-warning-soft); color: var(--app-chip-warning-text); }
.app-chip--danger  { background: var(--bb-danger-soft);  color: var(--app-chip-danger-text); }
.app-chip--info    { background: var(--bb-info-soft);    color: var(--app-chip-info-text); }
.app-chip--accent  { background: var(--bb-primary-soft); color: var(--bb-primary); }
.app-chip--neutral { background: var(--bb-surface-3);    color: var(--app-chip-neutral-text); }
.app-chip--on-brand { background: var(--app-hero-chip-bg); color: var(--app-hero-fg); }

html.dark-theme .app-chip--accent {
    color: var(--app-accent-text);
}

/* ------------------------------------------------------------
   5. Tiles (4 across, 3 on very narrow phones)
   ------------------------------------------------------------ */
.app-tile-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 10px;
    margin: 0;
    padding: 0;
    list-style: none;
}

@media (max-width: 339.98px) {
    .app-tile-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

.app-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 7px;
    inline-size: 100%;
    min-block-size: var(--app-tile-h);
    margin: 0;
    padding: 12px 4px 10px;
    border: 1px solid var(--bb-border);
    border-radius: var(--app-radius);
    background: var(--bb-surface);
    box-shadow: var(--app-shadow-rest);
    color: var(--bb-text);
    font: inherit;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    transition: transform 80ms var(--bb-ease), background-color var(--bb-fast) var(--bb-ease),
                border-color var(--bb-fast) var(--bb-ease);
}

.app-tile:hover,
.app-tile:focus {
    color: var(--bb-text);
}

.app-tile-icon {
    display: grid;
    place-items: center;
    inline-size: 40px;
    block-size: 40px;
    flex: none;
    border-radius: var(--app-radius-sm);
    background: var(--bb-primary-soft);
    color: var(--bb-primary);
    font-size: 1.25rem;
    line-height: 1;
}

.app-tile-label {
    display: -webkit-box;
    max-inline-size: 100%;
    overflow: hidden;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    font-size: .78rem;
    font-weight: var(--bb-fw-semibold);
    line-height: 1.2;
}

.app-tile-sub {
    margin-block-start: -4px;
    color: var(--bb-text-muted);
    font-size: .6875rem;
    font-weight: var(--bb-fw-medium);
    line-height: 1.2;
}

/* The one filled tile of a grid */
.app-tile--primary,
.app-tile--primary:hover,
.app-tile--primary:focus {
    border-color: transparent;
    background: var(--app-fill);
    color: var(--app-on-fill);
}

.app-tile--primary .app-tile-icon {
    background: color-mix(in srgb, var(--app-on-fill) 18%, transparent);
    color: var(--app-on-fill);
}

.app-tile--primary .app-tile-sub {
    color: color-mix(in srgb, var(--app-on-fill) 80%, transparent);
}

/* Installed-only pill on a tile sits at the top inline-start corner */
.app-tile > .app-pill-app {
    position: absolute;
    inset-block-start: 6px;
    inset-inline-start: 6px;
}

/* Count badge at the top inline-end corner, ringed by the surface */
.app-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-inline-size: 20px;
    block-size: 20px;
    padding-inline: 6px;
    border-radius: var(--bb-radius-pill);
    background: var(--bb-danger);
    box-shadow: 0 0 0 2px var(--bb-surface);
    color: var(--bb-on-primary);
    font-size: .6875rem;
    font-weight: var(--bb-fw-bold);
    font-variant-numeric: tabular-nums;
    line-height: 1;
}

.app-tile > .app-badge {
    position: absolute;
    inset-block-start: 6px;
    inset-inline-end: 6px;
}

.app-badge[hidden] {
    display: none;
}

/* ------------------------------------------------------------
   6. Avatars
   ------------------------------------------------------------ */
.app-avatar {
    position: relative;
    display: inline-grid;
    place-items: center;
    flex: none;
    inline-size: var(--app-avatar-size, var(--app-avatar-md));
    block-size: var(--app-avatar-size, var(--app-avatar-md));
    border-radius: 50%;
    background: var(--bb-surface-3);
    vertical-align: middle;
}

.app-avatar--sm { --app-avatar-size: var(--app-avatar-sm); }
.app-avatar--md { --app-avatar-size: var(--app-avatar-md); }
.app-avatar--lg { --app-avatar-size: var(--app-avatar-lg); }
.app-avatar--xl { --app-avatar-size: var(--app-avatar-xl); }

.app-avatar > img {
    position: absolute;
    inset: 0;
    inline-size: 100%;
    block-size: 100%;
    border-radius: 50%;
    object-fit: cover;
    background: var(--bb-surface-3);
}

/* Initial under the photo: shows while it loads and when it is missing or broken */
.app-avatar-fallback {
    display: grid;
    place-items: center;
    inline-size: 100%;
    block-size: 100%;
    border-radius: 50%;
    background: var(--bb-primary-soft-2);
    color: var(--bb-primary);
    font-size: calc(var(--app-avatar-size, var(--app-avatar-md)) * .42);
    font-weight: var(--bb-fw-bold);
    line-height: 1;
    user-select: none;
}

html.dark-theme .app-avatar-fallback {
    color: var(--app-accent-text);
}

.app-avatar.is-broken > img {
    display: none;
}

.app-avatar--ring {
    box-shadow: 0 0 0 2px var(--bb-surface), 0 0 0 4px var(--bb-primary);
}

/* Status dot at the bottom inline-end, ringed by the surface. Colour is
   never alone: the component adds visually hidden text. */
.app-dot {
    position: absolute;
    inset-block-end: 0;
    inset-inline-end: 0;
    inline-size: var(--app-dot);
    block-size: var(--app-dot);
    border: 2px solid var(--bb-surface);
    border-radius: 50%;
    background: var(--bb-text-subtle);
}

.app-avatar--sm .app-dot {
    inline-size: 10px;
    block-size: 10px;
}

.app-avatar--xl .app-dot {
    inline-size: 16px;
    block-size: 16px;
    inset-block-end: 2px;
    inset-inline-end: 2px;
}

.app-dot--ok   { background: var(--bb-success); }
.app-dot--warn { background: var(--bb-warning); }
.app-dot--bad  { background: var(--bb-danger); }
.app-dot--none { background: var(--bb-text-subtle); }

.app-avatar-stack {
    display: inline-flex;
    align-items: center;
}

.app-avatar-stack > .app-avatar {
    box-shadow: 0 0 0 2px var(--bb-surface);
}

.app-avatar-stack > .app-avatar + .app-avatar {
    margin-inline-start: -10px;
}

.app-avatar-row {
    display: flex;
    gap: 14px;
    margin-inline: calc(var(--app-gutter) * -1);
    padding-block: 4px;
    padding-inline: var(--app-gutter);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--app-gutter);
    scrollbar-width: none;
}

.app-avatar-row::-webkit-scrollbar {
    display: none;
}

.app-avatar-row > * {
    flex: none;
    scroll-snap-align: start;
}

/* ------------------------------------------------------------
   7. Lists (56px rows, hairline separators)
   ------------------------------------------------------------ */
.app-list {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 0;
    list-style: none;
}

.app-list > li {
    margin: 0;
}

.app-list > li + li,
.app-list > .app-list-row + .app-list-row {
    border-block-start: 1px solid var(--bb-border);
}

.app-list-row {
    display: flex;
    align-items: center;
    gap: 12px;
    inline-size: 100%;
    min-block-size: 56px;
    padding: 8px 16px;
    border: 0;
    background: transparent;
    color: var(--bb-text-body);
    font: inherit;
    text-align: start;
    text-decoration: none;
}

a.app-list-row,
button.app-list-row {
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    transition: background-color var(--bb-fast) var(--bb-ease);
}

a.app-list-row:hover,
button.app-list-row:hover {
    color: var(--bb-text-body);
}

a.app-list-row:active,
button.app-list-row:active {
    background: var(--app-press-bg);
}

.app-list-main {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 2px;
    min-inline-size: 0;
}

.app-list-title {
    overflow: hidden;
    color: var(--bb-text);
    font-size: .9375rem;
    font-weight: var(--bb-fw-semibold);
    line-height: 1.3;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.app-list-sub {
    overflow: hidden;
    color: var(--bb-text-muted);
    font-size: var(--bb-fs-sm);
    line-height: 1.35;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.app-list-end {
    display: inline-flex;
    flex: none;
    align-items: center;
    gap: 6px;
    color: var(--bb-text-muted);
    font-size: var(--bb-fs-sm);
}

/* ------------------------------------------------------------
   8. Sheet actions (56px rows with an icon bubble)
   ------------------------------------------------------------ */
.app-action-list {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.app-action {
    display: flex;
    align-items: center;
    gap: 14px;
    inline-size: 100%;
    min-block-size: 56px;
    margin: 0;
    padding: 8px 10px;
    border: 0;
    border-radius: 14px;
    background: transparent;
    color: var(--bb-text);
    font: inherit;
    text-align: start;
    text-decoration: none;
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    transition: transform 80ms var(--bb-ease), background-color var(--bb-fast) var(--bb-ease);
}

.app-action:hover,
.app-action:focus {
    color: var(--bb-text);
}

.app-action-icon {
    display: grid;
    place-items: center;
    inline-size: 40px;
    block-size: 40px;
    flex: none;
    border-radius: var(--app-radius-sm);
    background: var(--bb-primary-soft);
    color: var(--bb-primary);
    font-size: 1.15rem;
    line-height: 1;
}

.app-action-text {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 2px;
    min-inline-size: 0;
}

.app-action-label {
    font-size: .9375rem;
    font-weight: var(--bb-fw-semibold);
    line-height: 1.3;
}

.app-action-sub {
    color: var(--bb-text-muted);
    font-size: var(--bb-fs-sm);
    line-height: 1.35;
}

.app-action-chevron {
    flex: none;
    color: var(--bb-text-subtle);
    font-size: .85rem;
}

[dir="ltr"] .app-action-chevron {
    transform: scaleX(-1);
}

.app-action--danger,
.app-action--danger:hover,
.app-action--danger:focus {
    color: var(--app-chip-danger-text);
}

.app-action--danger .app-action-icon {
    background: var(--bb-danger-soft);
    color: var(--app-chip-danger-text);
}

/* Press feedback (tiles, actions, list rows). Hover only where there is hover. */
.app-tile:active {
    background: var(--app-press-surface);
}

.app-action:active {
    background: var(--app-press-bg);
}

.app-tile--primary:active {
    background: var(--app-fill-active);
}

@media (prefers-reduced-motion: no-preference) {
    .app-tile:active,
    .app-action:active,
    .app-hero-btn:active,
    .app-btn:active {
        transform: scale(var(--app-press));
    }
}

@media (hover: hover) {
    .app-tile:hover {
        border-color: color-mix(in srgb, var(--bb-primary) 30%, var(--bb-border));
    }

    .app-tile--primary:hover {
        background: var(--app-fill-hover);
    }

    .app-action:hover,
    a.app-list-row:hover,
    button.app-list-row:hover {
        background: var(--bb-surface-3);
    }
}

/* ------------------------------------------------------------
   9. Empty state, skeleton, progress
   ------------------------------------------------------------ */
.app-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 28px 16px;
    text-align: center;
}

.app-empty-icon {
    display: grid;
    place-items: center;
    inline-size: 56px;
    block-size: 56px;
    margin-block-end: 6px;
    border-radius: 50%;
    background: var(--bb-primary-soft);
    color: var(--bb-primary);
    font-size: 1.5rem;
    line-height: 1;
}

.app-empty-title,
html.dark-theme .app-empty-title {
    margin: 0;
    color: var(--bb-text);
    font-size: .9375rem;
    font-weight: var(--bb-fw-bold);
    line-height: var(--bb-lh-tight);
}

.app-empty-text {
    max-inline-size: 32ch;
    color: var(--bb-text-muted);
    font-size: var(--bb-fs-sm);
    line-height: var(--bb-lh-base);
}

.app-empty > .app-btn {
    margin-block-start: 10px;
}

.app-skeleton {
    display: block;
    border-radius: var(--bb-radius-sm);
    background: var(--bb-surface-3);
    animation: app-skeleton-pulse 1.2s ease-in-out infinite;
}

.app-skeleton--line {
    inline-size: 100%;
    block-size: 12px;
    border-radius: var(--bb-radius-pill);
}

.app-skeleton--line.is-short { inline-size: 45%; }
.app-skeleton--line.is-mid { inline-size: 70%; }

.app-skeleton--circle {
    inline-size: 40px;
    block-size: 40px;
    flex: none;
    border-radius: 50%;
}

.app-skeleton--block {
    inline-size: 100%;
    block-size: 72px;
    border-radius: var(--app-radius);
}

/* Skeleton layouts rendered by <x-app.skeleton> */
.app-skeleton-group {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.app-skeleton-row {
    display: flex;
    align-items: center;
    gap: 12px;
}

.app-skeleton-lines {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 8px;
}

@keyframes app-skeleton-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: .55; }
}

@media (prefers-reduced-motion: reduce) {
    .app-skeleton {
        animation: none;
    }
}

.app-progress {
    block-size: 6px;
    overflow: hidden;
    border-radius: var(--bb-radius-pill);
    background: color-mix(in srgb, var(--app-hero-fg) 24%, transparent);
}

.app-progress-bar {
    inline-size: var(--app-progress, 0%);
    block-size: 100%;
    border-radius: inherit;
    background: var(--app-hero-fg);
    transition: inline-size var(--app-dur) var(--bb-ease);
}

/* On a plain surface instead of the hero */
.app-progress--surface {
    background: var(--bb-surface-3);
}

.app-progress--surface .app-progress-bar {
    background: var(--bb-primary);
}

/* ------------------------------------------------------------
   10. Segmented control (roving tabindex in app-ui.js)
   ------------------------------------------------------------ */
.app-seg {
    display: flex;
    gap: 2px;
    padding: 3px;
    border-radius: 13px;
    background: var(--bb-surface-3);
}

.app-seg-btn {
    display: inline-flex;
    flex: 1 1 0;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-inline-size: 0;
    min-block-size: 38px;
    padding: 0 10px;
    border: 0;
    border-radius: 10px;
    background: transparent;
    color: var(--bb-text-muted);
    font: inherit;
    font-size: var(--bb-fs-sm);
    font-weight: var(--bb-fw-semibold);
    white-space: nowrap;
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    transition: background-color var(--bb-fast) var(--bb-ease), color var(--bb-fast) var(--bb-ease),
                box-shadow var(--bb-fast) var(--bb-ease);
}

.app-seg-btn[aria-selected="true"] {
    background: var(--bb-surface);
    box-shadow: var(--app-shadow-seg);
    color: var(--bb-text);
}

html.dark-theme .app-seg-btn[aria-selected="true"] {
    background: var(--bb-surface-2);
}

.app-seg-btn .app-badge {
    min-inline-size: 18px;
    block-size: 18px;
    box-shadow: none;
    background: var(--bb-primary-soft-2);
    color: var(--bb-primary);
}

/* ------------------------------------------------------------
   11. Buttons, install prompts
   ------------------------------------------------------------ */
.app-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-block-size: 48px;
    padding: 0 18px;
    border: 1px solid transparent;
    border-radius: 14px;
    background: var(--bb-surface-3);
    color: var(--bb-text);
    font: inherit;
    font-size: .9375rem;
    font-weight: var(--bb-fw-semibold);
    line-height: 1.2;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
    user-select: none;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    transition: transform 80ms var(--bb-ease), background-color var(--bb-fast) var(--bb-ease),
                color var(--bb-fast) var(--bb-ease);
}

.app-btn:hover,
.app-btn:focus {
    color: var(--bb-text);
}

.app-btn .bi {
    font-size: 1.1em;
}

.app-btn[hidden] {
    display: none;
}

.app-btn--primary,
.app-btn--primary:hover,
.app-btn--primary:focus {
    background: var(--app-fill);
    color: var(--app-on-fill);
}

.app-btn--primary:active {
    background: var(--app-fill-active);
}

.app-btn--secondary,
.app-btn--secondary:hover,
.app-btn--secondary:focus {
    border-color: var(--bb-border-strong);
    background: var(--bb-surface);
    color: var(--bb-text);
}

.app-btn--ghost,
.app-btn--ghost:hover,
.app-btn--ghost:focus {
    background: transparent;
    color: var(--bb-text-muted);
}

.app-btn--block {
    display: flex;
    inline-size: 100%;
}

@media (hover: hover) {
    .app-btn--primary:hover { background: var(--app-fill-hover); }
    .app-btn--secondary:hover,
    .app-btn--ghost:hover { background: var(--bb-surface-3); }
}

/* Install CTA (<x-app.install-cta>): starts hidden, app-ui.js reveals it on a
   feature surface outside the installed app */
.app-install-cta[hidden] {
    display: none !important;
}

.app-install-cta {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 16px;
    border: 1px solid color-mix(in srgb, var(--bb-primary) 22%, transparent);
    border-radius: var(--app-radius);
    background: var(--bb-primary-soft);
    color: var(--bb-text-body);
}

.app-install-cta-icon {
    flex: none;
    inline-size: 48px;
    block-size: 48px;
    border-radius: 12px;
    background: var(--bb-surface);
    box-shadow: 0 2px 8px -2px color-mix(in srgb, var(--bb-primary) 45%, transparent);
}

.app-install-cta-main {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

.app-install-cta-title,
html.dark-theme .app-install-cta-title {
    margin: 0;
    color: var(--bb-text);
    font-size: .9375rem;
    font-weight: var(--bb-fw-bold);
    line-height: 1.3;
}

.app-install-cta-text {
    color: var(--bb-text-muted);
    font-size: var(--bb-fs-sm);
    line-height: var(--bb-lh-base);
}

.app-install-cta-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-block-start: 8px;
}

.app-install-cta-actions .app-btn {
    min-block-size: 44px;
    padding-inline: 16px;
    font-size: .875rem;
}

.app-install-cta-close {
    display: grid;
    place-items: center;
    flex: none;
    inline-size: 36px;
    block-size: 36px;
    margin-block: -6px;
    margin-inline-end: -6px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--bb-text-muted);
    font-size: 1rem;
    cursor: pointer;
    touch-action: manipulation;
}

.app-install-cta-close:active {
    background: var(--app-press-bg);
}

/* Inline variant: one compact row */
.app-install-cta--inline {
    align-items: center;
    padding: 10px 12px;
}

.app-install-cta--inline .app-install-cta-icon {
    inline-size: 36px;
    block-size: 36px;
    border-radius: 9px;
}

.app-install-cta--inline .app-install-cta-text {
    display: none;
}

.app-install-cta--inline .app-install-cta-actions {
    margin: 0;
}

/* The install sheet (partials/pwa/feature-gate) */
.app-install-intro {
    display: flex;
    align-items: center;
    gap: 14px;
    padding-block: 4px 14px;
}

.app-install-icon {
    flex: none;
    inline-size: 60px;
    block-size: 60px;
    border-radius: 15px;
    background: var(--bb-surface);
    box-shadow: 0 0 0 1px var(--bb-border), 0 6px 16px -6px color-mix(in srgb, var(--bb-primary) 55%, transparent);
}

.app-install-body {
    color: var(--bb-text-body);
    font-size: .9375rem;
    line-height: var(--bb-lh-base);
}

.app-install-steps {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin: 0 0 4px;
    padding: 6px;
    border-radius: var(--app-radius);
    background: var(--bb-surface-2);
    list-style: none;
    counter-reset: app-step;
}

html.dark-theme .app-install-steps {
    background: color-mix(in srgb, var(--bb-bg) 60%, var(--bb-surface));
}

.app-install-steps[hidden],
.app-install-note[hidden] {
    display: none;
}

.app-install-steps-title,
html.dark-theme .app-install-steps-title {
    margin: 4px 0 8px;
    color: var(--bb-text);
    font-size: var(--bb-fs-sm);
    font-weight: var(--bb-fw-bold);
}

.app-install-step {
    display: flex;
    align-items: center;
    gap: 12px;
    min-block-size: 48px;
    padding: 6px 8px;
    color: var(--bb-text);
    font-size: .9375rem;
    line-height: 1.35;
    counter-increment: app-step;
}

.app-install-step::before {
    content: counter(app-step);
    display: grid;
    place-items: center;
    flex: none;
    inline-size: 28px;
    block-size: 28px;
    border-radius: 50%;
    background: var(--bb-primary-soft-2);
    color: var(--bb-primary);
    font-size: var(--bb-fs-sm);
    font-weight: var(--bb-fw-bold);
}

html.dark-theme .app-install-step::before {
    color: var(--app-accent-text);
}

/* The iOS share and add glyphs, drawn like the system ones */
.app-install-glyph {
    display: inline-grid;
    place-items: center;
    inline-size: 30px;
    block-size: 30px;
    flex: none;
    margin-inline-start: auto;
    border-radius: 8px;
    background: var(--bb-surface);
    box-shadow: 0 0 0 1px var(--bb-border);
    color: var(--bb-info);
    font-size: 1rem;
}

.app-install-glyph svg {
    inline-size: 18px;
    block-size: 18px;
    fill: currentColor;
}

.app-install-note {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px 14px;
    border-radius: var(--app-radius-sm);
    background: var(--bb-surface-2);
    color: var(--bb-text-body);
    font-size: var(--bb-fs-sm);
    line-height: var(--bb-lh-base);
}

.app-install-note .bi {
    flex: none;
    color: var(--bb-primary);
    font-size: 1.1rem;
    line-height: 1.3;
}

.app-install-sheet [data-bb-gate-steps],
.app-install-sheet .app-install-note {
    margin-block-end: 12px;
}

.app-install-fineprint {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--bb-text-muted);
    font-size: var(--bb-fs-xs);
    line-height: 1.4;
}

.app-install-fineprint .bi {
    flex: none;
    color: var(--app-chip-success-text);
    font-size: .95rem;
}

.app-install-glyph img {
    inline-size: 20px;
    block-size: 20px;
    border-radius: 5px;
}

/* ------------------------------------------------------------
   12. Bottom sheet (<x-app.sheet>: a Bootstrap modal)
   ------------------------------------------------------------
   The dialog carries .bb-sheet-off, so mobile-polish's generic sheet
   rules (and their ::before handle) stay out of the way: the kit
   draws its own grab zone, which is also the drag handle.
   Phone layout: a bottom sheet (max 88dvh, rounded top corners,
   slides up, drags down to close). Wider: a centred modal. */
.app-sheet .modal-content,
html.dark-theme .app-sheet .modal-content {
    display: flex;
    flex-direction: column;
    max-block-size: calc(100dvh - 2 * var(--bs-modal-margin, .5rem));
    overflow: hidden;
    border: 1px solid var(--bb-border);
    border-radius: var(--app-radius-lg);
    background: var(--bb-surface);
    box-shadow: var(--app-shadow-float);
    color: var(--bb-text-body);
}

.app-sheet-grab {
    display: none;
}

.app-sheet-header {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 18px 20px 10px;
}

.app-sheet-heading {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 3px;
    min-inline-size: 0;
    padding-block-start: 5px;
}

.app-sheet-title,
html.dark-theme .app-sheet-title {
    margin: 0;
    color: var(--bb-text);
    font-size: 1.125rem;
    font-weight: var(--bb-fw-bold);
    line-height: 1.3;
    letter-spacing: 0;
}

.app-sheet-subtitle {
    color: var(--bb-text-muted);
    font-size: var(--bb-fs-sm);
    line-height: 1.4;
}

/* Close: a quiet 36px circle with a 44px tap area */
.app-sheet .btn-close,
html.dark-theme .app-sheet .btn-close {
    position: relative;
    display: grid;
    place-items: center;
    flex: none;
    inline-size: 36px;
    block-size: 36px;
    margin: 0;
    padding: 0;
    border-radius: 50%;
    background: var(--bb-surface-3);
    background-image: none;
    color: var(--bb-text-muted);
    font-size: .95rem;
    opacity: 1;
    filter: none;
    box-shadow: none;
}

.app-sheet .btn-close::after {
    content: '';
    position: absolute;
    inset: -4px;
}

.app-sheet .btn-close:hover {
    color: var(--bb-text);
}

.app-sheet .btn-close:focus-visible {
    outline: 2px solid var(--bb-primary);
    outline-offset: 2px;
}

.app-sheet-body {
    flex: 1 1 auto;
    min-block-size: 0;
    padding: 6px 20px 20px;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    color: var(--bb-text-body);
}

/* Action rows reach the sheet edges' visual gutter */
.app-sheet-body > .app-action-list {
    margin-inline: -10px;
}

.app-sheet-footer {
    display: flex;
    flex: none;
    flex-direction: column;
    gap: 8px;
    padding: 12px 20px 16px;
    border-block-start: 1px solid var(--bb-border);
}

.app-sheet-footer:empty {
    display: none;
}

/* Softer scrim while a kit sheet is up */
body.app-sheet-open .modal-backdrop.show {
    opacity: .42;
}

/* The accessibility button (privacy-a11y.js, z-index 999995) would float over
   the sheet's footer and take its taps. The sheet is modal - its focus trap
   keeps the button out of reach anyway - and the button is back as soon as
   the sheet closes. */
body.app-sheet-open .a11y-trigger-btn {
    visibility: hidden;
}

/* Phones with the tab bar: while the page scrolls down (app-ui.js,
   body.app-scrolled-down) the button slides off the left edge, where list rows
   keep their main action; any scroll up brings it back. Never while its panel
   is open or it has keyboard focus. Physical `left`: privacy-a11y.js pins it
   there in both directions. */
body.pwa-nav-shown.app-scrolled-down:not(:has(#a11y-panel[style*="block"])) .a11y-trigger-btn:not(:focus-visible) {
    transform: translateX(calc(-100% - 44px));
}

@media (max-width: 767.98px), (pointer: coarse) and (max-height: 540px) {
    .modal.app-sheet {
        --bs-modal-margin: 0;
    }

    .modal.app-sheet .app-sheet-dialog {
        position: fixed;
        inset-inline: 0;
        inset-block-end: 0;
        inset-block-start: auto;
        display: flex;
        align-items: flex-end;
        inline-size: 100%;
        max-inline-size: 560px;
        min-block-size: 0;
        margin: 0 auto;
        transform: translateY(100%);
        transition: transform var(--app-sheet-dur) var(--app-ease-out);
        will-change: transform;
    }

    .modal.app-sheet.show .app-sheet-dialog {
        transform: none;
    }

    /* The page behind stays put; only the scrim fades */
    .modal.app-sheet.fade {
        transition: opacity var(--app-sheet-dur) linear;
    }

    .modal.app-sheet.fade:not(.show) {
        opacity: 1;
    }

    .modal.app-sheet.is-dragging .app-sheet-dialog {
        transition: none;
    }

    .app-sheet .modal-content,
    html.dark-theme .app-sheet .modal-content {
        inline-size: 100%;
        max-block-size: calc(88dvh - env(safe-area-inset-top, 0px));
        border: 0;
        border-radius: var(--app-radius-lg) var(--app-radius-lg) 0 0;
        box-shadow: var(--app-shadow-sheet);
    }

    /* The grab zone and the header are the drag handle */
    .app-sheet-grab {
        display: flex;
        flex: none;
        justify-content: center;
        block-size: 22px;
        padding-block-start: 9px;
        cursor: grab;
        touch-action: none;
    }

    .app-sheet-grab::before {
        content: '';
        inline-size: 38px;
        block-size: 5px;
        border-radius: var(--bb-radius-pill);
        background: var(--bb-border-strong);
    }

    .app-sheet-header {
        padding: 4px 20px 10px;
        touch-action: none;
    }

    .app-sheet-body {
        padding-inline: 16px;
    }

    .app-sheet-body > .app-action-list {
        margin-inline: -6px;
    }

    .app-sheet-body:last-child {
        padding-block-end: calc(20px + env(safe-area-inset-bottom, 0px));
    }

    .app-sheet-footer {
        padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px));
    }
}

@media (prefers-reduced-motion: reduce) {
    .modal.app-sheet .app-sheet-dialog,
    .modal.app-sheet.fade {
        transition: none !important;
    }
}

/* The booking skeleton sheet (bbAppUi.sheet.loading): no scrim fade, it
   hands over to the booking form without a flash */
.app-sheet--loading .app-sheet-body {
    padding-block-start: 10px;
}

/* ------------------------------------------------------------
   13. Toast and the shared live region
   ------------------------------------------------------------ */
/* Physical left on purpose: the accessibility button (privacy-a11y.js) is
   a fixed 60px circle at the bottom LEFT in both directions, so the toast
   keeps clear of it rather than covering it or being covered */
.app-toast {
    position: fixed;
    left: 88px;
    right: 12px;
    inset-block-end: calc(max(var(--pwa-nav-h, 0px), env(safe-area-inset-bottom, 0px)) + 12px);
    z-index: 1058;
    display: flex;
    align-items: center;
    gap: 10px;
    max-inline-size: 440px;
    min-block-size: 48px;
    margin-inline: auto;
    padding: 10px 16px;
    border-radius: 14px;
    background: var(--app-toast-bg);
    box-shadow: var(--app-shadow-float);
    color: var(--app-toast-fg);
    font-size: .875rem;
    font-weight: var(--bb-fw-medium);
    line-height: 1.4;
    opacity: 0;
    transform: translateY(12px);
    transition: opacity .18s var(--bb-ease), transform .22s var(--app-ease-out);
    pointer-events: none;
}

.app-toast.is-visible {
    opacity: 1;
    transform: none;
    pointer-events: auto;
}

.app-toast-icon {
    flex: none;
    font-size: 1.1rem;
    line-height: 1;
}

.app-toast--success .app-toast-icon { color: var(--app-toast-success); }
.app-toast--danger .app-toast-icon { color: var(--app-toast-danger); }

.app-toast-text {
    flex: 1 1 auto;
    min-inline-size: 0;
}

.app-toast-action {
    flex: none;
    min-block-size: 40px;
    margin-block: -6px;
    margin-inline-end: -8px;
    padding: 0 12px;
    border: 0;
    border-radius: 10px;
    background: transparent;
    color: var(--app-toast-action);
    font: inherit;
    font-weight: var(--bb-fw-bold);
    cursor: pointer;
    touch-action: manipulation;
}

.app-toast-action:active {
    background: color-mix(in srgb, var(--app-toast-fg) 12%, transparent);
}

.app-toast-action:focus-visible {
    outline: 2px solid var(--app-toast-action);
    outline-offset: 0;
}

@media (prefers-reduced-motion: reduce) {
    .app-toast {
        transform: none;
        transition: opacity .12s linear;
    }
}

@media print {
    .app-toast {
        display: none !important;
    }
}

/* ------------------------------------------------------------
   14. Phone header fix (BEFORE bug: the account avatar was pushed off
   the screen edge on the staff header). Dot and chevron of the shift
   pill stay; its label and clock go. The refresh button goes while the
   tab bar is shown: the bar and pull-to-refresh cover it.
   ------------------------------------------------------------ */
@media (max-width: 767.98px), (pointer: coarse) and (max-height: 540px) {
    .top-header .navbar { gap: .5rem !important; }
    .top-header .top-navbar-right .navbar-nav { gap: 0 !important; }
    .top-header .shift-status-label, .top-header .js-shift-clock { display: none; }
    body.pwa-nav-shown #pwa-refresh-btn { display: none !important; }
    .top-header .dropdown-user-setting { flex-shrink: 0; }
}

/* ------------------------------------------------------------
   15. Page transitions (phones only, never under reduced motion).
   The opt-in, @view-transition { navigation: auto }, is an inline style
   at the very top of layouts/app's <head>, under the same media query:
   Chrome settles whether the incoming page takes part while it parses
   the head, before this file has loaded, so here it was never seen.
   Rollback: delete that style and this block.
   ------------------------------------------------------------ */
@media (max-width: 767.98px) and (prefers-reduced-motion: no-preference),
       (pointer: coarse) and (max-height: 540px) and (prefers-reduced-motion: no-preference) {
    ::view-transition-old(root), ::view-transition-new(root) { animation-duration: 180ms; }
    ::view-transition-old(root) { animation-name: app-vt-out; animation-timing-function: cubic-bezier(.4, 0, .2, 1); }
    ::view-transition-new(root) { animation-name: app-vt-in; animation-timing-function: cubic-bezier(.4, 0, .2, 1); }
    .top-header { view-transition-name: bb-header; }
    .pwa-bottom-nav { view-transition-name: bb-tabbar; }
    #bb-offline-bar { view-transition-name: bb-offline; }
}

@keyframes app-vt-out {
    to { opacity: 0; }
}

@keyframes app-vt-in {
    from { opacity: 0; transform: translateY(6px); }
}
