/* gettofu.app homepage styles, shared by index.html and sk.html (TOF-631).
   The host caches by URL: never edit a published file in place. Rename it with
   git mv to the next version number, change that, and point both pages at it. */

/* ========================================
   FONTS
   ======================================== */
/* WOFF2, named by the hash of the source .otf (scripts/fonts-to-woff2.py): half
   the bytes of the OTFs they come from, and a name that changes only when the
   font does, so they ship through the normal deploy and can be cached for a
   year. The .otf files stay in landing/fonts as the source; nothing loads them. */
@font-face {
    font-family: 'Clash Display';
    src: url('../fonts/ClashDisplay-Bold-cbf5670a.woff2') format('woff2');
    font-weight: 700;
    font-display: swap;
}
@font-face {
    font-family: 'Clash Display';
    src: url('../fonts/ClashDisplay-Semibold-e70dce86.woff2') format('woff2');
    font-weight: 600;
    font-display: swap;
}
@font-face {
    font-family: 'General Sans';
    src: url('../fonts/GeneralSans-Regular-f5cfd05c.woff2') format('woff2');
    font-weight: 400;
    font-display: swap;
}
@font-face {
    font-family: 'General Sans';
    src: url('../fonts/GeneralSans-Medium-a4c6067d.woff2') format('woff2');
    font-weight: 500;
    font-display: swap;
}
@font-face {
    font-family: 'General Sans';
    src: url('../fonts/GeneralSans-Semibold-6ad3ed96.woff2') format('woff2');
    font-weight: 600;
    font-display: swap;
}

/* ========================================
   TOKENS
   ======================================== */
:root {
    --primary: #2C6E46;
    --primary-light: rgba(44, 110, 70, 0.08);
    --primary-dark: #1E5233;
    --secondary: #D68C45;
    --tertiary: #FFE8B9;
    --bg: #F6F4EF;
    --bg-warm: #EDE9E0;
    --surface: #FFFFFF;
    --surface-2: #DDD9D0;
    --text: #0F1F0F;
    --text-2: #4A5A4A;
    --white: #FFFFFF;

    --font-display: 'Clash Display', Georgia, serif;
    --font-body: 'General Sans', -apple-system, sans-serif;

    /* Spacing: the app's TofuSpacing scale (xs 4 ... xxxl 48), plus the two
       section gaps the page needs and the app doesn't. */
    --space-xs: 4px; --space-sm: 8px; --space-md: 12px; --space-lg: 16px;
    --space-xl: 24px; --space-xxl: 32px; --space-xxxl: 48px;
    --space-section-sm: 64px; --space-section: 96px;

    /* Motion: linear() approximations of the app's springs. --spring is
       .spring(duration: 0.45, bounce: 0.3) from TofuAnimations.swift, for
       small things; --spring-soft overshoots less, for whole containers. */
    --spring: linear(0, 0.012, 0.047 2.2%, 0.19 4.6%, 0.738 13.4%, 0.95 17.6%, 1.05 21.2%, 1.1 24.6%, 1.108 27.2%, 1.1 30%, 1.064 35.4%, 1.012 44%, 0.99 51.4%, 0.987 58%, 0.998 72%, 1);
    --spring-soft: linear(0, 0.036 1.6%, 0.192 5.4%, 0.506 12.2%, 0.772 19.4%, 0.93 26.2%, 1.012 33%, 1.036 39.2%, 1.03 45.8%, 1.008 58%, 0.998 72%, 1);
    --out: cubic-bezier(0.16, 1, 0.3, 1);

    /* The journey stage's background, one tone per chapter (TOF-630). */
    --tone-oat: #EEE6D6;
    --tone-butter: #F8E4BC;
    --tone-sage: #DCE7DB;
    --tone-peach: #F7D9C4;
}

/* ========================================
   RESET & BASE
   ======================================== */
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

html {
    scroll-behavior: smooth;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

body {
    font-family: var(--font-body);
    color: var(--text);
    background: var(--bg);
    overflow-x: hidden;
}

a { color: var(--primary); text-decoration: none; }
img { max-width: 100%; display: block; }

.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 24px;
}

/* ========================================
   SCROLL REVEAL
   ======================================== */
.reveal {
    opacity: 0;
    transform: translateY(40px);
    transition: opacity 0.9s cubic-bezier(0.16, 1, 0.3, 1),
                transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}
.reveal.visible {
    opacity: 1;
    transform: translateY(0);
}

/* ========================================
   NAV
   ======================================== */
.nav {
    position: fixed;
    top: 16px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 1000;
    padding: 0 8px 0 24px;
    height: 56px;
    width: calc(100% - 48px);
    max-width: 1100px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    background: rgba(255, 255, 255, 0.92);
    backdrop-filter: blur(24px);
    -webkit-backdrop-filter: blur(24px);
    border-radius: 100px;
    box-shadow: 0 2px 16px rgba(0,0,0,0.06), 0 0 0 1px rgba(0,0,0,0.03);
    transition: box-shadow 0.3s ease;
}

.nav-logo {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 22px;
    color: var(--primary);
    letter-spacing: -0.5px;
}

.nav-center { flex: 1; display: flex; align-items: center; justify-content: center; gap: 36px; }
/* In flow, not absolutely centred. Absolute centring took the anchors
   out of the flex row, so the destinations added to the right zone
   rendered straight on top of them. */
.nav-link {
    font-size: 14px;
    font-weight: 500;
    color: var(--text-2);
    transition: color 0.2s;
}
.nav-link:hover { color: var(--text); }

.nav-right {
    display: inline-flex;
    align-items: center;
    gap: 10px;
}
.lang-switcher {
    display: inline-flex;
    align-items: center;
    background: rgba(0, 0, 0, 0.04);
    border-radius: 100px;
    padding: 3px;
    gap: 2px;
}
.lang-option {
    padding: 6px 11px;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-2);
    border-radius: 100px;
    text-decoration: none;
    line-height: 1;
    letter-spacing: 0.3px;
    transition: color 0.2s, background 0.2s, box-shadow 0.2s;
}
.lang-option.active {
    background: #fff;
    color: var(--text);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
    cursor: default;
    pointer-events: none;
}
.lang-option:not(.active):hover {
    color: var(--text);
}

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    font-family: var(--font-body);
    font-weight: 600;
    font-size: 14px;
    border: none;
    cursor: pointer;
    transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
.btn-primary {
    background: var(--primary);
    color: var(--white);
    padding: 12px 24px;
    border-radius: 100px;
}
.btn-primary:hover {
    background: var(--primary-dark);
    transform: translateY(-2px);
    box-shadow: 0 8px 24px rgba(44, 110, 70, 0.25);
}
/* Apple mark on the App Store CTA. currentColor so it tracks the button's
   text colour; the -1px lifts it into optical centre against the cap height. */
.btn-icon {
    width: 15px;
    height: 15px;
    flex-shrink: 0;
    margin-top: -1px;
}

/* ========================================
   JOURNEY (TOF-630)
   Chapter text on the left carries every word; one pinned stage on the
   right shows the same thing in the app's own UI. The stage is drawn at a
   540 x 640 design size; CSS sizes its box (--fit-w) and the shared
   homepage script scales the drawing to fill it (--s). Each chapter's
   layout is a `.stage[data-step="N"]` rule; timed sequences (the recipe
   counter) live in the script.
   ======================================== */
.journey {
    max-width: 1200px;
    margin: 0 auto;
    padding: 104px 24px 0;          /* clears the fixed nav pill */
    display: flex;
    align-items: flex-start;
    gap: clamp(40px, 6vw, 96px);
    position: relative;
    z-index: 1;
}
.chapters { flex: 1 1 0; min-width: 0; }
.chapter {
    min-height: calc(var(--len, 85) * 1vh);
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding-block: var(--space-section-sm);
}
.chapter-hero { min-height: calc(100svh - 104px); padding-block: var(--space-xxxl); }
/* Every chapter after the hero is a stretch of scroll that its stage changes
   are spread over (TOF-633, the Journey section of the shared script): the
   copy holds still near the middle of the screen while the reader scrolls
   through the chapter, then moves on with it. The more a chapter changes, the
   longer it is. */
.chapter:not(.chapter-hero) { justify-content: flex-start; }
.chapter-copy { position: sticky; top: max(120px, 50vh - 170px); }
/* in vh; phones take 15 less, in svh */
#library { --len: 95; }
#kitchen { --len: 110; }
#one-recipe { --len: 85; }
#adapt, #shop { --len: 155; }
#cook, #keep { --len: 125; }
/* The stage stays pinned only while the journey is on screen; room under the
   last chapter keeps it pinned until that chapter's sequence has played.
   Margin, not padding: chapters are border-box with a min-height, so extra
   padding would be absorbed and add nothing, and on phones `.chapters` is
   `display: contents`, so padding there would be ignored too. */
.chapter:last-child { margin-bottom: 40vh; }
.chapter h2, .section-title {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: clamp(30px, 3.3vw, 46px);
    line-height: 1.04;
    letter-spacing: -1px;
    color: var(--text);
    margin: 0 0 var(--space-xl);
    text-wrap: balance;
}
.chapter h2 { max-width: 15ch; }
.section-title { max-width: 24ch; }
.chapter-body, .hero-sub, .section-subtitle {
    font-size: 17px;
    line-height: 1.65;
    color: var(--text-2);
    max-width: 42ch;
}

/* ---- hero copy ---- */
/* Phones show her photo behind the headline. Desktop shows her on the stage,
   which is hidden from assistive tech, so here the photo stays in the page,
   visually hidden, for its description. Same file as the stage's: one download. */
.hero-photo { position: absolute; width: 1px; height: 1px; clip-path: inset(50%); }
.chapter-hero h1 {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: clamp(44px, 5.2vw, 74px);
    line-height: 0.98;
    letter-spacing: -2.4px;
    color: var(--text);
    margin: 0 0 var(--space-xl);
    text-wrap: balance;
    animation: rise 0.8s cubic-bezier(0.2, 0.8, 0.3, 1) 0.05s both;
}
/* Slovak headline: smaller and looser so the longer words keep to three lines. */
:where(:lang(sk)) .chapter-hero h1 {
    font-size: clamp(38px, 4.3vw, 62px);
    line-height: 1.0;
    letter-spacing: -1.9px;
}
.chapter-hero h1 em, .about-text blockquote em {
    position: relative;
    font-style: normal;
    color: var(--primary);
    white-space: nowrap;
}
/* the hand-drawn underline under the accent phrase, drawn once on load */
.u-line {
    position: absolute;
    left: -2%;
    bottom: -0.16em;
    width: 104%;
    height: 0.3em;
    overflow: visible;
    pointer-events: none;
}
.u-line path {
    fill: none;
    stroke: var(--secondary);
    stroke-width: 4;
    stroke-linecap: round;
    vector-effect: non-scaling-stroke;
    stroke-dasharray: 1;
    stroke-dashoffset: 1;
    animation: draw 1.1s var(--out) 0.5s forwards;
}
@keyframes draw { to { stroke-dashoffset: 0; } }
@keyframes rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

.hero-sub { animation: rise 0.7s cubic-bezier(0.2, 0.8, 0.3, 1) 0.42s both; }
.hero-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-md);
    margin-top: var(--space-xxl);
    animation: rise 0.7s cubic-bezier(0.2, 0.8, 0.3, 1) 0.54s both;
}
.hero-actions .app-store-link img { height: 56px; }
.hero-actions .android-badge { --badge-h: 56px; }
/* TOF-578: the Android waitlist is a second store-style badge beside
   the App Store one, and the App Store one stays first on every device.
   Built in HTML rather than as an SVG file so it uses the page font and
   localises like any other text. Google's Play badge is a trademark that
   may not be modified, so this uses the CC BY Android robot (attribution
   in the footer). Everything is derived from --badge-h. */
.android-badge {
    --badge-h: 64px;
    display: inline-flex;
    align-items: center;
    gap: calc(var(--badge-h) * 0.11);
    height: var(--badge-h);
    padding: 0 calc(var(--badge-h) * 0.22) 0 calc(var(--badge-h) * 0.18);
    border-radius: calc(var(--badge-h) * 0.165);
    background: #000;
    color: var(--white);
    border: 1px solid #a6a6a6;
    font-family: var(--font-body);
    text-decoration: none;
    cursor: pointer;
    transition: transform 0.2s ease;
}
.android-badge:hover { transform: scale(1.04); text-decoration: none; }
.android-badge-icon { width: calc(var(--badge-h) * 0.47); height: calc(var(--badge-h) * 0.47); fill: #3DDC84; flex-shrink: 0; }
.android-badge-text { display: flex; flex-direction: column; line-height: 1.05; text-align: left; }
.android-badge-text small { font-size: calc(var(--badge-h) * 0.18); font-weight: 500; letter-spacing: 0.01em; opacity: 0.92; }
.android-badge-text strong { font-size: calc(var(--badge-h) * 0.34); font-weight: 600; letter-spacing: -0.01em; white-space: nowrap; }

/* real App Store reviews, above the fold */
.hero-proof {
    margin: var(--space-xxl) 0 0;
    max-width: 30rem;
    animation: rise 0.7s cubic-bezier(0.2, 0.8, 0.3, 1) 0.66s both;
}
.hero-proof-top {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    margin-bottom: var(--space-md);
}
.hero-proof .stars { color: var(--secondary); font-size: 16px; letter-spacing: 3px; }
.hero-proof-src { font-size: 13px; font-weight: 500; color: var(--text-2); }
/* quotes are grid-stacked so swapping one for another can't shift the page */
.hero-quotes { display: grid; }
.hero-quotes blockquote {
    grid-area: 1 / 1;
    margin: 0;
    font-size: 18px;
    font-weight: 500;
    line-height: 1.5;
    color: var(--text);
    opacity: 0;
    /* outgoing quote leaves immediately... */
    transition: opacity 0.32s ease;
}
/* ...and the incoming one waits for it to clear */
.hero-quotes blockquote.is-on {
    opacity: 1;
    transition: opacity 0.38s ease 0.36s;
}

/* ---- the stage ----
   --fit-w is the stage's on-screen width: as big as the height under the nav
   pill (88px) allows once the progress segments above it (30px, with their
   gap) and a margin (32px) are in, at most half the width beside the text,
   never under 0.42 of the design size. The column is centred in the height
   left under the nav.
   --tone is the chapter's colour: the stage paints it, on phones the band. */
.stage-col {
    --fit-w: max(226.8px, min(540px, (100svh - 150px) * 540 / 640, 50vw));
    --tone: var(--tone-oat);
    flex: none;
    position: sticky;
    top: max(88px, (100svh + 42px - var(--fit-w) * 640 / 540) / 2);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-lg);
    padding-block: var(--space-sm);
}
.stage-fit { width: var(--fit-w); height: calc(var(--fit-w) * 640 / 540); contain: strict; }
.stage {
    position: relative;
    width: 540px;
    height: 640px;
    transform: scale(var(--s, 1));
    transform-origin: 0 0;
    border-radius: 32px;
    overflow: hidden;
    background-color: var(--tone);
    transition: background-color 0.8s ease;
}
/* one line per chapter's tone */
.stage-col[data-step="2"] { --tone: var(--tone-sage); }
.stage-col[data-step="3"] { --tone: var(--tone-butter); }
.stage-col[data-step="4"] { --tone: var(--tone-peach); }
.stage-col[data-step="6"], .stage-col[data-step="7"] { --tone: var(--primary); }
/* on a phone's green band the progress segments go white; above the desktop
   stage they sit on the page, so they stay green */
@media (max-width: 699px) {
    .stage-col[data-step="6"], .stage-col[data-step="7"] { --rail: rgba(255, 255, 255, 0.28); --rail-on: var(--white); }
}

/* Nikoleta: the hero, then the library's header tile */
.st-nika {
    position: absolute;
    z-index: 2;
    left: 0;
    top: 0;
    width: 540px;
    height: 640px;
    border-radius: 32px;
    overflow: hidden;
    background: #2B3A2E;
    transition: left 0.85s var(--spring-soft), top 0.85s var(--spring-soft),
                width 0.85s var(--spring-soft), height 0.85s var(--spring-soft),
                border-radius 0.6s var(--out), opacity 0.4s ease;
}
.st-nika img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 26%; }
.st-nika::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(10, 24, 14, 0.74) 0%, rgba(10, 24, 14, 0) 44%);
    transition: opacity 0.4s ease;
}
.stage:not([data-step="0"]) .st-nika { left: 24px; top: 24px; width: 64px; height: 64px; border-radius: 18px; }
.stage:not([data-step="0"]) .st-nika::after { opacity: 0; }
.stage:not([data-step="0"]):not([data-step="1"]) .st-nika { opacity: 0; }
/* the caption leaves the right side to the phone */
.st-nika-cap {
    position: absolute;
    z-index: 3;
    left: 36px;
    right: 226px;
    bottom: 36px;
    color: var(--white);
    transition: opacity 0.25s ease;
}
.st-nika-name { font-family: var(--font-display); font-weight: 700; font-size: 34px; line-height: 1; letter-spacing: -0.5px; }
.st-nika-line { margin-top: var(--space-md); font-size: 14px; line-height: 1.5; color: rgba(255, 255, 255, 0.85); }
.stage:not([data-step="0"]) .st-nika-cap { opacity: 0; }

/* TOF-642: the app beside her, so the hero reads as an app and not a cookbook.
   The app's own recipe screen (RecipeDetailView: photo, title, the green
   metadata block, Start Cooking) for a real recipe; its numbers are checked
   against the database by scripts/landing-library.mjs. Desktop only: on phones
   the hero card is the photo and the band below shows the app one swipe later. */
.st-phone {
    position: absolute;
    z-index: 4;
    right: 26px;
    bottom: 26px;
    width: 170px;
    height: 348px;
    padding: 6px;
    border-radius: 34px;
    background: #111;
    box-shadow: 0 24px 48px -12px rgba(0, 0, 0, 0.45);
    overflow: hidden; /* the sliding screen stops at the bezel */
    transition: opacity 0.35s ease, transform 0.6s var(--out);
}
.stage:not([data-step="0"]) .st-phone { opacity: 0; transform: translateY(24px) scale(0.96); }
.st-phone-screen { position: relative; height: 100%; border-radius: 28px; overflow: hidden; background: var(--bg); color: var(--text); }
/* The hero phone changes recipe on a timer (TOF-642): the screen slides out to
   the left, swaps, and the next one comes in from the right. The bezel clips it.
   The slide itself is animated in home-v{N}.js, so the screen's resting state is
   always this one: a browser that never runs it shows a plain swap, not a
   half-slid screen. */
.st-phone-photo { position: relative; height: 176px; background: var(--surface-2); }
.st-phone-photo img { width: 100%; height: 100%; object-fit: cover; }
/* the Dynamic Island, on the bezel: the screen slides under it */
.st-phone::before { content: ""; position: absolute; z-index: 2; left: 50%; top: 13px; width: 46px; height: 14px; margin-left: -23px; border-radius: 10px; background: #111; }
.st-phone .st-badge { right: 8px; bottom: 8px; padding: 2px 8px; font-size: 10px; line-height: 1.6; opacity: 1; }
.st-phone-body { padding: 10px 11px 0; }
.st-phone-title { font-family: var(--font-display); font-weight: 700; font-size: 18px; line-height: 1.05; letter-spacing: -0.2px; }
.st-phone-meta { display: flex; margin-top: 10px; padding: 7px 2px; border-radius: 10px; background: var(--primary); color: var(--white); }
.st-phone-meta span { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 1px; font-size: 9px; font-weight: 600; line-height: 1.25; white-space: nowrap; }
.st-phone-meta svg { width: 11px; height: 11px; margin-bottom: 2px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.st-phone-meta small { font-size: 7.5px; font-weight: 500; color: rgba(255, 255, 255, 0.6); }
.st-phone-cta { position: absolute; left: 11px; right: 11px; bottom: 12px; padding: 9px 0; border-radius: 100px; background: var(--primary); color: var(--white); font-size: 11px; font-weight: 600; text-align: center; box-shadow: 0 6px 14px -6px rgba(44, 110, 70, 0.6); }
@media (max-width: 699px) { .st-phone { display: none; } }

/* the library */
.st-lib-head {
    position: absolute;
    left: 104px;
    top: 24px;
    height: 64px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 6px;
    opacity: 0;
    transform: translateX(-10px);
    transition: opacity 0.25s ease, transform 0.4s var(--out);
}
.stage[data-step="1"] .st-lib-head { opacity: 1; transform: none; transition: opacity 0.4s ease 0.45s, transform 0.6s var(--out) 0.45s; }
.st-lib-label { font-size: 11.5px; font-weight: 600; line-height: 1; letter-spacing: 1.4px; text-transform: uppercase; color: var(--text-2); opacity: 0.8; }
.st-lib-count { display: flex; align-items: baseline; gap: 10px; }
.st-lib-count b { min-width: 3.2ch; font-family: var(--font-display); font-weight: 700; font-size: 34px; line-height: 1; letter-spacing: -0.5px; color: var(--primary); font-variant-numeric: tabular-nums; }
.st-lib-count span { font-size: 13px; color: var(--text-2); }
/* the app's chip row: it scrolls sideways and fades out at the edge */
.st-chips {
    position: absolute;
    left: 24px;
    right: 0;
    top: 108px;
    display: flex;
    gap: var(--space-sm);
    padding-right: var(--space-xl);
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 48px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 48px), transparent);
    opacity: 0;
    transition: opacity 0.25s ease;
}
.st-chips::-webkit-scrollbar { display: none; }
.stage[data-step="1"] .st-chips { opacity: 1; transition: opacity 0.4s ease 0.55s; }
.st-chip { flex: none; padding: 8px 13px; border-radius: 100px; background: var(--surface); border: 1px solid var(--surface-2); font-size: 13px; font-weight: 500; line-height: 1; white-space: nowrap; color: var(--text-2); transition: background-color 0.25s ease, border-color 0.25s ease, color 0.25s ease; }
.st-chip.is-on { background: var(--primary); border-color: var(--primary); color: var(--white); }
.stage[data-step="1"] .st-chip { cursor: pointer; }
@media (hover: hover) {
    .stage[data-step="1"] .st-chip:not(.is-on):hover { border-color: var(--primary); color: var(--text); }
}
.st-thumb {
    position: absolute;
    width: 94px;
    height: 94px;
    border-radius: 14px;
    overflow: hidden;
    background: var(--surface-2);
    box-shadow: 0 6px 16px -10px rgba(26, 45, 26, 0.45);
    transition: opacity 0.2s ease, transform 0.3s ease, scale 0.3s var(--out);
}
.st-thumb img { width: 100%; height: 100%; object-fit: cover; }
/* --w is the cell's row + column, so the grid fills in a diagonal wave */
.stage[data-step="1"] .st-thumb {
    opacity: 1;
    transform: none;
    transition: opacity 0.3s ease calc(300ms + var(--w) * 55ms),
                transform 0.75s var(--spring) calc(300ms + var(--w) * 55ms),
                scale 0.3s var(--out);
}
/* past the library the others fly outward from the chosen card: the zoom */
.stage:not([data-step="0"]):not([data-step="1"]) .st-thumb {
    opacity: 0;
    transform: translate(var(--zx), var(--zy)) scale(1.35);
    transition: opacity 0.45s ease, transform 0.8s var(--out), scale 0.3s var(--out);
}
/* the tiles' hidden pose: before the library, and while a filter pill swaps
   the set (the tiles drop out, then wave back in with the new one) */
.st-thumb, .stage.is-swapping .st-thumb { opacity: 0; transform: translateY(-28px) scale(0.82); }
.stage.is-swapping .st-thumb { transition: opacity 0.18s ease, transform 0.25s ease; }
.st-thumb.is-empty { visibility: hidden; }
.st-more { position: absolute; left: 0; right: 0; top: 578px; display: flex; justify-content: center; opacity: 0; transition: opacity 0.25s ease; }
.st-more span { padding: 10px 16px; border-radius: 100px; background: var(--surface); box-shadow: 0 4px 14px -6px rgba(15, 31, 15, 0.2); font-size: 13px; font-weight: 600; line-height: 1; color: var(--text-2); }
.stage[data-step="1"] .st-more { opacity: 1; transition: opacity 0.4s ease 1.5s; }
.stage.is-filtered .st-more { opacity: 0; transition: opacity 0.2s ease; }

/* the one recipe card that travels; its base position is its library cell
   (cell 7 of the grid the shared homepage script lays out) */
.st-card {
    --od: 0s;
    position: absolute;
    z-index: 3;
    left: 223px;
    top: 260px;
    width: 94px;
    height: 94px;
    border-radius: 14px;
    overflow: hidden;
    background: var(--surface);
    box-shadow: 0 6px 16px -10px rgba(26, 45, 26, 0.45);
    transition: left 0.8s var(--spring-soft), top 0.8s var(--spring-soft),
                width 0.8s var(--spring-soft), height 0.8s var(--spring-soft),
                border-radius 0.6s var(--out), box-shadow 0.5s ease, opacity 0.3s ease var(--od),
                scale 0.3s var(--out);
}
.stage[data-step="0"] .st-card { opacity: 0; }
.stage[data-step="1"] .st-card { --od: 0.46s; }
/* a category fills the card's cell, so the card steps aside (and comes back with "All") */
.stage.is-filtered .st-card { --od: 0s; opacity: 0; pointer-events: none; }
/* the spotlight: the Kitchen's first result lifts out of the list */
.stage[data-step="3"] .st-card {
    left: 70px;
    top: 114px;
    width: 400px;
    height: 412px;
    border-radius: 26px;
    box-shadow: 0 26px 60px -26px rgba(26, 45, 26, 0.38), 0 2px 6px rgba(26, 45, 26, 0.06);
}
.st-photo { position: absolute; left: 0; top: 0; width: 100%; height: 94px; overflow: hidden; background: var(--surface-2); transition: width 0.8s var(--spring-soft), height 0.8s var(--spring-soft); }
.st-photo img { width: 100%; height: 100%; object-fit: cover; }
.stage[data-step="3"] .st-photo { height: 280px; }
.st-badge { position: absolute; right: 10px; bottom: 10px; padding: 3px 10px; border-radius: 100px; background: rgba(44, 110, 70, 0.9); color: var(--white); font-size: 12px; font-weight: 700; line-height: 1.5; white-space: nowrap; opacity: 0; transition: opacity 0.3s ease; }
.stage[data-step="2"] .st-badge, .stage[data-step="3"] .st-badge { opacity: 1; }
.st-face { position: absolute; left: 0; right: 0; opacity: 0; visibility: hidden; transition: opacity 0.22s ease, visibility 0s linear 0.22s; }
.stage[data-step="3"] .st-face-recipe { opacity: 1; visibility: visible; transition: opacity 0.4s ease 0.32s, visibility 0s; }
.st-face-recipe { top: 280px; padding: var(--space-xl); }
.st-title { font-family: var(--font-display); font-weight: 700; font-size: 27px; line-height: 1.08; letter-spacing: -0.4px; color: var(--text); text-wrap: balance; }
.st-meta { display: flex; flex-wrap: wrap; margin-top: var(--space-sm); font-size: 13px; color: var(--text-2); }
.st-meta span + span::before { content: "\00B7"; margin: 0 7px; }

/* hovering a tile opens it into the app's recipe card (RecipeCardView): photo
   with the heart and the protein badge, then the name and the time. It pops
   out of the tile, then glides from tile to tile (is-moving). */
.st-peek {
    position: absolute;
    z-index: 5;
    left: 0;
    top: 0;
    width: 170px;
    border-radius: 16px;
    overflow: hidden;
    background: var(--surface);
    box-shadow: 0 18px 40px -18px rgba(26, 45, 26, 0.5), 0 2px 6px rgba(26, 45, 26, 0.08);
    opacity: 0;
    transform: scale(0.55);
    pointer-events: none;
    transition: opacity 0.15s ease, transform 0.2s ease;
}
.st-peek.is-on { opacity: 1; transform: none; transition: opacity 0.15s ease, transform 0.35s var(--spring); }
.st-peek.is-moving { transition: opacity 0.15s ease, transform 0.35s var(--spring), translate 0.25s var(--out); }
.st-peek-photo { position: relative; height: 118px; background: var(--surface-2); }
.st-peek-photo img { width: 100%; height: 100%; object-fit: cover; }
.st-peek-heart { position: absolute; left: 8px; top: 8px; display: grid; place-items: center; width: 26px; height: 26px; border-radius: 50%; background: rgba(0, 0, 0, 0.3); }
.st-peek-heart svg { width: 13px; height: 13px; fill: none; stroke: var(--white); stroke-width: 2.4; stroke-linejoin: round; }
.st-peek .st-badge { right: 8px; bottom: 8px; padding: 3px 8px; font-size: 11px; line-height: 1.4; opacity: 1; }
.st-peek-body { padding: var(--space-sm) var(--space-md) var(--space-md); }
.st-peek-title { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; min-height: 2.5em; font-size: 14px; font-weight: 600; line-height: 1.25; color: var(--text); }
/* a card's time with the clock, in the hover card and the Kitchen's cards */
.st-time { display: flex; align-items: center; gap: var(--space-xs); margin-top: 6px; font-size: 11px; font-weight: 500; color: var(--text-2); }
.st-time svg { width: 11px; height: 11px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; }

/* ---- chapter 2, the Kitchen: the app's My Kitchen with its results
   (FridgeResultsView). The chips are what's at home; under them, the recipes
   they match in the app's order, as its two-column grid of cards with the
   tilted "You have X of Y" sticker (FridgeMatchSticker). The recipe card is
   the first; the shared homepage script copies it for the rest. The second
   row runs off the stage's bottom edge, the way a list runs off a screen. ---- */
.st-kitchen {
    position: absolute;
    left: 24px;
    right: 24px;
    top: 24px;
    opacity: 0;
    transform: translateY(8px);
    transition: opacity 0.25s ease, transform 0.3s var(--out);
}
.stage[data-step="2"] .st-kitchen { opacity: 1; transform: none; transition: opacity 0.4s ease 0.2s, transform 0.5s var(--out) 0.2s; }
.st-kitchen-title { font-family: var(--font-display); font-weight: 700; font-size: 28px; line-height: 1; letter-spacing: -0.4px; color: var(--text); }
.st-kitchen-label { margin-top: 18px; font-size: 11.5px; font-weight: 600; line-height: 1; letter-spacing: 1.4px; text-transform: uppercase; color: var(--text-2); opacity: 0.8; }
.st-fridge { display: flex; flex-wrap: wrap; gap: var(--space-sm); margin-top: var(--space-md); }
/* --i staggers the chips landing, like ingredients added one by one */
.st-ing {
    padding: 8px 12px;
    border-radius: 100px;
    background: var(--surface);
    border: 1px solid var(--surface-2);
    font-size: 13px;
    font-weight: 500;
    line-height: 1;
    white-space: nowrap;
    color: var(--text-2);
    opacity: 0;
    transform: translateY(-14px) scale(0.9);
    transition: opacity 0.2s ease, transform 0.2s ease;
}
.stage[data-step="2"] .st-ing {
    opacity: 1;
    transform: none;
    transition: opacity 0.3s ease calc(250ms + var(--i) * 50ms), transform 0.6s var(--spring) calc(250ms + var(--i) * 50ms);
}
/* the app's section header, with its count of the whole list */
.st-kitchen-group { position: absolute; left: 24px; top: 222px; display: flex; align-items: center; gap: var(--space-sm); font-family: var(--font-display); font-weight: 700; font-size: 18px; line-height: 1; color: var(--text); opacity: 0; transition: opacity 0.25s ease; }
.stage[data-step="2"] .st-kitchen-group { opacity: 1; transition: opacity 0.4s ease 0.6s; }
.st-kitchen-count { padding: 4px 8px; border-radius: 100px; background: rgba(15, 31, 15, 0.07); font-family: var(--font-body); font-size: 11px; font-weight: 600; color: var(--text-2); }
/* the grid's first cell; the script puts the copies in the others */
.stage[data-step="2"] .st-card { left: 24px; top: 256px; width: 238px; height: 208px; border-radius: 16px; }
.stage[data-step="2"] .st-photo, .st-match .st-photo { height: 140px; }
.st-match {
    position: absolute;
    z-index: 2;
    width: 238px;
    height: 208px;
    border-radius: 16px;
    overflow: hidden;
    background: var(--surface);
    box-shadow: 0 6px 16px -10px rgba(26, 45, 26, 0.45);
    opacity: 0;
    transform: translateY(18px) scale(0.96);
    transition: opacity 0.2s ease, transform 0.3s ease;
}
.stage[data-step="2"] .st-match {
    opacity: 1;
    transform: none;
    transition: opacity 0.35s ease calc(650ms + var(--i) * 90ms), transform 0.6s var(--spring) calc(650ms + var(--i) * 90ms);
}
/* the card's face in the grid: RecipeCardView's name and time */
.st-face-list { top: 140px; padding: 10px 12px; }
.stage[data-step="2"] .st-face-list, .st-match .st-face-list { opacity: 1; visibility: visible; transition: opacity 0.4s ease 0.5s, visibility 0s; }
.st-list-title { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; min-height: 2.5em; font-size: 14.5px; font-weight: 600; line-height: 1.25; color: var(--text); }
.st-sticker {
    position: absolute;
    right: 8px;
    top: 8px;
    padding: 6px 12px;
    border-radius: 100px;
    background: var(--surface);
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.18);
    font-size: 12px;
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
    color: var(--text);
    font-variant-numeric: tabular-nums;
    transform: rotate(-2deg);
    opacity: 0;
    transition: opacity 0.2s ease;
}
.stage[data-step="2"] .st-sticker { opacity: 1; transition: opacity 0.3s ease 0.9s; }
/* the list fades out at the stage's bottom edge, like a screen that scrolls on;
   it waits for the stage's tone to finish changing */
.stage::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; z-index: 4; height: 64px; background: linear-gradient(to bottom, transparent, var(--tone)); opacity: 0; pointer-events: none; transition: opacity 0.2s ease; }
.stage[data-step="2"]::after { opacity: 1; transition: opacity 0.4s ease 0.7s; }

/* ---- chapters 4 and 5, Make it yours and Shop: only what changes, big. The
   card stays as the header; under it the app's two switches, the three rows
   they change, and the protein per serving (chapter 4) or the button that adds
   them to the shopping list (chapter 5). Each change happens on its own and
   grows for a moment, like a library tile under the cursor. ---- */
.stage:is([data-step="4"], [data-step="5"], [data-step="6"], [data-step="7"]) .st-card { left: 24px; top: 24px; width: 492px; height: 72px; border-radius: 16px; }
.stage:is([data-step="4"], [data-step="5"], [data-step="6"], [data-step="7"]) .st-photo { width: 72px; height: 72px; }
.stage:is([data-step="4"], [data-step="5"]) .st-face-list { top: 0; left: 72px; padding: 16px; opacity: 1; visibility: visible; transition: opacity 0.4s ease 0.45s, visibility 0s; }
.stage:is([data-step="4"], [data-step="5"]) .st-list-title { min-height: 0; -webkit-line-clamp: 1; font-size: 16px; }
.st-swap { position: absolute; left: 24px; right: 24px; top: 120px; bottom: 28px; display: flex; flex-direction: column; gap: 16px; opacity: 0; transform: translateY(12px); transition: opacity 0.25s ease, transform 0.3s var(--out); }
.stage:is([data-step="4"], [data-step="5"]) .st-swap { opacity: 1; transform: none; transition: opacity 0.4s ease 0.35s, transform 0.6s var(--out) 0.35s; }
/* the app's two switches, as big pills: outlined, then green */
.st-switches { display: flex; gap: 12px; }
.st-switch { flex: 1; display: flex; align-items: center; justify-content: center; gap: 8px; height: 54px; border-radius: 100px; background: var(--surface); box-shadow: inset 0 0 0 1.5px rgba(44, 110, 70, 0.3); font-size: 16px; font-weight: 600; line-height: 1; color: var(--primary); transition: background-color 0.35s ease, color 0.35s ease, box-shadow 0.35s ease, scale 0.4s var(--spring); }
.st-switch svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.st-switch .st-bolt { fill: currentColor; stroke: none; }
.stage.is-soyfree .st-switch[data-kind="soy"], .stage.is-boosted .st-switch[data-kind="boost"] { background: var(--primary); box-shadow: none; color: var(--white); }
/* the three rows they change; a row swaps on its own .is-on, one at a time */
.st-rows { display: flex; flex-direction: column; gap: 10px; }
.st-srow { display: flex; align-items: center; gap: 12px; min-height: 68px; padding: 10px 18px; border-radius: 16px; background: var(--surface); font-size: 18px; font-weight: 500; line-height: 1.25; color: var(--text); transition: background-color 0.4s ease, scale 0.4s var(--spring), box-shadow 0.4s ease; }
.st-srow.is-on { background: #E8F1E7; }
.st-srow > span { display: flex; flex-direction: column; gap: 3px; }
.st-srow small { font-size: 13px; font-weight: 400; line-height: 1.2; color: var(--text-2); }
.st-srow .st-now, .st-srow.is-on .st-was { display: none; }
.st-srow.is-on .st-now { display: flex; animation: st-swap-in 0.45s var(--out) both; }
@keyframes st-swap-in { from { opacity: 0; transform: translateY(5px); } }
/* chapter 5: why these three go to the list (the Kitchen's "missing") */
.st-stock { display: none; margin-left: auto; padding: 4px 10px; border-radius: 100px; background: rgba(214, 140, 69, 0.18); font-size: 12.5px; font-style: normal; font-weight: 600; line-height: 1.2; color: var(--text); white-space: nowrap; }
.stage[data-step="5"] .st-stock { display: inline-block; }
/* chapter 4: the protein per serving, with what the switches gain */
.st-protein { display: flex; align-items: center; justify-content: space-between; margin-top: auto; padding: 18px 22px; border-radius: 18px; background: var(--surface); transition: scale 0.4s var(--spring), box-shadow 0.4s ease; }
.st-protein p:first-child { font-size: 16px; font-weight: 500; color: var(--text-2); }
.st-protein p + p { position: relative; font-family: var(--font-display); font-weight: 700; font-size: 42px; line-height: 1; color: var(--text); font-variant-numeric: tabular-nums; }
.stage[data-step="5"] .st-protein { display: none; }
/* chapter 5: the recipe's button, in the protein's place */
.st-cart-btn { display: none; align-items: center; justify-content: center; gap: 10px; height: 60px; margin-top: auto; border-radius: 18px; background: var(--primary); font-size: 16px; font-weight: 600; color: var(--white); transition: scale 0.4s var(--spring), box-shadow 0.4s ease; }
.stage[data-step="5"] .st-cart-btn { display: flex; }
.st-cart-btn svg { width: 19px; height: 19px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.st-cart-btn .st-done, .stage.is-added .st-cart-btn .st-todo { display: none; }
.stage.is-added .st-cart-btn .st-done { display: inline; }

/* ---- chapter 5, the list: once the rows are added, the switches and rows
   give way to the Shopping List in the same tinted box, under the same card:
   one white card grouped by aisle, like the app's Shopping view. A seitan row
   another Kitchen result (the sviečková) needs is already on it; the cacio's
   rows land in their aisles and seitan merges. The button stays, "Added!". ---- */
.st-switches, .st-rows { transition: opacity 0.3s ease, translate 0.4s var(--out); }
.stage.is-listed .st-switches, .stage.is-listed .st-rows { opacity: 0; translate: 0 -10px; }
.st-shop { position: absolute; z-index: 3; left: 24px; right: 24px; top: 120px; opacity: 0; translate: 0 14px; transition: opacity 0.25s ease, translate 0.3s var(--out); }
.stage.is-listed .st-shop { opacity: 1; translate: none; transition: opacity 0.4s ease 0.2s, translate 0.6s var(--spring-soft) 0.2s; }
.st-shop-title { margin-bottom: var(--space-md); font-family: var(--font-display); font-weight: 700; font-size: 24px; line-height: 1.1; color: var(--text); }
.st-shop-list { padding-block: 6px; border-radius: 18px; background: var(--surface); box-shadow: 0 14px 32px -22px rgba(26, 45, 26, 0.4); }
.st-aisle, .st-aisle-new > div > div { padding: 10px 20px; }
.st-aisle-name { display: flex; align-items: center; gap: var(--space-sm); margin-bottom: var(--space-xs); font-size: 15px; font-weight: 500; line-height: 1.2; color: var(--text-2); }
.st-aisle-name svg { width: 15px; height: 15px; fill: none; stroke: var(--primary); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
/* an aisle the cacio adds opens as its row lands */
.st-aisle-new { display: grid; grid-template-rows: 0fr; padding: 0; opacity: 0; transition: grid-template-rows 0.5s var(--out), opacity 0.3s ease; }
.st-aisle-new > div { min-height: 0; overflow: hidden; }
.stage.is-pasta .st-new-pasta, .stage.is-oat .st-new-oat { grid-template-rows: 1fr; opacity: 1; }
/* ShoppingListView's row: tick circle, amount and name over the recipe, a delete x */
.st-item { display: flex; align-items: center; gap: var(--space-md); margin: 0 -8px; padding: 5px 8px; border-radius: 10px; font-size: 16px; line-height: 1.3; color: var(--text); font-variant-numeric: tabular-nums; transition: scale 0.4s var(--spring), background-color 0.4s ease; }
.st-item::before { content: ""; flex: none; width: 20px; height: 20px; border-radius: 50%; border: 1.5px solid rgba(74, 90, 74, 0.4); }
.st-item::after { content: "\00D7"; margin-left: auto; font-size: 16px; line-height: 1; color: rgba(74, 90, 74, 0.5); }
.st-item > span { display: flex; flex-direction: column; gap: 2px; }
.st-item small { font-size: 12.5px; line-height: 1.2; color: var(--text-2); }
/* seitan: the sviečková's row, then both recipes' in one, "2 recipes" */
.st-merge small i { font-style: normal; }
.st-merge small i + i, .stage.is-merged .st-merge small i:first-child { display: none; }
.stage.is-merged .st-merge small i + i { display: inline-flex; align-items: center; gap: 3px; }
.st-merge small svg { width: 9px; height: 9px; fill: none; stroke: currentColor; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }

/* Every chapter's layers stay in the stage, invisible outside their step, so
   nothing in it takes the pointer (the Kitchen's layers once sat over the
   library's filter pills) but the controls of the step on show: the filter
   pills and chapter 4's switches. The library's hover reads the pointer's
   position on the stage itself. */
.stage * { pointer-events: none; }
.stage[data-step="1"] .st-chip[data-cat], .stage[data-step="4"] .st-switch { pointer-events: auto; cursor: pointer; }

/* what is changing grows for a moment, like a library tile under the cursor */
.is-grow { position: relative; z-index: 2; scale: 1.05; box-shadow: 0 18px 36px -16px rgba(26, 45, 26, 0.45); }
.st-item.is-grow { scale: 1.03; box-shadow: none; background: #E8F1E7; }
/* a gain: the protein's over the recipe as written, the cacio's share of the seitan */
.st-delta { position: absolute; top: 50%; right: calc(100% + 10px); translate: 0 -50%; padding: 3px 8px; border-radius: 100px; background: var(--primary); font-family: var(--font-body); font-size: 12px; font-style: normal; font-weight: 700; line-height: 1.3; color: var(--white); white-space: nowrap; opacity: 0; scale: 0.6; transition: opacity 0.25s ease, scale 0.35s var(--spring); }
.st-delta.is-on { opacity: 1; scale: 1; }
.st-merge .st-delta { position: static; translate: none; margin-left: 6px; font-size: 11px; }
.stage.is-merged .st-merge .st-delta { opacity: 1; scale: 1; }
/* a missing row's name on its way into the button */
.st-fly { position: absolute; z-index: 6; padding: 5px 12px; border-radius: 100px; background: var(--secondary); font-size: 14px; font-weight: 600; line-height: 1.3; color: var(--white); white-space: nowrap; pointer-events: none; box-shadow: 0 6px 16px -6px rgba(214, 140, 69, 0.7); }

/* ---- chapter 6, Cook: Cook Mode, the app's green screen, fills the stage and
   the card steps aside. Step 2 and its timer, which starts and counts down from
   its real length; then Next, step 3 slides in, and the timer keeps running in
   the bar at the bottom, as it does in the app. One change at a time. ---- */
.stage:is([data-step="6"], [data-step="7"]) .st-card { opacity: 0; }
/* chapters 6 and 7 are whole app screens over the stage */
.st-cook, .st-keep { position: absolute; inset: 0; z-index: 3; color: var(--white); text-align: center; opacity: 0; transform: scale(0.97); transition: opacity 0.25s ease, transform 0.3s var(--out); }
.stage[data-step="6"] .st-cook, .stage[data-step="7"] .st-keep { opacity: 1; transform: none; transition: opacity 0.5s ease 0.3s, transform 0.7s var(--spring-soft) 0.3s; }
.st-cook-title { position: absolute; left: 40px; right: 40px; top: 30px; font-size: 15px; font-weight: 700; line-height: 1.2; color: rgba(255, 255, 255, 0.7); }
.st-cook-pill { position: absolute; left: 50%; top: 68px; translate: -50% 0; padding: 5px 14px; border-radius: 100px; background: var(--secondary); font-size: 15px; font-weight: 500; line-height: 1.3; white-space: nowrap; }
.st-cook-pill span + span, .stage.is-step3 .st-cook-pill span:first-child { display: none; }
.stage.is-step3 .st-cook-pill span + span { display: inline; }
/* the step in the middle; step 3 comes in from the right as step 2 leaves left */
.st-cook-steps { position: absolute; left: 36px; right: 36px; top: 112px; bottom: 124px; }
.st-cook-step { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 20px; transition: opacity 0.35s ease, translate 0.55s var(--out); }
.st-cook-3 { opacity: 0; translate: 70px 0; }
.stage.is-step3 .st-cook-2 { opacity: 0; translate: -70px 0; }
.stage.is-step3 .st-cook-3 { opacity: 1; translate: none; }
.st-cook-chips span { display: inline-block; padding: 6px 14px; border-radius: 100px; background: rgba(255, 255, 255, 0.15); font-size: 14px; font-weight: 600; line-height: 1.3; font-variant-numeric: diagonal-fractions; }
.st-cook-text { font-family: var(--font-display); font-weight: 600; font-size: 25px; line-height: 1.28; text-wrap: balance; }
/* the step's timer: a start capsule, then the running card with its ring */
.st-timer-start { display: inline-flex; align-items: center; gap: 8px; padding: 12px 18px; border-radius: 100px; background: rgba(255, 255, 255, 0.15); font-size: 15px; font-weight: 500; line-height: 1.2; transition: scale 0.4s var(--spring), box-shadow 0.4s ease; }
.st-timer-start svg { width: 16px; height: 16px; fill: currentColor; }
.st-timer-start i { font-style: normal; opacity: 0.6; }
.st-timer-card { display: none; flex-direction: column; align-items: center; gap: 6px; padding: 14px 30px 12px; border-radius: 16px; background: var(--surface); color: var(--text); }
.stage.is-timing .st-timer-start { display: none; }
.stage.is-timing .st-timer-card { display: flex; animation: st-pop 0.5s var(--spring) both; }
@keyframes st-pop { from { opacity: 0; scale: 0.85; } }
.st-ring { position: relative; width: 84px; height: 84px; }
.st-ring svg { width: 100%; height: 100%; rotate: -90deg; fill: none; stroke-width: 6; }
.st-ring circle { stroke: var(--surface-2); }
.st-ring .st-ring-on { stroke: var(--primary); stroke-linecap: round; stroke-dasharray: 100; stroke-dashoffset: 100; transition: stroke-dashoffset 1s linear; }
.st-ring b { position: absolute; inset: 0; display: grid; place-items: center; font-family: var(--font-display); font-weight: 600; font-size: 22px; font-variant-numeric: tabular-nums; }
.st-timer-card small { font-size: 12px; line-height: 1.2; color: var(--text-2); }
/* a timer running on another step: the app's floating bar, above the dots */
.st-timerbar { position: absolute; left: 36px; right: 36px; bottom: 124px; display: flex; align-items: center; gap: 10px; padding: 10px 14px; border-radius: 12px; background: var(--surface); color: var(--text); font-size: 14px; line-height: 1.2; text-align: left; opacity: 0; translate: 0 14px; transition: opacity 0.3s ease, translate 0.5s var(--out), scale 0.4s var(--spring), box-shadow 0.4s ease; }
.stage.is-step3.is-timing .st-timerbar { opacity: 1; translate: none; }
.st-timerbar b { flex: none; display: grid; place-items: center; width: 22px; height: 22px; border-radius: 50%; background: var(--primary); color: var(--white); font-size: 11px; }
.st-timerbar span { flex: 1; }
.st-timerbar i { font-style: normal; font-weight: 700; color: var(--primary); font-variant-numeric: tabular-nums; }
.stage.is-done .st-ring b, .stage.is-done .st-timerbar i { color: var(--secondary); }
/* the progress dots: two ingredient screens, then the eight steps */
.st-dots { position: absolute; left: 0; right: 0; bottom: 96px; display: flex; justify-content: center; align-items: center; gap: 8px; }
.st-dots i { width: 6px; height: 6px; border-radius: 50%; background: rgba(255, 255, 255, 0.3); transition: width 0.3s ease, height 0.3s ease, background-color 0.3s ease; }
.st-dots i:nth-child(4), .stage.is-step3 .st-dots i:nth-child(5) { width: 8px; height: 8px; background: var(--white); }
.stage.is-step3 .st-dots i:nth-child(4) { width: 6px; height: 6px; background: rgba(255, 255, 255, 0.3); }
.st-cook-nav { position: absolute; left: 36px; right: 36px; bottom: 28px; display: flex; gap: 16px; }
.st-cook-nav span { flex: 1; display: flex; align-items: center; justify-content: center; gap: 6px; height: 50px; border-radius: 12px; font-size: 16px; font-weight: 600; line-height: 1; transition: scale 0.4s var(--spring), box-shadow 0.4s ease; }
.st-cook-nav span:first-child { background: rgba(255, 255, 255, 0.12); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.3); }
.st-cook-nav .st-next { background: var(--white); color: var(--primary); }
.st-cook-nav svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; }

/* ---- chapter 7, Keep: the app's end of cooking, on the same green. "Time to
   eat!" with its emoji confetti; the heart grows and fills, and as in the app
   that opens the collections sheet; one collection takes the recipe and its
   count goes up by one. The collections are made up: they are a reader's own. ---- */
.st-keep { overflow: hidden; }
.st-keep-title { position: absolute; left: 36px; right: 36px; top: 60px; font-family: var(--font-display); font-weight: 700; font-size: 36px; line-height: 1.1; }
.st-keep-recipe { position: absolute; left: 36px; right: 36px; top: 110px; font-size: 16px; line-height: 1.3; color: rgba(255, 255, 255, 0.7); }
.st-keep-ask { position: absolute; left: 36px; right: 36px; top: 168px; font-size: 15px; font-weight: 500; line-height: 1.3; color: rgba(255, 255, 255, 0.7); }
.st-keep-ask span + span, .stage.is-saved .st-keep-ask:not(.st-keep-rate) span:first-child { display: none; }
.stage.is-saved .st-keep-ask span + span { display: inline; }
.st-keep-rate { top: 300px; }
/* the heart: outlined, then filled ochre */
.st-heart { position: absolute; left: 238px; top: 196px; width: 64px; height: 64px; scale: 0.9; transition: scale 0.45s var(--spring); }
.st-heart svg { width: 100%; height: 100%; fill: transparent; stroke: rgba(255, 255, 255, 0.4); stroke-width: 1.6; stroke-linejoin: round; transition: fill 0.3s ease, stroke 0.3s ease; }
.stage.is-saved .st-heart { scale: 1; }
.stage.is-saved .st-heart svg { fill: var(--secondary); stroke: var(--secondary); }
.stage .st-heart.is-grow { box-shadow: none; scale: 1.25; }
.st-stars { position: absolute; left: 0; right: 0; top: 326px; display: flex; justify-content: center; gap: 12px; }
.st-stars svg { width: 30px; height: 30px; fill: none; stroke: rgba(255, 255, 255, 0.3); stroke-width: 1.6; stroke-linejoin: round; }
.st-keep-done { position: absolute; left: 36px; right: 36px; bottom: 28px; display: flex; align-items: center; justify-content: center; height: 52px; border-radius: 12px; background: var(--white); color: var(--primary); font-size: 16px; font-weight: 600; }
/* the app's emoji confetti: three bursts */
.st-confetti i { position: absolute; margin: -18px 0 0 -18px; font-style: normal; line-height: 1; opacity: 0; }
.stage[data-step="7"] .st-confetti i { animation: st-burst 1.7s cubic-bezier(0.2, 0.7, 0.4, 1) var(--d) both; }
@keyframes st-burst { 0% { opacity: 0; transform: none; scale: 0.4; } 8% { opacity: 1; } 75% { opacity: 1; } 100% { opacity: 0; transform: translate(var(--x), var(--y)) rotate(var(--r)); scale: 1; } }
@media (prefers-reduced-motion: reduce) { .st-confetti { display: none; } }
/* the collections sheet, over the dimmed screen */
.st-dim { position: absolute; inset: 0; background: rgba(8, 20, 12, 0.4); opacity: 0; transition: opacity 0.4s ease; }
.stage.is-sheet .st-dim { opacity: 1; }
.st-sheet { position: absolute; left: 0; right: 0; bottom: 0; height: 356px; padding: 24px 28px 0; border-radius: 26px 26px 0 0; background: var(--primary); box-shadow: 0 -14px 34px -14px rgba(0, 0, 0, 0.45); text-align: left; transform: translateY(105%); transition: transform 0.35s ease; }
.st-sheet::before { content: ""; position: absolute; left: 50%; top: 8px; width: 36px; height: 5px; margin-left: -18px; border-radius: 3px; background: rgba(255, 255, 255, 0.35); }
.stage.is-sheet .st-sheet { transform: none; transition: transform 0.7s var(--spring-soft); }
.st-sheet-head { display: flex; align-items: center; gap: 14px; padding-bottom: 16px; border-bottom: 1px solid rgba(255, 255, 255, 0.14); font-size: 17px; font-weight: 600; line-height: 1.2; }
.st-sheet-head span { flex: 1; }
.st-sheet-head svg { width: 24px; height: 24px; }
.st-sheet-head svg:first-child { fill: var(--secondary); }
.st-sheet-head svg:last-child { fill: rgba(255, 255, 255, 0.5); }
.st-sheet-title { display: flex; align-items: center; justify-content: space-between; padding: 14px 0 8px; }
.st-sheet-title span:first-child { font-family: var(--font-display); font-weight: 600; font-size: 20px; }
.st-sheet-new { padding: 4px 12px; border-radius: 100px; background: var(--secondary); font-size: 14px; font-weight: 600; }
.st-coll { display: flex; align-items: center; gap: 16px; margin: 0 -10px; padding: 10px; border-radius: 12px; transition: scale 0.4s var(--spring), background-color 0.4s ease; }
.st-coll + .st-coll { background-image: linear-gradient(rgba(255, 255, 255, 0.14), rgba(255, 255, 255, 0.14)); background-size: calc(100% - 84px) 1px; background-position: 84px 0; background-repeat: no-repeat; }
.st-coll i { flex: none; display: grid; place-items: center; width: 48px; height: 48px; border-radius: 10px; background: rgba(255, 255, 255, 0.12); font-size: 26px; font-style: normal; }
.st-coll > span { flex: 1; display: flex; flex-direction: column; gap: 2px; font-size: 17px; font-weight: 600; line-height: 1.2; }
.st-coll small { font-size: 12px; font-weight: 400; color: rgba(255, 255, 255, 0.6); }
.st-coll small em { font-style: normal; }
.st-coll svg { flex: none; width: 26px; height: 26px; }
.st-plus { fill: none; stroke: rgba(255, 255, 255, 0.4); stroke-width: 1.6; }
.st-check { display: none; fill: var(--white); }
/* the one collection takes the recipe: + becomes a tick, the count goes up */
.st-coll-pick small em + em, .stage.is-collected .st-coll-pick small em:first-child, .stage.is-collected .st-coll-pick .st-plus { display: none; }
.stage.is-collected .st-coll-pick small em + em { display: inline; }
.stage.is-collected .st-coll-pick .st-check { display: block; animation: st-pop 0.45s var(--spring) both; }
.stage .st-coll.is-grow { box-shadow: none; scale: 1.03; background-color: rgba(255, 255, 255, 0.1); }

/* chapter rail under the stage */
/* The rail is the journey's progress: one thin segment per chapter, like
   stories, above the stage (on phones, along the top of the band). The
   chapters read are full and the current one fills as it goes (--p, from the
   shared script). Each segment is a button to its chapter, its label kept as
   the accessible name. */
.stage-rail { order: -1; display: flex; gap: 4px; width: var(--fit-w); }
.stage-rail button { position: relative; flex: 1; height: 14px; padding: 0; border: 0; background: none; font-size: 0; cursor: pointer; }
.stage-rail button::before { content: ""; position: absolute; left: 0; right: 0; top: 5px; height: 3px; border-radius: 2px; background: linear-gradient(to right, var(--rail-on, var(--primary)) calc(var(--p, 0) * 100%), var(--rail, rgba(15, 31, 15, 0.16)) 0); transition: top 0.2s ease, height 0.2s ease; }
.stage-rail button:hover::before { top: 4px; height: 5px; }
.stage-rail button:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* ---- tablets and half-screen windows: still side by side, smaller type ---- */
@media (max-width: 899px) {
    .journey { gap: 40px; }
    .stage-col { --fit-w: max(226.8px, min(540px, (100svh - 150px) * 540 / 640, 46vw)); }
    .chapter-hero h1 { font-size: clamp(34px, 5.2vw, 46px); letter-spacing: -1.2px; }
    .chapter h2, .section-title { font-size: clamp(26px, 3.6vw, 34px); }
}

/* ---- phones: the stage is the top half of the screen, like the app's own
   screen, and the story is a sheet pulled up under it ---- */
@media (max-width: 699px) {
    /* --band-w: the band's stage width, which the copy's resting place under it needs too */
    .journey { --band-w: max(226.8px, min(100vw, (100svh - 366px) * 540 / 640)); flex-direction: column; align-items: stretch; gap: 0; padding: 88px 16px 0; }
    .chapters { display: contents; }
    .chapter { min-height: calc((var(--len, 85) - 15) * 1svh); justify-content: flex-start; padding-block: var(--space-xl) var(--space-xxxl); }
    /* the copy holds still just under the band's sheet edge (100px of padding + the stage + 12px of edge) */
    .chapter-copy { top: calc(112px + var(--band-w) * 640 / 540); padding-top: var(--space-md); }
    .chapter-hero { order: -2; min-height: 0; padding-block: var(--space-sm) var(--space-xxl); }
    /* a full-width band in the chapter's tone, running up behind the nav pill;
       the stage sits in it, so a short phone letterboxes it without a floating box */
    .stage-col {
        /* full width, unless that leaves under ~230px for the chapter text:
           366px = the 100px top padding + the 36px sheet edge + 230px */
        --fit-w: var(--band-w);
        order: -1;
        top: 0;
        z-index: 10;
        margin-inline: -16px;
        padding: 100px 0 0;             /* the nav pill, then the progress segments */
        gap: 0;
        background-color: var(--tone);
        transition: background-color 0.8s ease;
    }
    .stage { background-color: transparent; border-radius: 0; }
    /* the sheet's top edge, with a grab handle: the chapter text scrolls under it */
    .stage-col::after {
        content: "";
        align-self: stretch;
        height: 24px;
        margin-top: -12px;
        border-radius: 22px 22px 0 0;
        background: var(--bg) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='36' height='5'%3E%3Crect width='36' height='5' rx='2.5' fill='%23C9C4B9'/%3E%3C/svg%3E") center 8px no-repeat;
        box-shadow: 0 -10px 24px -14px rgba(15, 31, 15, 0.35);
        position: relative;
        z-index: 2;
    }
    /* the progress segments run along the top of the band */
    .stage-rail { position: absolute; top: 82px; left: 16px; right: 16px; z-index: 3; width: auto; }
    .hero-top {
        position: relative;
        isolation: isolate;
        overflow: hidden;
        min-height: 72svh;
        display: flex;
        flex-direction: column;
        justify-content: flex-end;
        padding: var(--space-xxl) var(--space-xl) var(--space-xl);
        border-radius: 28px;
        color: var(--white);
    }
    .hero-photo { display: block; inset: 0; z-index: -2; width: 100%; height: 100%; clip-path: none; object-fit: cover; object-position: 50% 18%; }
    .hero-top::before { content: ""; position: absolute; inset: 0; z-index: -1; background: linear-gradient(to top, rgba(10, 24, 14, 0.88) 0%, rgba(10, 24, 14, 0.55) 46%, rgba(10, 24, 14, 0) 74%); }
    .hero-top h1 { color: var(--white); }
    .hero-top h1 em { color: var(--tertiary); }
    .hero-top .hero-sub { color: rgba(255, 255, 255, 0.88); }
}
@media (max-width: 640px) {
    .chapter-hero h1 { font-size: clamp(34px, 10vw, 44px); letter-spacing: -1px; }
    /* 48px keeps both badges on one row at 390px */
    .hero-actions .app-store-link img { height: 48px; }
    .hero-actions .android-badge { --badge-h: 48px; }
    .hero-quotes blockquote { font-size: 16px; }
}
@media (prefers-reduced-motion: reduce) {
    .chapter-hero h1, .hero-sub, .hero-actions, .hero-proof,
    .stage-col, .stage, .stage *, .stage *::after {
        animation: none !important;
        transition-duration: 0.01ms !important;
        transition-delay: 0s !important;
    }
    .u-line path { animation: none; stroke-dashoffset: 0; }
}

/* ========================================
   ABOUT NIKOLETA
   ======================================== */
.about {
    padding-block: var(--space-section);
    /* fades in from the page's ground and back out over its own padding, so
       nothing of it reaches into the sections around it */
    background: linear-gradient(to bottom, var(--bg), var(--bg-warm) var(--space-section),
                var(--bg-warm) calc(100% - var(--space-section)), var(--bg));
}

.about-content {
    display: grid;
    grid-template-columns: 1fr 1.2fr;
    gap: 80px;
    align-items: center;
}

.about-photo {
    position: relative;
}
.about-photo-frame {
    width: 360px;
    height: 440px;
    border-radius: 32px;
    overflow: hidden;
    box-shadow: 0 32px 64px rgba(26, 45, 26, 0.1);
}
.about-photo-frame img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center top;
}

/* One sentence of Nikoleta's, set big, and one small line under it (TOF-634) */
.about-text { margin: 0; }
.about-text blockquote {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: clamp(28px, 3.4vw, 44px);
    line-height: 1.2;
    letter-spacing: -0.5px;
    color: var(--text);
    text-wrap: balance;
    margin: 0 0 28px;
}
.about-meta {
    font-size: 15px;
    color: var(--text-2);
}
.about-meta b {
    font-family: var(--font-display);
    font-weight: 600;
    color: var(--text);
}
.about-meta a {
    color: var(--primary);
    font-weight: 500;
}
.about-meta a:hover { text-decoration: underline; }
/* The quote's last word sits on the hero's hand-drawn underline, drawn when the
   quote scrolls in; the photo settles in with it. */
.about-text .u-line path { animation: none; }
@media (prefers-reduced-motion: no-preference) {
    .about-text.visible .u-line path { animation: draw 1.1s var(--out) 0.45s forwards; }
    .about-photo.reveal { transform: translateY(40px) scale(0.96); }
    .about-photo.reveal.visible { transform: none; }
}
/* Her numbers, counted up by the script the first time they scroll in */
.about-stats {
    list-style: none;
    display: grid;
    grid-template-columns: repeat(3, auto);
    justify-content: start;
    gap: 44px;
    margin: 0 0 32px;
    padding: 0;
}
.about-stats li { display: flex; flex-direction: column; gap: 6px; }
.about-stats b {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: clamp(30px, 3.2vw, 46px);
    line-height: 1;
    letter-spacing: -1px;
    color: var(--text);
}
.about-stats span { max-width: 10em; font-size: 14px; line-height: 1.35; color: var(--text-2); }

/* ========================================
   REVIEWS
   ======================================== */
.reviews {
    padding-block: var(--space-section);
    background: var(--bg);
}
.reviews-header {
    margin-bottom: 56px;
}
.reviews-header .section-title { margin-bottom: 24px; }
.reviews-stars {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    text-decoration: none;
    transition: opacity 0.2s ease;
}
.reviews-stars:hover { opacity: 0.7; }
.reviews-stars .stars {
    color: var(--secondary);
    font-size: 22px;
    letter-spacing: 3px;
}
.reviews-stars-label {
    font-family: var(--font-body);
    font-weight: 600;
    font-size: 15px;
    color: var(--text);
}
.reviews-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 20px;
    max-width: 960px;
}
.review-card {
    background: var(--white);
    border-radius: 24px;
    padding: 40px 36px;
    display: flex;
    flex-direction: column;
    gap: 18px;
    transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1),
                box-shadow 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}
.review-card:hover {
    transform: translateY(-6px);
    box-shadow: 0 24px 48px rgba(26, 45, 26, 0.08);
}
.review-stars {
    color: var(--secondary);
    font-size: 16px;
    letter-spacing: 3px;
}
.review-card blockquote {
    font-family: var(--font-display);
    font-weight: 500;
    font-size: 19px;
    line-height: 1.55;
    letter-spacing: -0.3px;
    color: var(--text);
}
.review-card figcaption {
    font-family: var(--font-body);
    font-size: 14px;
    font-weight: 600;
    color: var(--text-2);
    margin-top: auto;
}
/* an odd card out spans the row, so the two columns never end on a lone card */
.review-card:last-child:nth-child(odd) { grid-column: 1 / -1; }
.review-card:last-child:nth-child(odd) blockquote { max-width: 72ch; }

/* ========================================
   PRICING
   ======================================== */
.pricing {
    padding-block: var(--space-section);
    position: relative;
    z-index: 2;
}
.pricing-header {
    margin-bottom: 64px;
}

.pricing-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
    max-width: 780px;
}

.pricing-card {
    border-radius: 24px;
    padding: 44px 36px;
    position: relative;
    transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1),
                box-shadow 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.pricing-card:hover {
    transform: translateY(-4px);
}
.pricing-card.free {
    background: var(--white);
}
.pricing-card.free:hover {
    box-shadow: 0 16px 40px rgba(26, 45, 26, 0.06);
}
.pricing-card.premium {
    background: var(--primary);
    color: var(--white);
    box-shadow: 0 16px 48px rgba(44, 110, 70, 0.2);
}
.pricing-card.premium:hover {
    box-shadow: 0 24px 56px rgba(44, 110, 70, 0.3);
}

.pricing-badge {
    position: absolute;
    top: -12px;
    right: 24px;
    background: var(--secondary);
    color: var(--white);
    font-weight: 600;
    font-size: 12px;
    padding: 6px 16px;
    border-radius: 100px;
    letter-spacing: 0.5px;
}

.pricing-card h3 {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 24px;
    margin-bottom: 8px;
}
.pricing-card .pricing-desc {
    font-size: 14px;
    opacity: 0.6;
    margin-bottom: 32px;
}

.pricing-features {
    list-style: none;
    margin-bottom: 32px;
}
.pricing-features li {
    font-size: 15px;
    padding: 10px 0;
    border-bottom: 1px solid rgba(0,0,0,0.05);
    display: flex;
    align-items: center;
    gap: 12px;
}
.pricing-card.premium .pricing-features li {
    border-bottom-color: rgba(255,255,255,0.12);
}
.pricing-features li::before {
    content: '\2713';
    font-weight: 700;
    font-size: 13px;
    width: 22px;
    height: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    flex-shrink: 0;
}
.pricing-card.free .pricing-features li::before {
    background: var(--primary-light);
    color: var(--primary);
}
.pricing-card.premium .pricing-features li::before {
    background: rgba(255,255,255,0.15);
    color: var(--white);
}

.pricing-note {
    text-align: left;
    margin-top: 24px;
    font-size: 14px;
    color: var(--text-2);
}

/* ========================================
   FAQ
   ======================================== */
.faq {
    padding-block: var(--space-section);
}
.faq-header {
    margin-bottom: 56px;
}
.faq-list {
    max-width: 680px;
}
.faq-item {
    border-bottom: 1px solid var(--surface-2);
}
.faq-question {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 24px 0;
    background: none;
    border: none;
    cursor: pointer;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 18px;
    color: var(--text);
    text-align: left;
    transition: color 0.2s;
}
.faq-question:hover { color: var(--primary); }
.faq-icon {
    font-size: 20px;
    color: var(--text-2);
    transition: transform 0.3s ease;
    flex-shrink: 0;
}
.faq-item.open .faq-icon {
    transform: rotate(45deg);
}
.faq-answer {
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.faq-item.open .faq-answer {
    max-height: 40em;               /* room for the longest answer on a phone */
}
.faq-answer p {
    font-size: 15px;
    line-height: 1.7;
    color: var(--text-2);
    padding-bottom: 24px;
}

/* ========================================
   FINAL CTA
   ======================================== */
.final-cta {
    background: var(--primary);
    border-radius: 32px;
    margin: 0 24px 80px;
    padding: 96px 48px;
    text-align: center;
    position: relative;
    overflow: hidden;
}
.final-cta::before {
    content: '';
    position: absolute;
    width: 700px;
    height: 700px;
    background: radial-gradient(circle, rgba(255,255,255,0.06) 0%, transparent 60%);
    top: -250px;
    right: -150px;
    border-radius: 50%;
}
.final-cta::after {
    content: '';
    position: absolute;
    width: 500px;
    height: 500px;
    background: radial-gradient(circle, rgba(255,255,255,0.04) 0%, transparent 60%);
    bottom: -200px;
    left: -100px;
    border-radius: 50%;
}
/* everything in the box sits above the glows (TOF-643) */
.final-cta > * { position: relative; z-index: 1; }
.final-cta h2 {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: clamp(32px, 5vw, 52px);
    color: var(--white);
    margin-bottom: 16px;
    letter-spacing: -1px;
}
.final-cta p {
    font-size: 17px;
    color: rgba(255,255,255,0.7);
    margin-bottom: 40px;
}

/* ========================================
   THE ENDING (TOF-634): after the journey, static sections in its look. The
   headings and body lines are the chapters' own (the shared rules above),
   left-aligned in the same column, no eyebrows, one spacing rhythm.
   ======================================== */
.extras { padding-block: var(--space-section); }

/* scanner + supplements: two small screens in the app's own UI, one line each */
.extras-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-xl); max-width: 960px; margin-top: var(--space-xxxl); }
.extra { display: flex; flex-direction: column; gap: var(--space-lg); }
.extra-screen { flex: 1; padding: 28px; border-radius: 28px; background: var(--surface); box-shadow: 0 24px 48px -28px rgba(26, 45, 26, 0.35); }
.extra figcaption { max-width: 36ch; font-size: 17px; line-height: 1.55; color: var(--text-2); }
/* the scanner's result for a vegan product, as ProductDetailView shows it */
.scan-name { font-family: var(--font-display); font-weight: 600; font-size: 22px; line-height: 1.2; text-align: center; color: var(--text); }
.scan-brand { margin-top: var(--space-xs); font-size: 15px; font-weight: 500; text-align: center; color: var(--text-2); }
.scan-verdict { display: flex; flex-direction: column; align-items: center; gap: var(--space-sm); margin-top: var(--space-xl); padding: var(--space-xl); border-radius: 16px; background: var(--primary); color: var(--white); text-align: center; transition: scale 0.6s var(--spring) 0.6s, opacity 0.3s ease 0.6s; }
.scan-verdict svg { width: 34px; height: 34px; fill: currentColor; }
.scan-verdict b { font-family: var(--font-display); font-weight: 600; font-size: 20px; }
.scan-verdict span { font-size: 13px; color: rgba(255, 255, 255, 0.7); }
/* the supplement tracker's rows: B12 taken today, D3 still to take */
.supps-title { margin-bottom: var(--space-sm); font-family: var(--font-display); font-weight: 600; font-size: 20px; color: var(--text); }
.supps-row { display: flex; align-items: center; gap: var(--space-md); margin: 0 -10px; padding: 14px 10px; border-radius: 12px; border-top: 1px solid rgba(15, 31, 15, 0.06); font-size: 16px; color: var(--text); }
.supps-row i { font-style: normal; font-size: 24px; line-height: 1; }
.supps-row span { flex: 1; }
.supps-row.is-taken span { color: var(--text-2); text-decoration: line-through; }
.supps-row svg { flex: none; width: 24px; height: 24px; }
.supps-info { fill: var(--primary); opacity: 0.85; }
.supps-done circle { fill: var(--primary); }
/* both screens play while they're on screen (the shared script); the markup
   rests on the finished state, which is what reduced motion and no script see */
.scan { position: relative; min-height: 292px; padding: 0; overflow: hidden; }
.scan-cam, .scan-result { position: absolute; inset: 0; transition: opacity 0.35s ease; }
.scan-result { padding: 28px; }
/* the camera, as the scanner tab shows it: the pack's barcode, the viewfinder's
   corner brackets pulsing, a scan line sweeping */
.scan-cam { display: grid; place-items: center; background: radial-gradient(120% 90% at 50% 40%, #3f4b40, #1b201c); }
.scan-label { padding: 12px 16px 8px; border-radius: 8px; background: #FBFAF6; rotate: -4deg; box-shadow: 0 12px 26px -12px rgba(0, 0, 0, 0.7); text-align: center; }
.scan-label svg { display: block; width: 190px; height: 70px; fill: #161616; }
.scan-label span { display: block; margin-top: 5px; font-size: 12px; font-weight: 500; line-height: 1; letter-spacing: 2px; color: #222; font-variant-numeric: tabular-nums; }
.scan-frame { position: absolute; left: 50%; top: 50%; width: 76%; aspect-ratio: 1.4; translate: -50% -50%; container-type: size; animation: scan-pulse 2s ease-in-out infinite alternate paused; }
.scan-frame i { position: absolute; width: 36px; height: 36px; border: 2.5px solid rgba(255, 255, 255, 0.8); filter: drop-shadow(0 0 6px rgba(255, 255, 255, 0.25)); transition: border-color 0.2s ease; }
.scan-frame i:nth-child(1) { left: 0; top: 0; border-right: 0; border-bottom: 0; border-top-left-radius: 6px; }
.scan-frame i:nth-child(2) { right: 0; top: 0; border-left: 0; border-bottom: 0; border-top-right-radius: 6px; }
.scan-frame i:nth-child(3) { left: 0; bottom: 0; border-right: 0; border-top: 0; border-bottom-left-radius: 6px; }
.scan-frame i:nth-child(4) { right: 0; bottom: 0; border-left: 0; border-top: 0; border-bottom-right-radius: 6px; }
.scan-line { position: absolute; left: 16px; right: 16px; top: 16px; height: 1.5px; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0.15), transparent); box-shadow: 0 0 12px rgba(255, 255, 255, 0.3); animation: scan-sweep 1.25s ease-in-out infinite alternate paused; }
@keyframes scan-sweep { to { translate: 0 calc(100cqh - 32px); } }
.extras-grid.is-live .scan:not(.is-found) :is(.scan-frame, .scan-line) { animation-play-state: running; }
@keyframes scan-pulse { to { scale: 1.015; } }
/* caught: the brackets flash green, the camera gives way to the result and
   its verdict springs in, as ProductDetailView's does */
.scan.is-found .scan-frame i { border-color: #7BD49A; }
.scan.is-found .scan-cam { opacity: 0; transition: opacity 0.45s ease 0.25s; }
.scan:not(.is-found) .scan-result { opacity: 0; }
.scan.is-found .scan-result { transition-delay: 0.45s; }
.scan:not(.is-found) .scan-verdict { scale: 0.6; opacity: 0; transition: none; }
/* the tracker: a row ticked off grows for a moment and its name strikes through */
.supps-done, .supps-row.is-taken .supps-todo { display: none; }
.supps-row.is-taken .supps-done { display: block; animation: st-pop 0.45s var(--spring) both; }
.supps-row.is-taken { animation: supps-tick 0.8s ease; }
@keyframes supps-tick { 35% { scale: 1.03; background-color: #E8F1E7; } }
@media (prefers-reduced-motion: reduce) { .scan-frame, .scan-line, .supps-row.is-taken, .supps-row.is-taken .supps-done { animation: none; } }
@media (max-width: 699px) {
    :root { --space-section: var(--space-section-sm); }
    .extras-grid { grid-template-columns: 1fr; }
}

/* ========================================
   FOOTER
   ======================================== */
.footer {
    background: var(--text);
    color: rgba(255,255,255,0.6);
    padding: 64px 0 40px;
}
.footer-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.footer-logo {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 24px;
    color: var(--white);
}

.footer-links {
    display: flex;
    gap: 28px;
}
.footer-links a {
    font-size: 14px;
    color: rgba(255,255,255,0.5);
    transition: color 0.2s;
}
.footer-links a:hover { color: var(--white); }

.footer-legal a { color: inherit; text-decoration: underline; }   /* not colour alone */
.footer-legal {
    text-align: center;
    font-size: 12px;
    color: rgba(255,255,255,0.62);   /* 0.3 failed contrast on the dark footer */
    margin-top: 48px;
    padding-top: 24px;
    border-top: 1px solid rgba(255,255,255,0.06);
}

/* ========================================
   RESPONSIVE
   ======================================== */
@media (max-width: 900px) {

    .about-content {
        grid-template-columns: 1fr;
        text-align: center;
        gap: 48px;
    }
    .about-photo-frame {
        width: 280px;
        height: 340px;
        margin: 0 auto;
    }
    .about-stats { justify-content: center; gap: 22px; }
    .about-stats li { align-items: center; }

    .reviews-grid {
        grid-template-columns: 1fr;
        max-width: 460px;
    }

    .pricing-grid {
        grid-template-columns: 1fr;
        max-width: 400px;
    }

    .footer-inner {
        flex-direction: column;
        gap: 24px;
        text-align: center;
    }
    .footer-links { flex-wrap: wrap; justify-content: center; }

    .nav-center { display: none; }
    .nav { padding: 0 8px 0 20px; }
}

@media (max-width: 480px) {
    /* Nav pill has ~170px for the CTA at 375px — "Download Tofu" doesn't fit
       next to the logo and language switcher, so drop back to "Download". */
    .btn-label-extra { display: none; }
    .final-cta { padding: 64px 24px; margin: 0 16px 64px; border-radius: 24px; }
}

/* App Store download badge */
.app-store-link {
    display: inline-block;
    transition: transform 0.2s ease;
    line-height: 0;
}
.app-store-link:hover {
    transform: scale(1.04);
}
.app-store-link img {
    display: block;
    height: 60px;
    width: auto;
}
.final-cta .app-store-link img { height: 64px; }
.final-cta .store-badges { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 12px; }
.final-cta .android-badge { --badge-h: 64px; }
@media (max-width: 480px) {
    .app-store-link img { height: 52px; }
    .android-badge { --badge-h: 52px; }
    .final-cta .app-store-link img { height: 56px; }
    .final-cta .android-badge { --badge-h: 56px; }
}

/* TOF-538 — the shared CTA motion: a lift, and a sheen that crosses
   once on hover. Matches the app-install buttons on the recipe
   directory so every page behaves the same. */
.btn-primary { position: relative; overflow: hidden;
    transition: transform .18s cubic-bezier(.2,.8,.3,1), box-shadow .18s ease, background .18s ease; }
.btn-primary::after { content: ""; position: absolute; inset: 0; border-radius: inherit;
    pointer-events: none; transform: translateX(-120%);
    background: linear-gradient(105deg, transparent 38%, rgba(255,255,255,.30) 50%, transparent 62%); }
.btn-primary:hover::after { transform: translateX(120%); transition: transform .75s ease; }
.btn-primary:active { transform: translateY(0) scale(.985); }
@media (prefers-reduced-motion: reduce) {
    .btn-primary, .btn-primary::after { transition: none; }
    .btn-primary:hover::after { transform: translateX(-120%); }
}

/* TOF-538 — destinations live in the right-hand zone, never among the
   anchors. The left and centre of this nav scroll this page; the right
   is where things that change your context already are, the language
   switcher and the store CTA. Recipes and Guides belong with those.
   Mixing them into .nav-center would give five links that scroll and
   two that navigate, all styled the same, with no way to tell which. */
.nav-dests { display: flex; align-items: center; gap: 22px;
    padding-right: 20px; margin-right: 4px;
    border-right: 1px solid rgba(0,0,0,0.10); }
.nav-dest { font-size: 14px; font-weight: 600; color: var(--text);
    text-decoration: none; white-space: nowrap; transition: color 0.2s; }
.nav-dest:hover { color: var(--primary); }
/* Seven links plus a switcher plus a CTA do not fit a tablet. The
   anchors go first: they only scroll a page you are already on, while
   the destinations are the only route into 290 pages of content. */
@media (max-width: 1100px) { .nav-center { display: none; } }
@media (max-width: 640px) { .nav-dests { display: none; } }

/* the cue to scroll (the journey script adds it): a visitor still on the
   first screen after a moment gets a small arrow; the first scroll puts it away */
.scroll-cue { position: fixed; z-index: 20; left: 50%; bottom: calc(20px + env(safe-area-inset-bottom)); width: 44px; height: 44px; margin-left: -22px; display: grid; place-items: center; border-radius: 50%; background: var(--surface); box-shadow: 0 8px 22px -10px rgba(15, 31, 15, 0.45); color: var(--primary); opacity: 0; translate: 0 10px; pointer-events: none; transition: opacity 0.4s ease, translate 0.5s var(--out); }
.scroll-cue.is-on { opacity: 1; translate: none; }
.scroll-cue svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; animation: cue-bob 1.6s ease-in-out infinite; }
@keyframes cue-bob { 50% { transform: translateY(4px); } }
@media (prefers-reduced-motion: reduce) { .scroll-cue svg { animation: none; } }
/* phones: the badges and the review line fill the bottom centre, so it sits in the corner */
@media (max-width: 699px) { .scroll-cue { left: auto; right: 16px; bottom: calc(12px + env(safe-area-inset-bottom)); margin-left: 0; } }
