/* ==========================================================================
   components.css — the reusable UI kit.
   One card system, one glass recipe, one icon scale, one motion curve.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Icons — a single scale so every glyph reads at the same weight.
   -------------------------------------------------------------------------- */
.icon {
    width: 20px;
    height: 20px;
    flex: none;
}

/* --------------------------------------------------------------------------
   Card system
   Two tiers, both from the same recipe:
   full-width cards pad with --space-5, two-up cards with --space-4.
   -------------------------------------------------------------------------- */
.card {
    position: relative;
    padding: var(--space-5);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-card);
    background: var(--surface-gradient);
    -webkit-backdrop-filter: blur(var(--blur-card)) saturate(130%);
    backdrop-filter: blur(var(--blur-card)) saturate(130%);
    box-shadow: var(--shadow-inset), var(--shadow-card);
    overflow: hidden;
}

/* A single restrained highlight along the top edge. */
.card::before {
    content: "";
    position: absolute;
    inset-inline: 12%;
    top: 0;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.28), transparent);
    pointer-events: none;
}

/* Quieter surfaces for the supporting blocks. */
.card--patterns,
.card--recommendation,
.card--leaderboard {
    background: var(--surface-gradient-quiet);
    border-color: var(--glass-border-soft);
    box-shadow: var(--shadow-inset), 0 10px 24px rgba(0, 0, 0, 0.14);
}

.card--hero {
    padding-block: var(--space-5);
    text-align: center;
}

.card__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    text-align: left;
}

.card__head--compact {
    justify-content: flex-start;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

.card__headings { min-width: 0; }

.card__title {
    font-size: var(--fs-section);
    font-weight: 600;
    letter-spacing: -0.02em;
}

.card__eyebrow {
    font-size: var(--fs-label);
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--text-primary);
}

.card__caption {
    font-size: var(--fs-tiny);
    font-weight: 600;
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    color: var(--text-muted);
}

.card__subtitle {
    font-size: 1.0625rem;
    font-weight: 600;
    letter-spacing: -0.015em;
}

.card__subtitle--tight { margin-bottom: var(--space-1); }

.card__meta {
    margin-top: var(--space-1);
    font-size: var(--fs-small);
    color: var(--text-muted);
}

.card__meta--small { font-size: var(--fs-tiny); }

.card__lede {
    margin-inline: auto;
    max-width: 34ch;
    font-size: var(--fs-small);
    color: var(--text-secondary);
}

.card--hero .card__lede { margin-top: var(--space-2); }

.card__lede--small {
    margin-inline: 0;
    max-width: none;
    color: var(--text-muted);
}

.card__hint {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px solid var(--glass-hairline);
    font-size: var(--fs-tiny);
    color: var(--text-muted);
}

.card__hint--plain {
    justify-content: flex-start;
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    text-align: left;
}

.card__hint-icon { width: 14px; height: 14px; }

/* --------------------------------------------------------------------------
   Header
   -------------------------------------------------------------------------- */
.app-header {
    position: sticky;
    top: 0;
    z-index: 20;
    padding-top: calc(var(--safe-top) + var(--space-3));
    padding-bottom: var(--space-3);
    border-bottom: 1px solid transparent;
    transition: background-color var(--transition-fast), border-color var(--transition-fast);
}

/* Scrolled: a solid tint that fades out at the bottom edge, so content
   slides under the header instead of colliding with it. */
.app-header.is-scrolled {
    background: linear-gradient(180deg,
        rgba(48, 45, 47, 0.95) 0%,
        rgba(48, 45, 47, 0.88) 58%,
        rgba(48, 45, 47, 0) 100%);
    -webkit-backdrop-filter: blur(var(--blur-bar)) saturate(140%);
    backdrop-filter: blur(var(--blur-bar)) saturate(140%);
}

.app-header__inner {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: var(--space-3);
}

.app-header__brand { justify-self: center; }

.pill--devices { justify-self: start; }

.app-header__name {
    font-size: var(--fs-brand);
    font-weight: 600;
    letter-spacing: -0.03em;
}

.pill--account { justify-self: end; }

/* --------------------------------------------------------------------------
   Pills + buttons
   -------------------------------------------------------------------------- */
.pill {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-height: 42px;
    padding-inline: var(--space-3);
    border: 1px solid var(--glass-border-soft);
    border-radius: var(--radius-pill);
    background: var(--glass-soft);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
    color: var(--text-secondary);
}

/* The two header buttons: one circle, mirrored left and right of the name,
   cut from the same pane as the tab bar. They read the same tokens, so the
   three cannot drift apart, and each composes its own background — a shared
   rule that set one would have to come last and would silently replace the
   bar's. */
.pill--devices,
.pill--account {
    position: relative;
    isolation: isolate;
    width: var(--header-btn);
    height: var(--header-btn);
    min-height: 0;
    padding-inline: 0;
    justify-content: center;
    border: 0;
    background:
        linear-gradient(177deg,
            rgba(255, 255, 255, 0.115) 0%,
            rgba(255, 255, 255, 0.042) 46%,
            rgba(255, 255, 255, 0.06) 100%),
        rgba(30, 28, 29, 0.46);
    -webkit-backdrop-filter: blur(var(--pane-blur)) saturate(var(--pane-saturate)) brightness(var(--pane-brightness));
    backdrop-filter: blur(var(--pane-blur)) saturate(var(--pane-saturate)) brightness(var(--pane-brightness));
    box-shadow:
        0 8px 20px rgba(0, 0, 0, 0.30),
        inset 0 1px 0 rgba(255, 255, 255, 0.13);
    color: var(--text-primary);
    transition: transform var(--transition-fast), box-shadow var(--transition-fast);
}

/* The same rim as the bar, on a circle. */
.pill--devices::after,
.pill--account::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    padding: 1px;
    background: var(--pane-rim);
    -webkit-mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    mask-composite: exclude;
    pointer-events: none;
}

/* One box for the pair, the same way the tab bar has one box for its five.
   The marks inside are normalised on the grid, so this is all it takes for
   the two to read as the same size. */
.pill--devices .icon,
.pill--account .icon { width: var(--header-icon); height: var(--header-icon); }

/* A press settles the pane rather than shrinking the button. */
.pill--devices:active,
.pill--account:active {
    transform: scale(0.96);
    box-shadow: 0 3px 10px rgba(0, 0, 0, 0.26), inset 0 1px 0 rgba(255, 255, 255, 0.10);
}

.pill--devices > *,
.pill--account > * { position: relative; }

.pill--close { padding-inline: var(--space-2) var(--space-3); }

.pill__icon { width: 18px; height: 18px; }

.pill__label {
    font-size: var(--fs-small);
    font-weight: 500;
}

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 42px;
    padding-inline: var(--space-4);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-pill);
    background: var(--glass);
    color: var(--text-primary);
    font-size: var(--fs-small);
    font-weight: 600;
    transition: background-color var(--transition-fast), transform var(--transition-fast);
}

.btn:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

/* --------------------------------------------------------------------------
   Primary score ring
   -------------------------------------------------------------------------- */
.score-ring {
    position: relative;
    width: min(50vw, 184px);
    aspect-ratio: 1;
    margin: var(--space-4) auto var(--space-3);
}

.score-ring::before {
    content: "";
    position: absolute;
    inset: 18%;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(60, 158, 114, 0.16), transparent 70%);
}

.score-ring__svg {
    width: 100%;
    height: 100%;
    transform: rotate(-90deg);
    overflow: visible;
}

.score-ring__track {
    fill: none;
    stroke: rgba(255, 255, 255, 0.07);
    stroke-width: 10;
}

.score-ring__value {
    fill: none;
    stroke: url(#ringGradient);
    stroke-width: 10;
    stroke-linecap: round;
    /* 2 * PI * r (r = 68) — the ring starts undrawn and is filled by JS. */
    stroke-dasharray: 427.26;
    stroke-dashoffset: 427.26;
    transition: stroke-dashoffset 1100ms var(--ease-out);
}

/* Empty state: a dotted track makes "no data yet" unmistakable. */
.is-empty .score-ring::before { background: radial-gradient(circle, rgba(255, 255, 255, 0.05), transparent 70%); }

.is-empty .score-ring__track {
    stroke-width: 3.5;
    stroke-dasharray: 0.5 9;
    stroke-linecap: round;
    stroke: rgba(255, 255, 255, 0.26);
}

.is-empty .score-ring__value { stroke: transparent; }

.score-ring__center {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.score-ring__number {
    font-size: var(--fs-score);
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.045em;
    font-variant-numeric: tabular-nums;
}

.is-empty .score-ring__number { color: var(--text-secondary); }

.score-ring__scale {
    margin-top: var(--space-2);
    font-size: var(--fs-tiny);
    color: var(--text-muted);
}

.score-ring__label {
    font-size: var(--fs-section);
    font-weight: 600;
    letter-spacing: -0.02em;
}

/* Ring legend — explains what the score is made of. */
.legend {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-2);
    margin-top: var(--space-4);
    padding: var(--space-3) var(--space-2);
    border: 1px solid var(--glass-hairline);
    border-radius: var(--radius-md);
    background: rgba(255, 255, 255, 0.035);
}

.legend__item {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-width: 0;
}

.legend__dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}

.legend__label {
    font-size: var(--fs-tiny);
    color: var(--text-secondary);
    white-space: nowrap;
}

/* The pillar's own score, in the legend's own size — a number beside the
   name, not a second label. */
.legend__value {
    font-size: var(--fs-tiny);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
    white-space: nowrap;
}

.legend__item.is-empty .legend__value { font-weight: 500; color: var(--text-muted); }

/* --------------------------------------------------------------------------
   Score value + meters (shared by category cards and goal progress)
   -------------------------------------------------------------------------- */
.score-value {
    display: flex;
    align-items: baseline;
    gap: 2px;
    margin-top: var(--space-3);
}

.score-value__number {
    font-size: var(--fs-score-sm);
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.035em;
    font-variant-numeric: tabular-nums;
}

.is-empty .score-value__number { color: var(--text-secondary); }

.score-value__max {
    font-size: var(--fs-small);
    color: var(--text-muted);
}

.meter {
    height: 6px;
    margin-top: var(--space-3);
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.08);
    overflow: hidden;
}

.meter__fill {
    display: block;
    width: 0;
    height: 100%;
    border-radius: inherit;
    background: var(--accent);
    background: linear-gradient(90deg, var(--accent), color-mix(in srgb, var(--accent) 65%, #ffffff));
    transition: width 1000ms var(--ease-out);
}

.is-empty .meter {
    height: 4px;
    background: repeating-linear-gradient(90deg,
        rgba(255, 255, 255, 0.11) 0 2px,
        transparent 2px 8px);
}

.is-empty .meter--goal { height: 6px; }

.meter--goal { height: 10px; }

/* --------------------------------------------------------------------------
   Icon tile + chips
   -------------------------------------------------------------------------- */
.icon-tile {
    display: grid;
    place-items: center;
    width: 36px;
    height: 36px;
    flex: none;
    border: 1px solid var(--glass-hairline);
    border-radius: var(--radius-sm);
    background: rgba(255, 255, 255, 0.065);
    color: var(--text-secondary);
}

.icon-tile .icon { width: 18px; height: 18px; }

.card--goal .icon-tile { color: var(--accent); }

.icon-tile--accent { color: var(--nutrition); }

.chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--glass-hairline);
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.055);
    font-size: var(--fs-tiny);
    font-weight: 600;
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    color: var(--text-secondary);
    white-space: nowrap;
}

.chip--muted {
    text-transform: none;
    letter-spacing: 0;
    font-weight: 500;
    color: var(--text-muted);
}

.chip__dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--health);
}

.chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-4);
}

.chips--centered { justify-content: center; }

/* --------------------------------------------------------------------------
   Insights
   -------------------------------------------------------------------------- */
.insights {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.insights__item {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: start;
    gap: var(--space-3);
    padding: var(--space-3);
    border: 1px solid var(--glass-hairline);
    border-radius: var(--radius-md);
    background: rgba(255, 255, 255, 0.035);
}

.insights__marker {
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    flex: none;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.07);
    background: color-mix(in srgb, var(--accent) 16%, transparent);
    color: var(--accent);
}

.insights__marker .icon { width: 16px; height: 16px; }

.insights__title {
    font-size: var(--fs-label);
    font-weight: 600;
    letter-spacing: -0.01em;
}

.insights__item.is-empty .insights__title { color: var(--text-secondary); }

.insights__text {
    margin-top: var(--space-1);
    font-size: var(--fs-small);
    color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   Patterns placeholder
   -------------------------------------------------------------------------- */
.trend {
    display: flex;
    align-items: flex-end;
    gap: var(--space-2);
    height: 64px;
    margin-bottom: var(--space-4);
    padding-bottom: var(--space-2);
    border-bottom: 1px dashed var(--glass-border-soft);
    opacity: 0.6;
}

/* Equal heights on purpose: a shaped skeleton would read as data that does
   not exist yet. Flat + shimmering reads as "waiting for measurements". */
.trend__bar {
    flex: 1;
    height: 46%;
    border-radius: 6px;
}

/* --------------------------------------------------------------------------
   Goal progress
   -------------------------------------------------------------------------- */
.goal__headline {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-3);
}

.goal__name {
    font-size: 1.0625rem;
    font-weight: 600;
    letter-spacing: -0.015em;
}

.is-empty .goal__name { color: var(--text-secondary); }

.goal__figure {
    display: flex;
    align-items: baseline;
    flex: none;
}

.goal__percent {
    font-size: var(--fs-score-sm);
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.035em;
    font-variant-numeric: tabular-nums;
}

.is-empty .goal__percent { color: var(--text-secondary); }

.goal__unit-sign {
    font-size: var(--fs-small);
    color: var(--text-muted);
    margin-left: 2px;
}

.milestones {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    margin-top: var(--space-3);
}

.milestones__item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
}

.milestones__item:first-child { align-items: flex-start; }
.milestones__item:last-child { align-items: flex-end; }

.milestones__dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.18);
}

.milestones__item.is-reached .milestones__dot {
    background: var(--health);
    box-shadow: 0 0 0 3px rgba(60, 158, 114, 0.18);
}

.milestones__label {
    font-size: var(--fs-tiny);
    color: var(--text-muted);
}

.milestones__item.is-reached .milestones__label { color: var(--text-secondary); }

.goal__action {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-top: var(--space-4);
}

.goal__note {
    font-size: var(--fs-tiny);
    color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   Leaderboard — deliberately the quietest block on the page
   -------------------------------------------------------------------------- */
.board {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.board__row {
    display: grid;
    grid-template-columns: 16px 28px minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: rgba(255, 255, 255, 0.03);
}

.board__rank {
    font-size: var(--fs-small);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
    text-align: center;
}

.board__avatar {
    display: grid;
    place-items: center;
    width: 28px;
    height: 28px;
    border: 1px solid var(--glass-hairline);
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.06);
    color: var(--text-muted);
}

.board__avatar .icon { width: 15px; height: 15px; }

.board__name {
    font-size: var(--fs-small);
    color: var(--text-secondary);
    min-width: 0;
}

.board__value {
    font-size: var(--fs-small);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.board__row--self {
    background: rgba(60, 158, 114, 0.1);
    border-color: rgba(60, 158, 114, 0.22);
}

.board__row--self .board__name { color: var(--text-primary); font-weight: 600; }

/* --------------------------------------------------------------------------
   Bottom navigation
   -------------------------------------------------------------------------- */
/* The dock holds everything pinned to the bottom: above the page rail, below
   the assistant sheet. It is also the sheet's grab area — `touch-action: none`
   here is what makes the upward swipe possible, while everywhere else vertical
   movement stays with the browser and ordinary scrolling is untouched.
   The band between the handle and the tab bar stays click-through. */
.app-dock {
    position: absolute;
    inset-inline: 0;
    bottom: 0;
    z-index: 30;
    display: flex;
    flex-direction: column;
    align-items: center;
    touch-action: none;
    pointer-events: none;
}

.app-dock > * { pointer-events: auto; }

/* Pull-up affordance, and a tap target for anyone not using the gesture. */
.ai-handle {
    display: grid;
    place-items: center;
    width: 128px;
    height: 40px;
    border-radius: var(--radius-pill);
}

.ai-handle__grip {
    display: block;
    width: 38px;
    height: 4px;
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.18);
    transition: background-color var(--transition-fast), width var(--transition-fast);
}

.ai-handle:active .ai-handle__grip,
.ai-handle:focus-visible .ai-handle__grip {
    width: 50px;
    background: rgba(255, 255, 255, 0.42);
}

/* --------------------------------------------------------------------------
   The tab bar — a pane of glass floating over the page

   Not a slab across the bottom of the screen: a capsule with air at its sides
   and underneath, so the page runs past it on every edge and you can see it
   doing so. The material is grey and white only; nothing in here takes an
   accent colour.

   It is built from four things, in the order light meets them:

     backdrop-filter   blurs and saturates the page behind the capsule
     background        the glass body — its own faint tint over that
     ::before          a reflection, pushed out of true by the turbulence
                       filter so it is never a perfect gradient
     ::after           the rim, a hairline that catches light at the top-left
                       and gives it back at the bottom-right
   -------------------------------------------------------------------------- */
.tabbar {
    position: relative;
    isolation: isolate;
    width: min(94vw, 27.5rem);
    height: var(--tabbar-height);
    margin-bottom: calc(var(--safe-bottom) + var(--dock-gap));
    border-radius: var(--radius-pill);
    background:
        linear-gradient(177deg,
            rgba(255, 255, 255, 0.115) 0%,
            rgba(255, 255, 255, 0.042) 44%,
            rgba(255, 255, 255, 0.06) 100%),
        rgba(30, 28, 29, 0.62);
    /* The blur is what makes it translucent rather than see-through: the
       page's colour and brightness still move under the glass, its words do
       not survive the trip.

       10px, not the 40-odd you might reach for. Measured through the glass,
       text-scale detail bottoms out around 8-10px and then climbs again —
       Chromium downsamples the backdrop at large radii and the resampling
       puts the detail back. At 48px more of the page reads through than at
       10px. It is also the cheaper number on a phone. */
    -webkit-backdrop-filter: blur(var(--pane-blur)) saturate(var(--pane-saturate)) brightness(var(--pane-brightness));
    backdrop-filter: blur(var(--pane-blur)) saturate(var(--pane-saturate)) brightness(var(--pane-brightness));
    /* It floats, so it casts: a wide soft shadow for the height and a tight
       one directly under it for the contact. */
    box-shadow:
        0 18px 44px rgba(0, 0, 0, 0.46),
        0 5px 14px rgba(0, 0, 0, 0.30),
        inset 0 1px 0 rgba(255, 255, 255, 0.14),
        inset 0 -1px 0 rgba(255, 255, 255, 0.04);
}

/* The reflection. A static layer, rasterised once, so the turbulence that
   keeps it from looking like a plain gradient costs nothing per frame.

   It is drawn oversized and clipped back, which is not decoration. A filter
   paints wherever its region reaches and `border-radius` does not clip what
   comes out of one, so at inset: 0 the displacement carried this layer's own
   edge across the rim — measured at 10.8px proud of the glass near the top of
   the curve, with the matching bite taken out of it further round. clip-path
   is the one that runs after the filter. Overhanging by more than the
   displacement can travel (scale 19, so ±9.5px) keeps a real edge from ever
   reaching the cut. */
.tabbar::before {
    content: "";
    position: absolute;
    inset: calc(-1 * var(--sheen-overhang));
    z-index: -1;
    background:
        radial-gradient(57% 94% at 24.2% 0%,
            rgba(255, 255, 255, 0.20) 0%,
            rgba(255, 255, 255, 0.06) 40%,
            transparent 68%),
        radial-gradient(44% 82% at 85% 99%,
            rgba(255, 255, 255, 0.10) 0%,
            transparent 62%);
    filter: url(#glass-refraction);
    clip-path: inset(var(--sheen-overhang) round var(--radius-pill));
    pointer-events: none;
}

/* The rim. One hairline, drawn as a gradient behind a ring cut out of itself,
   brightest where light lands and nearly gone across the face — an edge with
   thickness rather than an outline around a box. */
.tabbar::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    padding: 1px;
    background: var(--pane-rim);
    -webkit-mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    mask-composite: exclude;
    pointer-events: none;
}

.tabbar__list {
    position: relative;
    display: grid;
    /* Five equal columns: a longer label never claims more space. */
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 0;
    width: 100%;
    height: 100%;
    /* Keeps the capsule's curve off the first letter of the outer labels.
       One rule for every width, and it leaves the five columns equal — it
       insets the row, not the items. The slope it needs is worked out where
       the token is defined. */
    padding-inline: var(--tab-edge);
}

/* The capsule is only as tall as an icon, a label and a little air. */
.tab {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--tab-gap);
    width: 100%;
    height: 100%;
    /* One correction, the same on all five tabs. The icon box is a square
       frame around marks that are mostly wider than they are tall, so it
       carries more dead space above the strokes than the label's box carries
       under its baseline, and centring the boxes leaves the pair reading low.
       Measured in label ems, so it holds if the type ever moves. */
    padding: 0 0 calc(var(--tab-label) * var(--tab-optical));
    border-radius: var(--radius-pill);
    /* Translucent glass gives back less contrast than a solid bar, so the
       resting label carries a little more of its own. */
    color: var(--text-secondary);
    transition: color var(--transition-fast);
}

/* One box for all five. The icons used to need a per-icon correction here to
   look centred; they are normalised on the grid instead now, so the box and
   the eye agree and nothing is tuned tab by tab. */
.tab__icon { display: block; }
.tab__icon .icon { width: var(--tab-icon); height: var(--tab-icon); }

/* All five labels are single words, so they never wrap: the icons stay on one
   baseline and the bar keeps its height at every width. */
.tab__label {
    display: block;
    font-size: var(--tab-label);
    font-weight: 500;
    /* No leading. The icon above is already trimmed to its ink, so the label
       is measured the same way and the gap between them is the gap, not the
       gap plus two half-leadings. */
    line-height: 1;
    letter-spacing: -0.012em;
    text-align: center;
    white-space: nowrap;
}

/* The selected item is a second, brighter pane of the same glass sitting
   inside the first — lighter, with its own lit top edge and its own small
   shadow, so it reads as a piece of the material and not as a coloured chip.
   No accent: the bar is grey and white throughout. */
.tab__glow {
    position: absolute;
    inset: var(--tab-glow-inset);
    border-radius: var(--radius-pill);
    background: linear-gradient(178deg,
        rgba(255, 255, 255, 0.20) 0%,
        rgba(255, 255, 255, 0.115) 48%,
        rgba(255, 255, 255, 0.085) 100%);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.28),
        inset 0 -1px 0 rgba(255, 255, 255, 0.05),
        0 2px 7px rgba(0, 0, 0, 0.20);
    opacity: 0;
    transform: scale(0.94);
    transition: opacity var(--transition-slow), transform var(--transition-slow);
    pointer-events: none;
}

/* The whole tab is a .press elsewhere in the app; inside the capsule the
   lozenge does the responding, so the tab itself must not also shrink. */
.tab.press:active { transform: none; }

/* Two cues, not three. The lozenge and the brighter ink are the state; the
   label used to bold as well, which cost the five labels their shared metrics
   and shifted the word's width as you moved between tabs. */
.tab.is-active { color: var(--text-primary); }
.tab.is-active .tab__icon { color: var(--text-primary); }

.tab.is-active .tab__glow {
    opacity: 1;
    transform: none;
}

/* A press lifts the glass under the finger, then lets it settle. */
.tab:not(.is-active):active .tab__glow { opacity: 0.45; transform: none; }
.tab:not(.is-active):active { color: var(--text-primary); }

/* --------------------------------------------------------------------------
   Floating control
   -------------------------------------------------------------------------- */
/* Sits on the right edge of the content column, clear of the text below it. */
.fab {
    --fab-size: 50px;
    --fab-x: calc(var(--shell-w) / 2 - var(--fab-size));

    position: absolute;
    left: 50%;
    bottom: calc(var(--dock-clearance) + var(--space-4));
    /* Above the dock, so it stays tappable where the two overlap. */
    z-index: 36;
    display: grid;
    place-items: center;
    width: var(--fab-size);
    height: var(--fab-size);
    border: 1px solid var(--glass-border);
    border-radius: 50%;
    background: rgba(48, 45, 47, 0.72);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
    backdrop-filter: blur(18px) saturate(140%);
    box-shadow: var(--shadow-float);
    color: var(--text-secondary);
    opacity: 0;
    transform: translate(var(--fab-x), 8px);
    transition: opacity var(--transition-fast), transform var(--transition-fast);
}

.fab[hidden] { display: none; }

.fab.is-visible {
    opacity: 1;
    transform: translate(var(--fab-x), 0);
}

.fab:active { transform: translate(var(--fab-x), 0) scale(0.94); }

/* --------------------------------------------------------------------------
   Footnote
   -------------------------------------------------------------------------- */
.disclaimer {
    margin-top: var(--space-2);
    padding-inline: var(--space-2);
    font-size: var(--fs-tiny);
    color: var(--text-muted);
    text-align: center;
}
