/* =========================================================================
   Ketchup — hand-written, mobile-first.

   No component library on purpose: every Blazor library on offer is a desktop
   admin vocabulary, and the parts that make this app itself — ripeness, the
   dot strip, tomato estimates, the timer face — would be bespoke anyway.
   This file travels with the RCL, so a MAUI Blazor Hybrid head gets the same
   look without moving a single rule.

   ONE RULE ABOUT COLOUR, and everything here follows from it:

     Colour on a task row means URGENCY. Colour behind a screen means WHERE
     YOU ARE. Nothing else gets to be colourful.

   Freshness owns the ripe → overripe → dropping ramp, because "decay must be
   visible before it happens" is a promise the app makes. Giving rows arbitrary
   hues would look wonderful and quietly break the only thing the design is
   for. So the gradients and the new greens live in the chrome — washes, hero,
   buttons, rings — and never on a row.
   ========================================================================= */

/* ------------------------------------------------------------------ tokens */

/* Every token is declared ONCE, as light-dark(light, dark). Which half applies is decided
   entirely by `color-scheme` on the root, so the theme switch below is a single property
   rather than a second copy of the palette that has to be kept in step with the first.

   Pastels from a light-mode reference go muddy at night, so the dark halves are designed
   rather than computed from the light ones. */
:root {
    /* The default: follow the device. A phone that switches at dusk takes the app with it. */
    color-scheme: light dark;

    --bg:         light-dark(#fdf8f4, #16110e);
    --surface:    light-dark(#ffffff, #211a15);
    --surface-2:  light-dark(#f7efe8, #2b221b);
    --ink:        light-dark(#241c18, #f5ede7);
    --ink-soft:   light-dark(#6b5b52, #b5a396);
    --ink-faint:  light-dark(#9c8b80, #82736a);
    --line:       light-dark(#f1e7df, #33281f);

    --accent:     light-dark(#e04a33, #ff6a4d);
    --accent-2:   light-dark(#f4813f, #ffa062);   /* warm end of the primary gradient */
    --accent-ink: light-dark(#ffffff, #1a120e);
    --accent-wash:light-dark(#fdeee9, #331a12);

    /* The vine. The app is named for a fruit that grows on one and had no green in it at all,
       which is most of why it read as severe rather than happy. Green is growth and progress;
       red is ripe and urgent. */
    --vine:       light-dark(#3f9e6a, #5fbf85);
    --vine-2:     light-dark(#6fc48d, #8ad9a6);
    --vine-wash:  light-dark(#e8f4ec, #14261c);

    /* Freshness is a product mechanic, not decoration — these three are the whole point of
       the palette. Ripe, overripe, about to drop. */
    --fresh:      light-dark(#e04a33, #ff6a4d);
    --wilting:    light-dark(#e0902f, #e8a04c);
    --dropping:   light-dark(#9c8468, #a08f76);

    --done:       var(--vine);

    /* Zone washes, as colours rather than whole gradients, so the gradient geometry is
       written once and only the hues change with the theme. */
    --wash-today-a:   light-dark(#ffe2cc, #3a1d12);
    --wash-today-b:   light-dark(#ffd9d0, #33161a);
    --wash-vine-a:    light-dark(#dff1e5, #13291d);
    --wash-vine-b:    light-dark(#eaf6ec, #10231a);
    --wash-compost-a: light-dark(#ede1d2, #2a2119);

    /* ---- Liquid Glass ----------------------------------------------------------------
       Apple's material is three things stacked: a frosted, saturated backdrop; a rim of
       specular light along the edges; and a diagonal sheen across the surface. The fourth —
       real lensing, where the backdrop bends through the glass — needs an SVG
       feDisplacementMap used as a backdrop-filter, and only Chromium supports that. It would
       therefore never appear on the iPhone this app exists for, so it is left out rather
       than shipped as an Android-only effect on the one platform where the blur already
       costs the most. */
    --glass-blur:      20px;
    --glass-tint:      light-dark(rgb(255 255 255 / .62), rgb(44 35 29 / .58));
    --glass-tint-thin: light-dark(rgb(255 255 255 / .40), rgb(44 35 29 / .38));
    --glass-edge:      light-dark(rgb(255 255 255 / .70), rgb(255 255 255 / .16));
    --glass-rim-top:   light-dark(rgb(255 255 255 / .85), rgb(255 255 255 / .26));
    --glass-rim-side:  light-dark(rgb(255 255 255 / .35), rgb(255 255 255 / .09));
    --glass-rim-base:  light-dark(rgb(255 255 255 / .30), rgb(255 255 255 / .06));
    --glass-sheen:     light-dark(rgb(255 255 255 / .55), rgb(255 255 255 / .18));
    --glass-cast:      light-dark(rgb(120 60 40 / .16), rgb(0 0 0 / .55));

    --radius:     22px;
    --radius-sm:  14px;
    --radius-lg:  28px;

    /* Concentric, the way Apple nests corners: an inner radius equals the outer one minus
       the padding between them, so curves stay parallel instead of drifting apart. */
    --radius-inner: calc(var(--radius) - 8px);

    --tabbar-h:   58px;
    --tabbar-lift: calc(env(safe-area-inset-bottom, 0px) + 10px);
    --gutter:     16px;

    /* Softer and warmer than a neutral drop shadow — on a cream background a grey shadow
       reads as dirt. */
    --shadow:     0 1px 2px light-dark(rgb(120 60 40 / .04), rgb(0 0 0 / .5)),
                  0 8px 22px -14px light-dark(rgb(120 60 40 / .28), rgb(0 0 0 / .8));
    --shadow-lg:  0 2px 6px light-dark(rgb(120 60 40 / .06), rgb(0 0 0 / .5)),
                  0 18px 40px -22px light-dark(rgb(120 60 40 / .40), rgb(0 0 0 / .9));

    --grad-accent: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
    --grad-vine:   linear-gradient(135deg, var(--vine) 0%, var(--vine-2) 100%);

    --safe-b:     env(safe-area-inset-bottom, 0px);
    --safe-t:     env(safe-area-inset-top, 0px);
}

/* The whole theme switch. Setting color-scheme is also what makes native form controls,
   scrollbars and the caret follow — which a hand-rolled class swap would have missed. */
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"]  { color-scheme: dark; }

/* --------------------------------------------------------------- base ---- */

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

html, body {
    margin: 0;
    padding: 0;
    color: var(--ink);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
    font-size: 16px;
    line-height: 1.45;
    -webkit-font-smoothing: antialiased;
}

/* The base colour goes on html, not body. A background on body paints as a normal element
   box and would cover the z-index:-1 wash entirely — which is exactly what it did first
   time round, leaving every screen the same cream. */
html { background: var(--bg); }

body {
    background: transparent;

    /* App, not web page: no rubber-band scroll, no accidental text selection on
       a tap, no blue flash on every button. */
    overscroll-behavior-y: none;
    -webkit-tap-highlight-color: transparent;
}

button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; }

h1, h2, h3 { margin: 0; font-weight: 700; letter-spacing: -0.025em; }
h1 { font-size: 1.75rem; }
h2 { font-size: 1.05rem; }
h3 { font-size: .95rem; }
p  { margin: 0 0 .7em; }
a  { color: var(--accent); }

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

/* FocusOnNavigate moves focus to the heading on every route change so screen readers
   announce the new screen. That focus is programmatic, the heading is not interactive, and
   drawing a ring around it on every navigation just looks broken. */
[tabindex="-1"]:focus, [tabindex="-1"]:focus-visible { outline: none; }

/* --------------------------------------------------------------- glass --- */

/* The material, in one place. Apple's own guidance is that glass belongs to the navigation
   and control layer and NOT to content — which lands on exactly the same line this stylesheet
   already drew. Glass is translucent, so anything behind it bleeds through; a glass task row
   would take its colour from the wash and freshness would stop being readable. Chrome floats,
   content stays solid. */
.glass,
.tabbar__inner,
.timerbar__inner,
.btn,
.icon-btn,
.segmented__option[aria-pressed="true"] {
    position: relative;
    isolation: isolate;
    background: var(--glass-tint);
    backdrop-filter: blur(var(--glass-blur)) saturate(180%);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(180%);
    border: 1px solid var(--glass-edge);
    box-shadow:
        inset  0  1px 1px var(--glass-rim-top),    /* the lit top edge */
        inset  0 -1px 1px var(--glass-rim-base),
        inset  1px 0  0   var(--glass-rim-side),
        inset -1px 0  0   var(--glass-rim-side),
        0 10px 30px -12px var(--glass-cast);
}

/* The diagonal sheen. Screen-blended so it lifts whatever is underneath rather than
   painting grey over it. */
/* Note the absence of .icon-btn: a 135° wedge across a 44px disc reads as a thumbprint
   rather than as a highlight. Small round controls get the rim and nothing else. */
.glass::after,
.tabbar__inner::after,
.timerbar__inner::after,
.btn::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    mix-blend-mode: screen;
    background: linear-gradient(135deg,
        var(--glass-sheen) 0%,
        color-mix(in srgb, var(--glass-sheen) 18%, transparent) 28%,
        transparent 58%);
}

.glass--thin { background: var(--glass-tint-thin); }

/* Tinted glass, for a control that needs to stay prominent. Kept fairly opaque on purpose:
   Apple's tinted glass compensates for contrast dynamically and CSS cannot, so a primary
   action floating over an unknown backdrop has to carry its own legibility. */
.glass--accent,
.timerbar__inner,
.btn--primary {
    background: var(--grad-accent);
    border-color: color-mix(in srgb, #fff 34%, transparent);
    color: var(--accent-ink);
    box-shadow:
        inset 0  1px 1px rgb(255 255 255 / .45),
        inset 0 -1px 1px rgb(0 0 0 / .10),
        0 10px 26px -10px color-mix(in srgb, var(--accent) 75%, transparent);
}

.glass--vine {
    background: var(--grad-vine);
    border-color: color-mix(in srgb, #fff 34%, transparent);
    color: #fff;
    box-shadow:
        inset 0  1px 1px rgb(255 255 255 / .45),
        inset 0 -1px 1px rgb(0 0 0 / .10),
        0 10px 26px -10px color-mix(in srgb, var(--vine) 75%, transparent);
}

/* Reduce Transparency is a real iOS setting and the whole material has to survive it. Glass
   becomes an ordinary opaque surface: no blur to read through, no sheen over the text. */
@media (prefers-reduced-transparency: reduce) {
    .glass,
    .tabbar__inner,
    .btn,
    .icon-btn,
    .segmented__option[aria-pressed="true"] {
        background: var(--surface);
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
    }

    .glass::after,
    .tabbar__inner::after,
    .timerbar__inner::after,
    .btn::after,
    .icon-btn::after { display: none; }

    .glass--accent, .timerbar__inner, .btn--primary { background: var(--grad-accent); }
    .glass--vine { background: var(--grad-vine); }
}

@media (prefers-contrast: more) {
    .glass, .tabbar__inner, .btn, .icon-btn { border-color: var(--ink-soft); }

    .glass::after,
    .tabbar__inner::after,
    .timerbar__inner::after,
    .btn::after,
    .icon-btn::after { display: none; }
}

/* ---------------------------------------------------------------- wash --- */

/* Where you are, said in colour. Three stacked layers crossfaded by opacity
   rather than one layer with a changing gradient, because gradients do not
   interpolate — swapping one would cut rather than fade. */
.wash {
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    opacity: 0;
    transition: opacity .5s ease;
}

.wash--on { opacity: 1; }

/* Geometry written once; only the hues change with the theme. Fading to a zero-alpha copy of
   the same hue rather than to `transparent`, so no browser can interpolate through grey. */
.wash--today {
    background:
        radial-gradient(120% 62% at 50% -8%,
            var(--wash-today-a) 0%, color-mix(in srgb, var(--wash-today-a) 0%, transparent) 62%),
        radial-gradient(90% 45% at 100% 0%,
            var(--wash-today-b) 0%, color-mix(in srgb, var(--wash-today-b) 0%, transparent) 55%);
}

/* Morning for Today (the day starts at 4am and the pull is a ritual), growing for the Vine,
   earth for the Compost — honest, not gloomy. */
.wash--vine {
    background:
        radial-gradient(120% 62% at 50% -8%,
            var(--wash-vine-a) 0%, color-mix(in srgb, var(--wash-vine-a) 0%, transparent) 62%),
        radial-gradient(90% 45% at 0% 0%,
            var(--wash-vine-b) 0%, color-mix(in srgb, var(--wash-vine-b) 0%, transparent) 55%);
}

.wash--compost {
    background: radial-gradient(120% 60% at 50% -8%,
        var(--wash-compost-a) 0%, color-mix(in srgb, var(--wash-compost-a) 0%, transparent) 60%);
}

/* --------------------------------------------------------------- shell --- */

.app {
    max-width: 560px;          /* reads as a phone app even in a desktop browser */
    margin: 0 auto;
    min-height: 100dvh;
    padding-top: var(--safe-t);
    /* clears the floating tab capsule, the timer bar, and the home indicator */
    padding-bottom: calc(var(--tabbar-lift) + var(--tabbar-h) + 16px);
}

.app--timing { padding-bottom: calc(var(--tabbar-lift) + var(--tabbar-h) + 92px); }

.page { padding: 4px var(--gutter) 8px; }

.page__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 0 12px;
}

.page__date {
    color: var(--ink-faint);
    font-size: .85rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.section { margin-top: 26px; }

.section__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 10px;
}

.section__title {
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--ink-faint);
}

.muted { color: var(--ink-soft); }
.faint { color: var(--ink-faint); }
.nums  { font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------- hero --- */

/* The first thing you see on Today is what you have DONE, not what you owe.
   The app is scrupulously honest about neglect; without this it was silent
   about progress, which is most of why it did not feel like somewhere you
   want to be. */
.hero {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 2px 2px 6px;
    margin-bottom: 8px;
}

.hero__number {
    font-size: 3.5rem;
    font-weight: 800;
    line-height: .95;
    letter-spacing: -.045em;
    font-variant-numeric: tabular-nums;
    background: var(--grad-accent);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

/* Nothing logged yet is not a failure, and a big red zero saying so would be
   the most demotivating pixel in the app. */
.hero__number--none {
    background: none;
    color: var(--ink-faint);
    opacity: .45;
}

.hero__body { min-width: 0; }

.hero__label {
    font-weight: 650;
    font-size: 1rem;
    letter-spacing: -.01em;
}

.hero__sub {
    font-size: .84rem;
    color: var(--ink-soft);
    margin-top: 2px;
}

.hero__tomatoes {
    display: flex;
    gap: 3px;
    margin-top: 6px;
    font-size: .85rem;
}

/* -------------------------------------------------------------- tab bar -- */

/* A floating capsule inset from the edges rather than a full-width bar welded to the bottom —
   the shape iOS 26 made its signature, and the one that lets the wash and the content show
   around and behind the glass. */
.tabbar {
    position: fixed;
    bottom: var(--tabbar-lift);
    left: 0;
    right: 0;
    z-index: 40;
    display: flex;
    justify-content: center;
    padding: 0 var(--gutter);
    pointer-events: none;
}

.tabbar__inner {
    pointer-events: auto;
    width: 100%;
    max-width: calc(560px - 2 * var(--gutter));
    padding: 5px;
    border-radius: 999px;
    display: grid;
    /* Column count follows the tabs rather than being hard-coded, so the bar survives the
       next time the information architecture changes. */
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
}

.tab {
    position: relative;
    z-index: 1;
    height: calc(var(--tabbar-h) - 10px);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    border-radius: 999px;
    text-decoration: none;
    color: var(--ink-faint);
    font-size: .66rem;
    font-weight: 600;
    letter-spacing: .02em;
    transition: color .18s, background .25s;
}

.tab__glyph { font-size: 1.15rem; line-height: 1; transition: transform .25s; }

/* The lit pill behind whichever tab you are on. */
.tab.active {
    color: var(--accent);
    background: color-mix(in srgb, var(--accent) 13%, transparent);
}

.tab.active .tab__glyph { transform: translateY(-1px) scale(1.06); }

/* Condensed: the labels roll away as you scroll down and come back when you stop or scroll
   up, so the bar takes less of the screen while you are reading. */
.tab__label {
    max-height: 1.2em;
    overflow: hidden;
    transition: max-height .25s ease, opacity .2s ease;
}

body[data-scrolled="down"] .tab__label { max-height: 0; opacity: 0; }
body[data-scrolled="down"] .tab { height: calc(var(--tabbar-h) - 22px); }

.tab__badge {
    position: absolute;
    transform: translate(14px, -12px);
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 8px;
    background: var(--grad-accent);
    color: var(--accent-ink);
    font-size: .62rem;
    font-weight: 700;
    display: grid;
    place-items: center;
}

/* ---------------------------------------------------------------- cards -- */

/* Tinted fill rather than white-plus-border. Most of the visual noise in the
   first cut was 1px lines; colour does the separating now. */
.card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
}

.card + .card { margin-top: 10px; }

.stack > * + * { margin-top: 10px; }

/* ----------------------------------------------------------------- rows -- */

.row {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    width: 100%;
    padding: 14px 15px;
    background: var(--surface);
    border: 1px solid transparent;
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    text-align: left;
    color: inherit;
    text-decoration: none;
    transition: transform .12s, box-shadow .12s;
}

.row + .row { margin-top: 9px; }

.row__body { flex: 1; min-width: 0; }

/* The title links to the task, but it is the row you are tapping — styling it like a link
   would put a red underline on almost every line in the app. */
.row__title {
    display: block;
    font-weight: 600;
    color: var(--ink);
    text-decoration: none;
    overflow-wrap: anywhere;
    letter-spacing: -.012em;
}

.row__meta {
    margin-top: 6px;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 5px 9px;
    font-size: .8rem;
    color: var(--ink-soft);
}

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

.row--done .row__title { text-decoration: line-through; color: var(--ink-faint); }
.row--done { box-shadow: none; background: color-mix(in srgb, var(--surface) 55%, transparent); }

/* Freshness tints the whole row, so the vine is scannable without reading it. */
.row--fresh    { border-left: 3px solid var(--fresh); }
.row--wilting  { border-left: 3px solid var(--wilting);
                 background: color-mix(in srgb, var(--wilting) 6%, var(--surface)); }
.row--dropping { border-left: 3px solid var(--dropping);
                 background: color-mix(in srgb, var(--dropping) 10%, var(--surface)); }

.row--running {
    border-color: color-mix(in srgb, var(--accent) 40%, transparent);
    background: var(--accent-wash);
    box-shadow: var(--shadow-lg);
}

/* Chosen for today, on the vine screen. Deliberately faint: the filled pull button is the
   real signal, and tinting whole rows this strongly turned the backlog pink. */
.row--picked {
    border-color: color-mix(in srgb, var(--accent) 30%, transparent);
    background: color-mix(in srgb, var(--accent) 4%, var(--surface));
}

.callout ul {
    margin: 8px 0;
    padding-left: 18px;
}

.callout li + li { margin-top: 5px; }
.callout li strong { font-weight: 650; }

/* ----------------------------------------------------------- suggestion -- */

/* Candidates, not commitments. Deliberately much lighter than .row — one line, no card, no
   shadow — so the morning pull cannot compete with the list it is feeding. Still a full-width
   button, so the tap target stays thumb-sized even though it reads as a single line. */
.suggest {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 44px;
    padding: 8px 13px;
    background: color-mix(in srgb, var(--surface) 55%, transparent);
    border: 1px solid var(--line);
    border-left: 3px solid var(--line);
    border-radius: var(--radius-sm);
    text-align: left;
    color: var(--ink-soft);
    font-size: .9rem;
    transition: transform .1s, background .15s;
}

.suggest + .suggest { margin-top: 6px; }

.suggest:active { transform: scale(.99); }

.suggest__plus {
    flex-shrink: 0;
    width: 25px;
    height: 25px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--grad-accent);
    color: var(--accent-ink);
}

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

.suggest--fresh    { border-left-color: var(--fresh); }
.suggest--wilting  { border-left-color: var(--wilting); }
.suggest--dropping { border-left-color: var(--dropping); }

/* ------------------------------------------------------------ freshness -- */

.freshness {
    display: block;
    height: 5px;
    margin-top: 9px;
    border-radius: 3px;
    background: color-mix(in srgb, var(--ink) 7%, transparent);
    overflow: hidden;
}

.freshness__fill {
    display: block;
    height: 100%;
    border-radius: 3px;
    background: var(--fresh);          /* fallback for anything without color-mix */
    transition: width .3s ease;
}

/* A continuous ripeness ramp rather than three flat steps: --t is 0 when the task was
   just worked and 1 when it is dropping, and the colour is interpolated across
   ripe → overripe → dusty. Two nested mixes because it is a two-segment ramp. */
@supports (background: color-mix(in oklab, red, blue 50%)) {
    .freshness__fill {
        background: color-mix(in oklab,
            color-mix(in oklab, var(--fresh), var(--wilting) calc(min(var(--t, 0), .5) * 200%)),
            var(--dropping) calc(max(var(--t, 0) - .5, 0) * 200%));
    }
}

.tag {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 9px;
    border-radius: 999px;
    font-size: .72rem;
    font-weight: 650;
    background: var(--surface-2);
    color: var(--ink-soft);
    white-space: nowrap;
}

.tag--fresh    { background: color-mix(in srgb, var(--fresh) 14%, transparent);    color: var(--fresh); }
.tag--wilting  { background: color-mix(in srgb, var(--wilting) 18%, transparent);  color: var(--wilting); }
.tag--dropping { background: color-mix(in srgb, var(--dropping) 20%, transparent); color: var(--dropping); }
.tag--accent   { background: var(--grad-accent); color: var(--accent-ink); }
.tag--warn     { background: color-mix(in srgb, var(--wilting) 18%, transparent);  color: var(--wilting); }
.tag--done     { background: color-mix(in srgb, var(--vine) 16%, transparent);     color: var(--vine); }

/* ------------------------------------------------------------- tomatoes -- */

.tomatoes {
    display: inline-flex;
    gap: 2px;
    font-size: .8rem;
    line-height: 1;
}

.tomato        { opacity: .3; filter: grayscale(1); }
.tomato--done  { opacity: 1;  filter: none; }

/* ------------------------------------------------------------ dot strip -- */

.strip { display: flex; gap: 4px; align-items: flex-end; }

.strip__day {
    width: 100%;
    max-width: 26px;
    aspect-ratio: 1;
    border-radius: 7px;
    background: color-mix(in srgb, var(--ink) 7%, transparent);
    display: grid;
    place-items: center;
    font-size: .62rem;
    font-weight: 700;
    color: var(--accent-ink);
}

.strip__day[data-n="1"] { background: color-mix(in srgb, var(--accent) 45%, transparent); }
.strip__day[data-n="2"] { background: color-mix(in srgb, var(--accent) 72%, transparent); }
.strip__day[data-n="3"] { background: var(--grad-accent); }

.strip__labels {
    display: flex;
    gap: 4px;
    margin-top: 5px;
    font-size: .6rem;
    color: var(--ink-faint);
}

.strip__labels span { width: 100%; max-width: 26px; text-align: center; }

/* -------------------------------------------------------------- buttons -- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    min-height: 46px;            /* thumb-sized, not mouse-sized */
    padding: 0 18px;
    border-radius: 999px;        /* every control is a capsule */
    color: var(--ink);
    font-size: .92rem;
    font-weight: 650;
    text-decoration: none;
    transition: transform .08s, background .12s, box-shadow .12s;
}

.btn:active { transform: scale(.97); }

/* Same reasoning as the icon buttons: a button sitting inside a card is not floating over the
   page, so it gets the rim without the long cast. */
.btn {
    box-shadow:
        inset 0  1px 1px var(--glass-rim-top),
        inset 0 -1px 1px var(--glass-rim-base),
        0 2px 8px -4px var(--glass-cast);
}

.btn--primary {
    color: var(--accent-ink);
    box-shadow:
        inset 0  1px 1px rgb(255 255 255 / .45),
        inset 0 -1px 1px rgb(0 0 0 / .10),
        0 8px 22px -10px color-mix(in srgb, var(--accent) 70%, transparent);
}

.btn--vine {
    background: var(--grad-vine);
    border-color: color-mix(in srgb, #fff 34%, transparent);
    color: #fff;
}

/* Flat by intent — these are the quiet options and should not float. */
.btn--ghost,
.btn--quiet,
.btn--danger {
    background: transparent;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    box-shadow: none;
}

.btn--ghost::after,
.btn--quiet::after,
.btn--danger::after { display: none; }

.btn--quiet   { border-color: transparent; color: var(--ink-soft); }
.btn--danger  { border-color: var(--line); color: var(--fresh); }
.btn--block   { width: 100%; }
.btn--sm      { min-height: 36px; padding: 0 14px; font-size: .82rem; }

.btn:disabled { opacity: .4; cursor: default; box-shadow: none; }
.btn:disabled:active { transform: none; }

/* Round icon button — start/stop, check off, rescue. */
.icon-btn {
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-size: 1rem;
    transition: transform .1s, background .12s, border-color .12s;

    /* The floating cast is sized for a bar, not a 44px disc — at this scale it reads as a
       smudge beside the button rather than as depth. Rim only, plus a tight contact shadow. */
    box-shadow:
        inset 0  1px 1px var(--glass-rim-top),
        inset 0 -1px 1px var(--glass-rim-base),
        0 2px 6px -3px var(--glass-cast);
}

.icon-btn:active { transform: scale(.92); }

.icon-btn--go {
    border-color: transparent;
    background: var(--grad-accent);
    color: var(--accent-ink);
    box-shadow: 0 5px 14px -7px color-mix(in srgb, var(--accent) 75%, transparent);
}

.icon-btn--on    { background: var(--grad-accent); border-color: transparent; color: var(--accent-ink); }
.icon-btn--check { font-size: 1.1rem; color: var(--ink-faint); }

.icon-btn--check[aria-pressed="true"] {
    background: var(--grad-vine);
    border-color: transparent;
    color: #fff;
}

.btn-row { display: flex; gap: 8px; flex-wrap: wrap; }

/* --------------------------------------------------------- celebration -- */

/* The app had nothing anywhere that said well done. It is meticulous about
   naming neglect and was silent about progress, which is a strange thing for
   something meant to motivate. */
@keyframes pop-in {
    0%   { transform: scale(.4); opacity: 0; }
    45%  { transform: scale(1.25); opacity: 1; }
    100% { transform: scale(1); opacity: 1; }
}

@keyframes float-away {
    0%   { transform: translateY(0) scale(.6); opacity: 0; }
    25%  { transform: translateY(-10px) scale(1.1); opacity: 1; }
    100% { transform: translateY(-42px) scale(.85); opacity: 0; }
}

.celebrating .icon-btn--check { animation: pop-in .45s ease-out; }

.pop {
    position: absolute;
    left: 50%;
    top: 0;
    pointer-events: none;
    font-size: 1.1rem;
    animation: float-away .95s ease-out forwards;
}

.pop--a { animation-delay: 0s;    margin-left: -26px; }
.pop--b { animation-delay: .09s;  margin-left: 0; }
.pop--c { animation-delay: .18s;  margin-left: 24px; }

.row { position: relative; }

/* ---------------------------------------------------------------- forms -- */

.field { display: block; margin-bottom: 13px; }

.field__label {
    display: block;
    margin-bottom: 6px;
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--ink-faint);
}

.input, .select, .textarea {
    width: 100%;
    min-height: 46px;
    padding: 11px 14px;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--ink);
    font-size: 1rem;   /* 16px — anything smaller makes iOS zoom on focus */
}

.textarea { min-height: 76px; resize: vertical; }

.input:focus, .select:focus, .textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-wash);
}

.field__hint { margin-top: 6px; font-size: .78rem; color: var(--ink-faint); }

.setting {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 13px 15px;
    border-bottom: 1px solid var(--line);
}

.setting:last-child { border-bottom: none; }

/* For a control too wide to sit beside its label without squeezing it into four lines. */
.setting--stack { display: block; }
.setting--stack .segmented { margin-top: 12px; }
.setting__label { font-weight: 600; }
.setting__hint  { font-size: .78rem; color: var(--ink-faint); margin-top: 2px; }
.setting .input { width: 92px; text-align: center; flex-shrink: 0; }

/* Segmented control — used for the theme choice. */
.segmented {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: 3px;
    padding: 3px;
    border-radius: 999px;
    background: var(--surface-2);
    flex-shrink: 0;
}

.segmented__option {
    min-height: 34px;
    padding: 0 13px;
    border: none;
    border-radius: 999px;
    background: transparent;
    color: var(--ink-soft);
    font-size: .82rem;
    font-weight: 650;
    white-space: nowrap;
    transition: background .15s, color .15s;
}

.segmented__option[aria-pressed="true"] {
    color: var(--ink);
    box-shadow:
        inset 0  1px 1px var(--glass-rim-top),
        inset 0 -1px 1px var(--glass-rim-base),
        0 2px 6px -3px var(--glass-cast);
}

/* day-of-week toggles for a routine's schedule */
.days { display: flex; gap: 6px; }

.day-toggle {
    flex: 1;
    aspect-ratio: 1;
    max-height: 46px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--line);
    background: var(--surface);
    color: var(--ink-soft);
    font-size: .78rem;
    font-weight: 650;
}

.day-toggle[aria-pressed="true"] {
    background: var(--grad-accent);
    border-color: transparent;
    color: var(--accent-ink);
}

/* ---------------------------------------------------------------- timer -- */

.timerbar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: calc(var(--tabbar-lift) + var(--tabbar-h) + 8px);
    z-index: 45;
    display: flex;
    justify-content: center;
    padding: 0 var(--gutter) 8px;
    pointer-events: none;
}

.timerbar__inner {
    pointer-events: auto;
    width: 100%;
    max-width: calc(560px - 2 * var(--gutter));
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 11px 10px 17px;
    border-radius: 999px;
    color: var(--accent-ink);
}

.timerbar--elapsed .timerbar__inner {
    background: var(--grad-vine);
    color: #fff;
    box-shadow:
        inset 0  1px 1px rgb(255 255 255 / .45),
        inset 0 -1px 1px rgb(0 0 0 / .10),
        0 10px 26px -10px color-mix(in srgb, var(--vine) 75%, transparent);
}

.timerbar__clock {
    font-size: 1.4rem;
    font-weight: 750;
    font-variant-numeric: tabular-nums;
    letter-spacing: -.01em;
}

.timerbar__task {
    flex: 1;
    min-width: 0;
    font-size: .82rem;
    opacity: .92;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.timerbar__btn {
    flex-shrink: 0;
    min-height: 38px;
    padding: 0 15px;
    border-radius: 999px;
    border: none;
    background: color-mix(in srgb, #fff 22%, transparent);
    color: inherit;
    font-size: .84rem;
    font-weight: 700;
}

/* the big face on the task page */
.timerface {
    display: grid;
    place-items: center;
    padding: 24px 0 20px;
}

/* A ring that drains as the pomodoro runs, so the core unit of work reads as
   an event rather than a readout. */
.ring { display: block; transform: rotate(-90deg); }

.ring__track {
    fill: none;
    stroke: color-mix(in srgb, var(--ink) 8%, transparent);
    stroke-width: 8;
}

.ring__fill {
    fill: none;
    stroke-width: 8;
    stroke-linecap: round;
    transition: stroke-dashoffset .5s linear;
}

.ring__wrap { position: relative; display: grid; place-items: center; }

.ring__centre {
    position: absolute;
    display: grid;
    place-items: center;
    gap: 2px;
}

.timerface__clock {
    font-size: 2.5rem;
    font-weight: 300;
    font-variant-numeric: tabular-nums;
    letter-spacing: -.03em;
    line-height: 1;
}

.timerface__label {
    font-size: .78rem;
    color: var(--ink-faint);
    letter-spacing: .04em;
}

/* --------------------------------------------------------------- pieces -- */

.callout {
    padding: 15px;
    border-radius: var(--radius);
    background: var(--surface-2);
    font-size: .88rem;
}

/* The reckoning. Marked out, but not so hard that it competes with the primary action
   sitting right under it — a full accent block turned the whole screen pink. */
.callout--accent {
    background: color-mix(in srgb, var(--accent) 5%, var(--surface));
    border-left: 3px solid var(--accent);
}

.callout--warn {
    background: color-mix(in srgb, var(--wilting) 13%, var(--surface));
}

.callout__title { font-weight: 700; margin-bottom: 5px; }

.empty {
    text-align: center;
    padding: 46px 20px;
    color: var(--ink-soft);
}

.empty__glyph { font-size: 2.8rem; display: block; margin-bottom: 12px; }
.empty__title { font-weight: 700; color: var(--ink); margin-bottom: 5px; font-size: 1.05rem; }
.empty p { font-size: .88rem; }

.counter {
    font-variant-numeric: tabular-nums;
    font-size: .85rem;
    font-weight: 700;
    color: var(--ink-soft);
}

.counter--over { color: var(--wilting); }

.checkbox {
    width: 24px;
    height: 24px;
    margin: 9px 0 0;
    flex-shrink: 0;
    accent-color: var(--accent);
}

.divider { height: 1px; background: var(--line); margin: 20px 0; border: 0; }

.menu-link {
    display: flex;
    align-items: center;
    gap: 13px;
    padding: 16px 15px;
    border-bottom: 1px solid var(--line);
    text-decoration: none;
    color: inherit;
}

.menu-link:last-child { border-bottom: none; }
.menu-link__glyph { font-size: 1.15rem; width: 26px; text-align: center; color: var(--accent); }
.menu-link__body { flex: 1; font-weight: 600; }
.menu-link__hint { font-size: .78rem; color: var(--ink-faint); font-weight: 400; }
.menu-link__chev { color: var(--ink-faint); }

.backlink {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 10px 0;
    font-size: .88rem;
    font-weight: 650;
    color: var(--accent);
    text-decoration: none;
}

/* ------------------------------------------------------- loading / error -- */

.boot {
    display: grid;
    place-items: center;
    min-height: 100dvh;
    gap: 14px;
    color: var(--ink-faint);
}

.boot__mark { font-size: 3rem; animation: bob 1.6s ease-in-out infinite; }

@keyframes bob {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-7px); }
}

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

    /* The floating tomatoes are pure decoration — with animation off they would
       otherwise sit frozen on screen rather than never appearing. */
    .pop { display: none; }
}
