/*
 * Mise en plat brand: terracotta and herb green on warm neutrals,
 * Fraunces for headings and Inter for text.
 */
:root {
    --mise-font-display: 'Fraunces Variable', Georgia, serif;

    --tblr-primary: oklch(60% 0.15 40deg);
    --tblr-primary-rgb: 200, 91, 50;
    --tblr-green: oklch(58% 0.11 145deg);
    --tblr-green-rgb: 77, 139, 80;

    /* Tabler's neutral grays, tinted warm. Backgrounds, borders and text derive from these. */
    --tblr-gray-50: oklch(97.8% 0.012 80deg);
    --tblr-gray-100: oklch(96.5% 0.012 80deg);
    --tblr-gray-200: oklch(91.5% 0.012 75deg);
    --tblr-gray-300: oklch(86.5% 0.012 75deg);
    --tblr-gray-400: oklch(71.5% 0.012 70deg);
    --tblr-gray-500: oklch(55.5% 0.012 70deg);
    --tblr-gray-600: oklch(44% 0.012 65deg);
    --tblr-gray-700: oklch(37% 0.012 65deg);
    --tblr-gray-800: oklch(27% 0.01 60deg);
    --tblr-gray-900: oklch(20.5% 0.008 60deg);
    --tblr-gray-950: oklch(14.5% 0.006 60deg);
    --tblr-dark: var(--tblr-gray-800);
    --tblr-light: var(--tblr-gray-50);

    --tblr-font-sans-serif: 'Inter Variable', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
    --tblr-border-radius-scale: 1.25;
}

h1, h2, h3, h4,
.h1, .h2, .h3, .h4,
.display-1, .display-2, .display-3, .display-4, .display-5, .display-6,
.navbar-brand {
    font-family: var(--mise-font-display);
    letter-spacing: -0.01em;
}

/* My kitchen and my recipe catalogue; icons only on a phone. */
.main-nav {
    gap: 0.25rem;
}

.main-nav .nav-link {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding-inline: 0.75rem;
    border-radius: var(--tblr-border-radius);
}

.main-nav .nav-link .icon {
    margin: 0;
}

.main-nav .nav-link.active {
    color: var(--tblr-primary);
    background: var(--tblr-primary-lt, color-mix(in oklch, var(--tblr-primary) 10%, transparent));
}

@media (max-width: 575.98px) {
    .main-nav .nav-link-title {
        display: none;
    }
}

/* Below large, the theme, language and account sit in a panel that the
   menu button folds out below the navbar: one row each, its label on the
   left and its controls on the right. */
.navbar-panel {
    width: 100%;
}

.navbar-panel-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding-block: 0.625rem;
}

.navbar-panel-row + .navbar-panel-row {
    border-top: 1px solid var(--tblr-border-color);
}

.navbar-panel-label {
    color: var(--tblr-secondary);
    font-size: 0.75rem;
    font-weight: var(--tblr-font-weight-medium);
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.navbar-panel-account {
    min-width: 0;
    overflow: hidden;
    color: var(--tblr-secondary);
    font-size: 0.875rem;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* A row of options side by side, the chosen one raised. */
.segmented {
    display: inline-flex;
    padding: 0.1875rem;
    border: 1px solid var(--tblr-border-color);
    border-radius: var(--tblr-border-radius);
    background: var(--tblr-bg-surface-secondary);
}

.segmented-item {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.5rem;
    padding: 0.3125rem 0.625rem;
    border: 0;
    border-radius: calc(var(--tblr-border-radius) - 0.1875rem);
    background: transparent;
    color: var(--tblr-secondary);
    font-size: 0.8125rem;
    font-weight: var(--tblr-font-weight-medium);
    line-height: 1.25rem;
    text-decoration: none;
}

.segmented-item:hover {
    color: var(--tblr-body-color);
    text-decoration: none;
}

.segmented-item .icon {
    width: 1.125rem;
    height: 1.125rem;
    margin: 0;
}

.segmented-item.active {
    background: var(--tblr-bg-surface);
    box-shadow: var(--tblr-shadow-sm, 0 1px 2px rgb(0 0 0 / 0.08));
    color: var(--tblr-primary);
}

.navbar-brand > a {
    color: var(--tblr-primary);
    font-size: 1.5rem;
    font-weight: 700;
    text-decoration: none;
}

.navbar-tagline {
    margin-left: 0.5rem;
}

/* Below large, the name and the tagline stack, both smaller. */
@media (max-width: 991.98px) {
    .navbar-brand:has(.navbar-tagline) {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        gap: 0;
    }

    .navbar-brand:has(.navbar-tagline) > a {
        font-size: 1.125rem;
        line-height: 1;
    }

    .navbar-tagline {
        margin-left: 0;
        font-size: 0.6875rem;
        line-height: 1;
    }
}

.navbar-brand-lg > a {
    font-size: 2.5rem;
}

.theme-icon {
    display: none;
}

[data-theme-choice="light"] .theme-icon-light,
[data-theme-choice="dark"] .theme-icon-dark,
[data-theme-choice="auto"] .theme-icon-auto {
    display: inline-block;
}

/* A button whose label hides on a phone is left with its icon alone,
   without the space the icon keeps from its label. */
@media (max-width: 575.98px) {
    .btn:has(> .d-none.d-sm-inline) > .icon {
        margin: 0;
    }
}

/* A dropdown that holds a form or other content rather than a list of
   items, such as a small form to fill in next to its button. */
.dropdown-panel {
    /* Sized by its content rather than the button it hangs from. */
    width: max-content;
    max-width: calc(100vw - 2rem);
    padding: 0.5rem;
}

/* The question as an alert: an icon, the question, and what follows if
   given, wrapping rather than widening the panel. */
.dropdown-panel-alert {
    max-width: 22rem;
    margin-bottom: 0.5rem;
}

.dropdown-panel-alert .alert-heading:last-child {
    margin-bottom: 0;
}

/* The buttons share the row equally, also those in a form of their own. */
.dropdown-panel-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.dropdown-panel-actions > * {
    flex: 1 1 0;
}

.dropdown-panel-actions > form > .btn {
    width: 100%;
}

/* A dropdown toggle without the arrow, such as an icon button in a button
   group that asks before it acts. */
.dropdown-toggle-plain::after {
    content: none;
}

/* While its panel is open, a layer dims the page around the element with
   the button and takes the clicks meant for the page, which only close the
   panel. The element's own content, the button and the panel, stays above
   it and usable. A section of a recipe being edited in place dims the page
   the same way. */
.dropdown-spotlight:has(.dropdown-panel.show),
.recipe-frame:has(> form) {
    position: relative;
    z-index: 1030;
}

.dropdown-spotlight:has(.dropdown-panel.show)::before,
.recipe-frame:has(> form)::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    background: rgb(0 0 0 / 0.4);
    animation: spotlight-in 0.15s ease-out;
}

@keyframes spotlight-in {
    from {
        opacity: 0;
    }
}

@media (prefers-reduced-motion: reduce) {
    .dropdown-spotlight:has(.dropdown-panel.show)::before,
    .recipe-frame:has(> form)::before {
        animation: none;
    }
}

/* Cards */

/* Meals on the dashboard, one per row: a coloured tile with the recipe's
   initial, its details, and what to do with it. */

.meal-list {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    margin: 0;
}

.meal-card {
    flex-direction: row;
    transition: box-shadow 0.15s, border-color 0.15s;
}

.meal-card:hover {
    border-color: color-mix(in oklch, var(--tblr-primary) 35%, var(--tblr-border-color));
    box-shadow: 0 0.25rem 1rem color-mix(in oklch, var(--tblr-body-color) 8%, transparent);
}

.meal-tile {
    flex: 0 0 5rem;
    display: grid;
    place-items: center;
    font-family: var(--mise-font-display);
    font-size: 2.25rem;
    font-weight: 700;
    text-decoration: none;
    background: oklch(93% 0.05 var(--hue));
    color: oklch(45% 0.13 var(--hue));
    /* Rounded with the card, which can't hide its overflow: that would cut
       off the panels its buttons open. */
    border-radius: var(--tblr-card-inner-border-radius) 0 0 var(--tblr-card-inner-border-radius);
}

.meal-card:hover .meal-tile {
    color: oklch(38% 0.14 var(--hue));
}

[data-bs-theme="dark"] .meal-tile {
    background: oklch(32% 0.05 var(--hue));
    color: oklch(85% 0.09 var(--hue));
}

.meal-content {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 0.75rem 1rem;
}

.meal-details {
    min-width: 0;
}

.meal-title {
    font-size: 1.125rem;
    line-height: 1.3;
}

.meal-meta {
    display: flex;
    flex-wrap: wrap;
    column-gap: 0.75rem;
}

.meal-meta > span + span::before {
    content: "·";
    margin-right: 0.75rem;
}

.meal-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: auto;
}

/* Controls sit above the link that covers a meal's card. */
.meal-actions > * {
    position: relative;
    z-index: 2;
}

/* A card or row with an open panel goes above the page its spotlight dims,
   as its own layers, such as a row's on hover, would keep the panel in. */
.meal-card:has(.dropdown-panel.show) {
    z-index: 1030;
}

.cooked-meal {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: 0.5rem;
}

@media (max-width: 575.98px) {
    .meal-tile {
        flex-basis: 4rem;
        font-size: 1.75rem;
    }
}

/* A card after a list, to add one more: more meals, another recipe. */
.add-card:hover {
    border-color: color-mix(in oklch, var(--tblr-primary) 35%, var(--tblr-border-color));
    box-shadow: 0 0.25rem 1rem color-mix(in oklch, var(--tblr-body-color) 8%, transparent);
}

.servings-stepper {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
}

.servings-value {
    display: inline-flex;
    align-items: center;
    min-width: 2rem;
    justify-content: center;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

/* The word after the stepper: "4 servings". */
.servings-unit {
    margin-left: 0.25rem;
    color: var(--tblr-secondary);
}

/*
 * Each tag has its own colour wherever it shows: as a badge, a filter chip or
 * a bookmark. The page sets --tag-hue from the tag's name.
 */
.recipe-tag,
.tag-chip,
.bookmark {
    --tag-hue: 145deg;
    --tag-tint: oklch(91% 0.06 var(--tag-hue));
    --tag-ink: oklch(42% 0.1 var(--tag-hue));
    --tag-solid: oklch(58% 0.15 var(--tag-hue));
}

[data-bs-theme="dark"] :is(.recipe-tag, .tag-chip, .bookmark) {
    --tag-tint: oklch(36% 0.07 var(--tag-hue));
    --tag-ink: oklch(88% 0.07 var(--tag-hue));
}

.recipe-tag {
    background: var(--tag-tint);
    color: var(--tag-ink);
}

/* Every tag starts with a tag icon, in its own colour. */
.recipe-tag::before,
.tag-chip::before,
.bookmark::before {
    content: '';
    display: inline-block;
    flex: none;
    width: 0.9em;
    height: 0.9em;
    margin-inline-end: 0.3em;
    vertical-align: -0.1em;
    background: currentColor;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7.5 7.5m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0'/%3E%3Cpath d='M3 6v5.172a2 2 0 0 0 .586 1.414l7.71 7.71a2.41 2.41 0 0 0 3.408 0l5.592 -5.592a2.41 2.41 0 0 0 0 -3.408l-7.71 -7.71a2 2 0 0 0 -1.414 -.586h-5.172a3 3 0 0 0 -3 3z'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* Those that lay out their parts with a gap already. */
.tag-pill::before,
.tag-chip.is-added::before {
    margin-inline-end: 0;
}

.tag-chip {
    font-weight: 500;
    color: var(--tag-ink);
}

/* A recipe's tags on its page: pills in their colour, each with a button to
   remove it, and a dashed one at the end to add another. */
.recipe-tags {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.375rem;
    margin-top: 0.75rem;
}

.tag-pill,
.tag-add {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    min-height: 1.75rem;
    border-radius: 999px;
    font-size: 0.8125rem;
    font-weight: 500;
    line-height: 1.2;
}

.tag-pill {
    padding: 0.25rem 0.5rem 0.25rem 0.75rem;
}

.tag-add {
    padding: 0.25rem 0.75rem 0.25rem 0.5rem;
    border: 1px dashed var(--tblr-border-color-dark, var(--tblr-border-color));
    background: transparent;
    color: var(--tblr-secondary);
    transition: color 0.15s, border-color 0.15s;
}

.tag-add:hover,
.tag-add[aria-expanded="true"] {
    border-color: var(--tblr-primary);
    color: var(--tblr-primary);
}

.tag-add-panel {
    width: 18rem;
}

.btn-check:checked + .tag-chip {
    background: var(--tag-tint);
    border-color: var(--tag-solid);
    color: var(--tag-ink);
}

/*
 * A page of the book: outlined, with a few page edges behind it and a dark
 * spine down its left side. The cookbook is one, and so is each recipe in
 * it, and the steps when cooking.
 */
.book-page {
    --page-edge: var(--tblr-border-color);
    --page-bg: var(--tblr-bg-surface);
    --page-spine: 0.5rem;
    --page-spine-bg: color-mix(in oklch, var(--page-edge), #000 25%);

    position: relative;
    padding: 1.5rem;
    background: var(--page-bg);
    border: 1px solid var(--page-edge);
    border-radius: 0.25rem var(--tblr-border-radius-lg) var(--tblr-border-radius-lg) 0.25rem;
    box-shadow:
        3px 3px 0 -1px var(--page-bg),
        3px 3px 0 0 var(--page-edge),
        6px 6px 0 -1px var(--page-bg),
        6px 6px 0 0 var(--page-edge);
}

/* In the dark, the page edge is too close to the page for a darker shade of
   it to show, so the spine takes a shade between the darkest warm grays. */
[data-bs-theme="dark"] .book-page {
    --page-spine-bg: color-mix(in oklch, var(--tblr-gray-950), var(--tblr-gray-900));
}

/* The spine. */
.book-page::before {
    content: '';
    position: absolute;
    inset-block: 0;
    left: 0;
    width: calc(var(--page-spine) + 1px);
    background: var(--page-spine-bg);
    border-right: 1px solid var(--page-edge);
    border-radius: calc(0.25rem - 1px) 0 0 calc(0.25rem - 1px);
}

/*
 * The bar at the top of a recipe's page: back to the cookbook on the left,
 * what to do with the recipe on the right, ruled off from the recipe.
 */
.recipe-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 1.25rem;
    padding-bottom: 0.75rem;
    border-bottom: 1px solid var(--page-edge);
}

.recipe-toolbar-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

/* A card as a page keeps the padding of its header, body and footer. */
.card.book-page {
    padding: 0;
}

@media (max-width: 575.98px) {
    .book-page {
        padding: 1rem 1rem 1rem 1.25rem;
    }
}

@media print {
    .book-page {
        padding: 0;
        border: 0;
        box-shadow: none;
    }

    .book-page::before {
        content: none;
    }
}

/*
 * The cookbook, with its search field above it and its tags as bookmarks
 * sticking out of its top edge, from between the pages.
 */
.cookbook-layout {
    margin-bottom: 0.5rem;
}

.cookbook {
    display: flex;
    flex-direction: column;
    min-height: min(36rem, 70svh);
    z-index: 1;
}

/* Tabler's empty state fills its parent's height; here it shares the page with the new-recipe line. */
.cookbook > .empty {
    flex: 1 0 auto;
    height: auto;
}

/* Recipes run down the page, one per line, like a table of contents. */
.cookbook-entry {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    /* Toggles on a line of their own are as far from the title above them
       as from the entry's edge below them. */
    gap: 0.875rem 1rem;
    padding-block: 0.875rem;
    border-bottom: 1px solid var(--page-edge);
}

/* Entries keep their padding, for their background when pointed at; the
   list makes up for it at either end. */
.cookbook-entries {
    margin-block: -0.875rem;
}

.cookbook-entry:last-child {
    border-bottom: 0;
}

.cookbook-entry-body {
    flex: 1 1 16rem;
    min-width: 0;
}

/* Its toggle for the menu sits above the link that opens the recipe, and
   above the other entries while it asks to confirm. */
.cookbook-plan {
    position: relative;
    z-index: 2;
}

.cookbook-plan:has(.dropdown-panel.show) {
    z-index: 1030;
}

/* An entry opens its recipe anywhere, and lights up when pointed at. */
.cookbook-entry {
    position: relative;
    margin-inline: -0.75rem;
    padding-inline: 0.75rem;
    border-radius: var(--tblr-border-radius);
    transition: background-color 0.15s;
}

.cookbook-entry:hover {
    background: var(--tblr-bg-surface-secondary);
}

/*
 * The house's recipes after the cookbook's own, on a tinted insert slipped
 * between the pages, so they read as apart from the cookbook. Its entries
 * light up in the page's colour instead.
 */
.cookbook-house {
    margin-top: 2.5rem;
    padding: 1rem 1.25rem 1.25rem;
    background: var(--tblr-bg-surface-secondary);
    border: 1px solid var(--page-edge);
    border-radius: var(--tblr-border-radius-lg);
}

.cookbook-house-header {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding-bottom: 0.75rem;
    margin-bottom: 0.875rem;
    border-bottom: 1px solid var(--page-edge);
}

.cookbook-house .cookbook-entry:hover {
    background: var(--tblr-bg-surface);
}

/* Its two toggles stay side by side, on the line below the title if they
   don't fit beside it. */
.cookbook-toggles {
    display: flex;
    gap: 0.5rem;
}

/* An entry's toggles keep to the right, also on a line of their own. */
.cookbook-entry > :is(.cookbook-plan, .cookbook-toggles) {
    margin-left: auto;
}

/* Its toggles line up in columns across the entries, whatever their state,
   where there is room for them beside the title. */
@media (min-width: 576px) {
    .cookbook-house .cookbook-toggles {
        display: contents;
    }

    .cookbook-house .cookbook-entries {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto auto;
        column-gap: 1rem;
    }

    .cookbook-house .cookbook-entry {
        grid-column: 1 / -1;
        display: grid;
        grid-template-columns: subgrid;
    }

    /* As flex items, the toggle's form or dropdown fills the column, inline or not. */
    .cookbook-house .cookbook-plan {
        display: flex;
        flex-direction: column;
    }

    .cookbook-house .cookbook-plan .btn {
        width: 100%;
    }
}

/* The new-recipe card after the list, spaced off the last entry. */
.cookbook-new {
    margin-top: 1.25rem;
}

/*
 * The bookmarks are index tabs in a row that scrolls sideways when there are
 * more than fit, fading out at its end to show there are more. Unpicked ones
 * tuck down behind the page; a picked one stands up taller, on top of the
 * page's edge.
 */
.bookmarks {
    display: flex;
    align-items: flex-end;
    gap: 0.375rem;
    padding: 0.25rem 1.5rem 0;
    margin-bottom: -1px;
    /* The tucked part of a bookmark is cut off, rather than scrolled to. */
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    mask-image: linear-gradient(to right, #000 calc(100% - 1.5rem), transparent);
}

.bookmarks::-webkit-scrollbar {
    display: none;
}

/*
 * Every bookmark is as tall as a picked one, so picking doesn't reflow the
 * page; the others slide down under it. Their foot is padded by as much, so
 * the text keeps its distance from the page.
 */
.bookmark {
    --bookmark-pull: 0.625rem;
    --bookmark-tuck: var(--bookmark-pull);

    flex: none;
    max-width: 10rem;
    padding: 0.375rem 0.75rem calc(0.375rem + var(--bookmark-pull));
    transform: translateY(var(--bookmark-tuck));
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--tag-ink);
    background: var(--tag-tint);
    border-radius: var(--tblr-border-radius) var(--tblr-border-radius) 0 0;
    cursor: pointer;
    transition: transform 0.15s ease, background-color 0.15s ease;
}

.bookmark:hover {
    --bookmark-tuck: calc(var(--bookmark-pull) - 0.25rem);
}

.btn-check:checked + .bookmark {
    position: relative;
    z-index: 2;
    --bookmark-tuck: 0rem;
    background: var(--tag-solid);
    color: #fff;
}

.btn-check:focus-visible + .bookmark {
    outline: 2px solid var(--tblr-primary);
    outline-offset: -2px;
}

@media (prefers-reduced-motion: reduce) {
    .bookmark {
        transition: none;
    }
}

/* Recipe */

.ingredient-amount {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    margin-right: 0.25rem;
}

.ingredient-alternative {
    padding-left: 1rem;
    margin-top: 0.25rem;
}

.step-list {
    counter-reset: step;
}

.step-list .step {
    counter-increment: step;
    position: relative;
    padding-left: 3.25rem;
}

.step-list .step::before {
    content: counter(step);
    position: absolute;
    left: 1rem;
    top: 0.75rem;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    background: var(--tblr-primary-lt, color-mix(in oklch, var(--tblr-primary) 15%, transparent));
    color: var(--tblr-primary);
    font-weight: 700;
    font-size: 0.8125rem;
    display: grid;
    place-items: center;
}

.step-text {
    line-height: 1.6;
}

/* Lists in a step, bulleted or numbered, become checklists to tick off while cooking. */
.step-text :is(ul, ol):has(> .step-check) {
    padding-left: 0;
    list-style: none;
}

.step-text :is(ul, ol):has(> .step-check) :is(ul, ol):has(> .step-check) {
    padding-left: 1.75rem;
}

.step-check + .step-check {
    margin-top: 0.25rem;
}

.step-check-label {
    display: inline-flex;
    align-items: baseline;
    gap: 0.5rem;
    cursor: pointer;
}

.step-check-label > p {
    margin: 0;
}

.step-check-label .form-check-input {
    flex: none;
    margin: 0;
    transform: translateY(0.15em);
}

.step-check-label:has(> :checked) {
    color: var(--tblr-secondary);
    text-decoration: line-through;
}

.step-text > p:last-of-type {
    margin-bottom: 0;
}

/* The parts of a timer's button, spaced apart only when shown. */
.timer-toggle {
    gap: 0.25rem;
}

.timer-display {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

/* A reset timer shows a stopwatch, and a done one a flag. */
.timer-icon-done {
    display: none;
}

.timer:is(.is-running, .is-paused, .is-done) .timer-icon-idle {
    display: none;
}

.timer.is-done .timer-icon-done {
    display: inline-block;
}

/* Unless running or paused, a timer has no action and its button stands alone. */
.timer:not(.is-running, .is-paused) > .timer-toggle {
    margin-left: 0;
    border-top-left-radius: var(--tblr-btn-border-radius);
    border-bottom-left-radius: var(--tblr-btn-border-radius);
}

/* Parts of a timer show in the states they list in data-when. */
.timer [data-when] {
    display: none;
}

.timer:not(.is-running, .is-paused, .is-done) [data-when~="idle"],
.timer.is-running [data-when~="running"],
.timer.is-paused [data-when~="paused"],
.timer.is-done [data-when~="done"] {
    display: inline-flex;
}

/* The menu of a timer: the time left between a minute less and more, how
   much has passed, then reset and remove. */
.timer-menu-panel {
    min-width: 13rem;
}

/* The menu is made of spans, as a timer can sit in a paragraph. */
.timer-menu-panel .dropdown-divider {
    display: block;
}

.timer-stepper {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
}

/* Bigger in a timer's menu, where it's what the menu is about. */
.timer-stepper .timer-duration-part input {
    font-size: 1.5rem;
}

/* How long ago a timer started, and finished, side by side after an icon
   each; a click shows the times of day instead. */
.timer-moments {
    width: 100%;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
    justify-content: center;
    gap: 0.75rem;
    margin-top: 0.5rem;
    font-variant-numeric: tabular-nums;
}

.timer-moment {
    align-items: center;
    gap: 0.25rem;
}

.timer-moment:not([data-when]) {
    display: inline-flex;
}

.timer.is-running .timer-menu-panel .progress,
.timer.is-paused .timer-menu-panel .progress,
.timer:not(.is-running, .is-paused, .is-done) .timer-menu-panel .progress {
    display: flex;
    margin-top: 0.5rem;
}

/* Every button of a timer takes its state's colour, not those in its panels. */
.timer.is-running > .btn,
.timer.is-running > .btn-group > .btn {
    background: var(--tblr-primary);
    border-color: var(--tblr-primary);
    color: #fff;
}

.timer.is-paused > .btn,
.timer.is-paused > .btn-group > .btn {
    border-color: var(--tblr-primary);
    color: var(--tblr-primary);
}

.timer.is-done > .btn,
.timer.is-done > .btn-group > .btn {
    background: var(--tblr-green);
    border-color: var(--tblr-green);
    color: #fff;
}

/* The flag of a done timer bounces until the timer is reset. */
.timer.is-done .timer-icon-done {
    animation: timer-done 0.8s ease-in-out infinite;
}

@keyframes timer-done {
    0%,
    60%,
    100% {
        transform: translateY(0);
    }

    30% {
        transform: translateY(-0.25rem);
    }
}

@media (prefers-reduced-motion: reduce) {
    .timer.is-done .timer-icon-done {
        animation: none;
    }
}

/* Recipe form */

.title-input {
    width: 100%;
    padding: 0.25rem 0;
    border: 0;
    border-bottom: 2px solid var(--tblr-border-color);
    border-radius: 0;
    background: transparent;
    color: inherit;
    font-family: var(--mise-font-display);
    font-size: 2rem;
    font-weight: 700;
    line-height: 1.2;
}

.title-input:focus {
    outline: none;
    border-bottom-color: var(--tblr-primary);
}

.title-input.is-invalid {
    border-bottom-color: var(--tblr-danger);
}

.servings-input {
    width: 3rem;
    padding: 0.25rem;
    text-align: center;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    -moz-appearance: textfield;
}

.servings-input::-webkit-inner-spin-button,
.servings-input::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.tag-chip.is-added {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    background: var(--tblr-green-lt, color-mix(in oklch, var(--tblr-green) 15%, transparent));
    border-color: var(--tblr-green);
    color: var(--tblr-green);
}

.tag-remove {
    display: inline-flex;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    opacity: 0.7;
}

.tag-remove:hover {
    opacity: 1;
}

.tag-entry {
    width: 9rem;
    padding: 0.25rem 0.75rem;
    border: 1px dashed var(--tblr-border-color);
    border-radius: 999px;
    background: transparent;
    color: inherit;
    font-size: 0.8125rem;
}

.tag-entry:focus {
    outline: none;
    border-style: solid;
    border-color: var(--tblr-primary);
}

/* One ingredient per row: amount, unit and name drawn as a single input. */

.ingredient-row,
.step-fields {
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

.ingredient-option + .ingredient-option {
    margin-top: 0.375rem;
}

.ingredient-line + .ingredient-line {
    margin-top: 0.5rem;
}

.ingredient-input {
    display: flex;
    flex: 1 1 auto;
    align-items: center;
    min-width: 0;
    border: 1px solid var(--tblr-border-color);
    border-radius: var(--tblr-border-radius);
    background: var(--tblr-bg-forms, var(--tblr-bg-surface));
    transition: border-color 0.15s, box-shadow 0.15s;
}

.ingredient-input:focus-within {
    border-color: var(--tblr-primary);
    box-shadow: 0 0 0 0.2rem color-mix(in oklch, var(--tblr-primary) 20%, transparent);
}

.ingredient-input.is-invalid {
    border-color: var(--tblr-danger);
}

.ingredient-input .form-control,
.ingredient-input .form-select {
    border: 0;
    box-shadow: none;
    background-color: transparent;
}

.ingredient-input .amount-input {
    flex: 0 0 4rem;
    min-width: 0;
    padding-right: 0.25rem;
    text-align: right;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.ingredient-input .unit-select {
    flex: 0 0 auto;
    width: auto;
    padding-left: 0.25rem;
    padding-right: 1.5rem;
    background-position: right 0.25rem center;
    color: var(--tblr-secondary);
}

.ingredient-input .name-input {
    flex: 1 1 auto;
    min-width: 0;
    padding-left: 0.5rem;
    border-left: 1px solid var(--tblr-border-color);
    border-radius: 0;
}

.or-label {
    flex: 0 0 auto;
    padding-left: 1rem;
    color: var(--tblr-secondary);
    font-size: 0.8125rem;
    font-style: italic;
}

.add-alternative {
    display: none;
    padding: 0.125rem 0 0 4.5rem;
    font-size: 0.8125rem;
}

.ingredient-line:not(:last-child):focus-within .add-alternative {
    display: inline-block;
}

/* Empty rows are for adding, not removing. */
.ingredient-line:last-child .row-remove,
.step-row:last-child .row-remove,
.step-row:has(.step-input:placeholder-shown) .row-remove {
    visibility: hidden;
}

.step-rows {
    counter-reset: step;
}

.step-row {
    counter-increment: step;
    position: relative;
    padding-left: 2rem;
}

.step-row::before {
    content: counter(step);
    position: absolute;
    left: 0;
    top: 0.4rem;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    background: var(--tblr-primary-lt, color-mix(in oklch, var(--tblr-primary) 15%, transparent));
    color: var(--tblr-primary);
    font-weight: 700;
    font-size: 0.8125rem;
    display: grid;
    place-items: center;
}

.step-row:last-child::before,
.step-row:has(.step-input:placeholder-shown)::before {
    background: transparent;
    border: 1px dashed var(--tblr-border-color);
    color: var(--tblr-secondary);
}

.step-row + .step-row {
    margin-top: 0.5rem;
}

.step-fields {
    align-items: flex-start;
}

.step-input {
    field-sizing: content;
    min-height: 2.375rem;
    resize: none;
}

/* Tips on writing a step, dropped down below an empty step while it's focused. */
.step-tips {
    top: 100%;
    left: 2rem;
    max-width: min(24rem, calc(100% - 2rem));
    margin-top: 0.25rem;
    white-space: normal;
}

.step-row:has(.step-input:focus:placeholder-shown) .step-tips {
    display: block;
}

.step-tip {
    display: flex;
    gap: 0.5rem;
}

.step-tip .icon {
    flex-shrink: 0;
    margin-top: 0.2rem;
}

.step-tip code {
    white-space: pre-line;
}

.form-actions {
    position: sticky;
    bottom: 0;
    z-index: 10;
    margin-top: 1.5rem;
    padding-block: 0.75rem;
    background: var(--tblr-body-bg);
    border-top: 1px solid var(--tblr-border-color);
}

/* Cooking: the steps scroll, the current one in large text and the others
   small and dimmed. Without JavaScript, a list. */

turbo-frame {
    display: block;
}

.cooking-ingredients,
.cooking-description {
    font-size: 0.8125rem;
}

.cooking-description .markdown > :last-child,
.recipe-description > :last-child {
    margin-bottom: 0;
}

.cooking-ingredients .list-group-item {
    padding-block: 0.375rem;
}

/* Above the steps: the overview toggle, the timers that are going, and
   a button to add a timer of your own. */
.cooking-bar {
    position: sticky;
    top: 0;
    z-index: 2;
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: flex-end;
    /* Rows are spaced by the margins of what's on them, so the break between
       them takes no room. */
    column-gap: 0.5rem;
    padding-block: calc(var(--tblr-card-cap-padding-y) - 0.25rem);
    background: var(--tblr-bg-surface, var(--tblr-body-bg));
}

/* A full bar fades the button but not its clock, which still tells the time. */
.cooking-add-timer:disabled {
    --tblr-btn-disabled-border-color: color-mix(in oklch, var(--tblr-border-color) 40%, transparent);
    opacity: 1;
}

.cooking-add-timer:disabled > :not(.cooking-clock) {
    opacity: var(--tblr-btn-disabled-opacity);
}

/* The clock fits in the line of its button, so the button is as high as a
   timer's, and keeps its width as the minutes change. */
.cooking-clock {
    height: var(--tblr-btn-line-height);
    padding-block: 0;
    font-variant-numeric: tabular-nums;
}

/* The bar covers the page's spine, so it draws the spine again. */
.book-page .cooking-bar {
    background:
        linear-gradient(to right, var(--page-spine-bg) var(--page-spine), var(--page-edge) var(--page-spine) calc(var(--page-spine) + 1px), transparent calc(var(--page-spine) + 1px)),
        var(--page-bg);
}

.cooking-bar > *,
.cooking-timer-row > * {
    margin-block: 0.25rem;
}

/* Every button on the bar is as high as a small button, whatever it holds,
   so they line up. Those in the panels they open keep their own height. */
.cooking-bar > .btn,
.cooking-bar > .dropdown > .btn,
.cooking-timer-row > .timer > .btn {
    height: calc(var(--tblr-btn-line-height) + var(--tblr-btn-padding-y) * 2 + var(--tblr-btn-border-width) * 2);
}

/* Above the rest of the page while a panel's spotlight dims it. */
.cooking-bar:has(.dropdown-panel.show) {
    z-index: 1030;
}

/* The top row holds the buttons, with your own timers just before the one
   to add a timer. Those that don't fit start the row below, which holds the
   timers of the steps. Rows are lined up on the right. The timers are
   ordered rather than moved, as moving one would restart it. */
.cooking-timer-row {
    display: contents;
}

/* Says where it leads: the kitchen, or the recipe by its title, cut short
   if long. */
.cooking-back {
    min-width: 0;
    max-width: 14rem;
    margin-right: auto;
}

.cooking-bar > .cooking-bar-break {
    flex-basis: 100%;
    height: 0;
    margin: 0;
    order: 1;
}

.cooking-own-timers > .timer.is-below,
.cooking-step-timers > .timer {
    order: 2;
}

/* The timers of the steps lead with the recipe's book icon, which sets them
   apart from yours before them. It's part of the first, so it never ends
   up on a line of its own. */
/* The group's shadow would wrap the icon too; the buttons take it instead. */
.cooking-step-timers > .timer:first-of-type {
    box-shadow: none;
}

.cooking-step-timers > .timer:first-of-type > .btn {
    box-shadow: var(--tblr-shadow-input);
}

/* After the timer, but shown first, as an open panel's spotlight takes the
   timer's ::before. */
.cooking-step-timers > .timer:first-of-type::after {
    content: "";
    order: -1;
    flex: none;
    align-self: center;
    width: 1.25rem;
    height: 1.25rem;
    margin-inline: 0.25rem 0.5rem;
    background: var(--tblr-secondary);
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 19a9 9 0 0 1 9 0a9 9 0 0 1 9 0'/%3E%3Cpath d='M3 6a9 9 0 0 1 9 0a9 9 0 0 1 9 0'/%3E%3Cpath d='M3 6v13'/%3E%3Cpath d='M12 6v13'/%3E%3Cpath d='M21 6v13'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* The timers of other steps than the current one fade, until pointed at
   or opened. One that's done stands out wherever it's from. */
.cooking-step-timers > .timer {
    transition: opacity 0.2s;
}

.cooking-step-timers > .timer.is-elsewhere:not(.is-done, :hover, :focus-within, :has(.dropdown-menu.show)) {
    opacity: 0.45;
}

/* A timer of your own fades in as it's added. */
.cooking-timer-row > .timer {
    animation: timer-appear 0.25s ease-out;
}

@keyframes timer-appear {
    from {
        opacity: 0;
        transform: scale(0.9);
    }
}

@media (prefers-reduced-motion: reduce) {
    .cooking-timer-row > .timer {
        animation: none;
    }
}

.timer-form {
    width: min(16rem, calc(100vw - 2rem));
}

/* The name's character count sits inside its field, while it has focus.
   It keeps its width as it changes. */
.timer-name {
    position: relative;
}

.timer-name .form-control:focus {
    padding-right: 3rem;
}

.timer-name-count {
    position: absolute;
    top: 50%;
    right: 0.5rem;
    transform: translateY(-50%);
    color: var(--tblr-secondary);
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
    pointer-events: none;
}

.timer-name:not(:focus-within) .timer-name-count {
    display: none;
}

/* One field for a duration's hours, minutes and seconds. */
.timer-duration {
    display: flex;
    width: 100%;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    padding: 0.25rem 0.5rem;
    border: 1px solid var(--tblr-border-color);
    border-radius: var(--tblr-border-radius);
    background: var(--tblr-bg-forms, var(--tblr-bg-surface));
    transition: border-color 0.15s, box-shadow 0.15s;
}

.timer-duration:focus-within {
    border-color: var(--tblr-primary);
    box-shadow: 0 0 0 0.2rem color-mix(in oklch, var(--tblr-primary) 20%, transparent);
}

.timer-duration-part {
    display: flex;
    align-items: center;
    gap: 0.125rem;
}

.timer-duration-value {
    display: flex;
    align-items: baseline;
    gap: 0.125rem;
    margin: 0;
    color: var(--tblr-secondary);
}

/* The arrows after a part's unit, stacked, in place of the browser's own. */
.timer-duration-steps {
    display: flex;
    flex-direction: column;
}

.timer-duration-steps button {
    display: flex;
    padding: 0;
    border: 0;
    background: none;
    color: var(--tblr-secondary);
    line-height: 1;
}

.timer-duration-steps button:hover:not(:disabled) {
    color: var(--tblr-body-color);
}

.timer-duration-steps button:disabled {
    visibility: hidden;
}

.timer-duration-steps .icon {
    width: 0.875rem;
    height: 0.875rem;
}

/* Wide enough for two digits. */
.timer-duration-part input {
    width: 2ch;
    padding: 0;
    appearance: textfield;
    border: 0;
    outline: 0;
    background: transparent;
    color: var(--tblr-body-color);
    font-size: 1.25rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.timer-duration-part input::-webkit-inner-spin-button,
.timer-duration-part input::-webkit-outer-spin-button {
    margin: 0;
    appearance: none;
}

.timer-duration-part input:disabled {
    color: var(--tblr-secondary);
}

.cooking-steps {
    list-style: none;
    margin: 0;
    padding: 1.5rem;
    display: flex;
    flex-direction: column;
    gap: 2rem;
}

.cooking-step-number {
    color: var(--tblr-secondary);
    font-size: 0.8125rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-bottom: 0.75rem;
}

.cooking-step-text {
    font-size: clamp(1.375rem, 1.14rem + 0.75vw, 1.6875rem);
    line-height: 1.45;
    font-weight: 500;
}

/* Trims the space above the capitals, so the text starts at the same
   height in large and small. Only on an opening paragraph: on the step as a
   whole, Chrome trims the line of a checklist item once it's pointed at. */
.cooking-step-text > p:first-child {
    text-box: trim-start cap alphabetic;
}

.cooking-step-text .timer > .btn,
.cooking-step-text .timer > .btn-group > .btn {
    font-size: 1rem;
}

/* The steps scroll within a fixed height, which the controller fits to the
   window. It also sets the bottom padding so the last step just reaches its
   trigger line. */
.cooking.is-scroller .cooking-viewport {
    --cooking-height: min(65svh, 34rem);
    /* The steps' offsets are measured from here, not from the card with the timers above. */
    position: relative;
    height: var(--cooking-height);
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* The steps fade out at the bottom, and at the top once scrolled. Overlays
   rather than a mask, which would also cut off the panels of the timers in
   the steps. */
.cooking.is-scroller .cooking-frame {
    position: relative;
}

.cooking.is-scroller .cooking-frame::before,
.cooking.is-scroller .cooking-frame::after {
    content: "";
    position: absolute;
    inset-inline: 0;
    z-index: 1;
    pointer-events: none;
}

/* The fades leave the page's spine showing. */
.book-page.cooking.is-scroller .cooking-frame::before,
.book-page.cooking.is-scroller .cooking-frame::after {
    left: calc(var(--page-spine) + 1px);
}

.cooking.is-scroller .cooking-frame::before {
    top: 0;
    height: 12%;
    background: linear-gradient(to top, transparent, var(--tblr-card-bg, var(--tblr-bg-surface)));
    opacity: 0;
}

.cooking.is-scroller.is-scrolled .cooking-frame::before {
    opacity: 1;
}

.cooking.is-scroller .cooking-frame::after {
    bottom: 0;
    height: 15%;
    background: linear-gradient(to bottom, transparent, var(--tblr-card-bg, var(--tblr-bg-surface)));
}

.cooking.is-scroller .cooking-steps {
    padding-bottom: calc(var(--cooking-height) * 0.75);
}

/* The other steps are smaller and dimmed, in the height of their large
   text, measured with all steps large. A tap anywhere on one makes it
   current, rather than ticking its checkboxes or starting its timers. */
.cooking.is-scroller .cooking-step {
    opacity: 0.35;
    cursor: pointer;
}

.cooking.is-scroller:not(.is-measuring) .cooking-step:not([aria-current]) .cooking-step-text {
    font-size: 1.125rem;
    pointer-events: none;
}

/* The new current step brightens up; the one before dims at once, so the
   two never look current together. */
.cooking.is-scroller .cooking-step[aria-current] {
    opacity: 1;
    cursor: auto;
    animation: step-brighten 0.3s ease-out;
}

@keyframes step-brighten {
    from {
        opacity: 0.35;
    }
}

@media (prefers-reduced-motion: reduce) {
    .cooking.is-scroller .cooking-step[aria-current] {
        animation: none;
    }
}

/* Shows or hides the description and ingredients beside the steps; pressed while they show. */
.overview-toggle[aria-expanded="true"] {
    color: var(--tblr-primary);
    border-color: color-mix(in oklch, var(--tblr-primary) 45%, var(--tblr-border-color));
    background: color-mix(in oklch, var(--tblr-primary) 8%, transparent);
}

/* Done fills the footer; its form is inline, but not as a flex item. */
.cooking-footer {
    display: flex;
}

.cooking-footer > form {
    flex: 1;
}

/* Timers in the text of a step */

/* A time a step mentions, outside cooking: marked with a clock, not a timer yet. */
.timer-hint {
    white-space: nowrap;
}

.timer-hint .icon {
    margin-right: 0.125rem;
    color: var(--tblr-secondary);
    vertical-align: -0.125em;
}

/* A timer stays on one line with the text right against it, like a period. */
.timer-nowrap {
    white-space: nowrap;
}

/* Its menu wraps as usual. */
.timer-nowrap .dropdown-menu {
    white-space: normal;
}

.step-text .timer {
    vertical-align: baseline;
    margin-inline: 0.125rem;
}

.step-text .timer > .btn,
.step-text .timer > .btn-group > .btn {
    padding-block: 0.125rem;
}

/* Shopping list */

/* Each line is a button that checks it off. It looks checked right away,
   and moves a second later (shopping_list_controller.js). */

/* Compact rows, so a long list fits on a phone screen in the shop. The
   button fills the whole row, so all of it checks the line off. */
.shopping-item {
    padding: 0;
    line-height: 1.3;
}

/* The full list has room for roomier rows. */
.shopping-lines.is-full .shopping-toggle {
    padding-block: 0.75rem;
}

/* Alternating rows, to follow a line from its amount to its name. */
.shopping-item:nth-child(even) {
    background: var(--tblr-bg-surface-secondary, color-mix(in oklch, var(--tblr-body-color) 3%, transparent));
}

/* What was checked off recently stays in sight, but steps back. */
.shopping-bought {
    opacity: 0.6;
}

.shopping-bought .shopping-item:nth-child(even) {
    background: none;
}

.shopping-toggle {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    width: 100%;
    padding: 0.5rem var(--tblr-list-group-item-padding-x, 1.25rem);
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-align: start;
    cursor: pointer;
}

.shopping-box {
    display: inline-flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    width: 1.125rem;
    height: 1.125rem;
    margin-top: 0.0625rem;
    border: 1px solid var(--tblr-border-color-translucent, var(--tblr-border-color));
    border-radius: var(--tblr-border-radius);
    background: var(--tblr-bg-forms, transparent);
}

.shopping-box .icon {
    width: 0.875rem;
    height: 0.875rem;
    visibility: hidden;
}

.shopping-toggle:focus-visible .shopping-box {
    outline: 2px solid var(--tblr-primary);
    outline-offset: 2px;
}

.shopping-item.is-checked .shopping-box {
    border-color: var(--tblr-green);
    background: var(--tblr-green);
    color: #fff;
}

.shopping-item.is-checked .shopping-box .icon {
    visibility: visible;
}

.shopping-item.is-checked .shopping-name,
.shopping-item.is-checked .shopping-amount {
    color: var(--tblr-secondary);
}

.shopping-item.is-checked .shopping-name {
    text-decoration: line-through;
}

/* Amounts first, right-aligned in a column of their own so the names line up. */
.shopping-amount {
    flex: none;
    min-width: 4.5rem;
    text-align: right;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

/* Where a line comes from, as tags after it: icons only, with their names
   on the full list from medium screens up. */
.shopping-sources {
    display: flex;
    flex: none;
    gap: 0.25rem;
    max-width: 40%;
    min-width: 0;
}

.shopping-source {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    min-width: 0;
}

.shopping-source-label {
    display: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

@media (min-width: 768px) {
    .shopping-lines.is-full .shopping-source-label {
        display: inline;
    }
}

/* The panel to jot something down holds a whole ingredient row. */
.shopping-jot-down {
    width: min(24rem, calc(100vw - 2rem));
}

@media print {
    .navbar,
    .footer {
        display: none !important;
    }

    .shopping-list {
        border: 0;
        box-shadow: none;
    }
}

/* Writing a recipe, step by step */

/* A recipe's page, where each section edits in place: its heading across
   the top, then the ingredients and the method, side by side on a wide
   screen like two facing pages. Space sets them apart, not lines. */
.recipe-page {
    padding: 2rem 2rem 2rem 2.25rem;
}

@media (max-width: 575.98px) {
    .recipe-page {
        padding: 1.25rem 1rem 1.25rem 1.5rem;
    }
}

.recipe-heading {
    margin-bottom: 2.5rem;
}

/* The recipe's name as the title of its page, large in the display face,
   with its pencil centred on the first line. */
.recipe-heading {
    --title-size: clamp(2.25rem, 1.5rem + 2.5vw, 3.5rem);
    --title-leading: 1.1;
}

.recipe-title {
    margin: 0;
    font-size: var(--title-size);
    font-weight: 600;
    line-height: var(--title-leading);
    letter-spacing: -0.02em;
    text-wrap: balance;
}

.recipe-heading .recipe-title + .recipe-edit {
    margin-top: calc((var(--title-size) * var(--title-leading) - 2rem) / 2);
}

.recipe-spread {
    display: grid;
    gap: 2.5rem;
}

/* On a wide screen, the ingredients take a narrow column. While edited,
   their form grows over the method dimmed beneath it, which stays in place,
   up to a width that suits it. */
@media (min-width: 992px) {
    .recipe-spread {
        grid-template-columns: minmax(0, 2fr) minmax(0, 5fr);
        column-gap: 4rem;
    }

    .recipe-spread > #recipe-method {
        grid-area: 1 / 2;
    }

    .recipe-spread > #recipe-ingredients:has(> form) {
        grid-area: 1 / 1 / auto / -1;
        justify-self: start;
        width: min(100%, 48rem);
    }
}

/* Each section opens its form wherever it's clicked, through its pencil
   stretched over it. Tags and links in it stay usable above the pencil,
   which shows on hover and focus where there is a pointer to hover with. */
.recipe-frame {
    display: block;
    position: relative;
}

.recipe-frame :is(.recipe-tags, .step-text a) {
    position: relative;
    z-index: 2;
}

.recipe-edit {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    color: var(--tblr-secondary);
}

@media (hover: hover) {
    .recipe-edit {
        opacity: 0;
        transition: opacity 0.15s ease-out;
    }

    .recipe-frame:is(:hover, :focus-within) .recipe-edit {
        opacity: 1;
    }
}

.recipe-section-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 2rem;
    margin-bottom: 0.75rem;
}

/* Lists run on the page itself, lined up with its headings. */
.recipe-page .list-group-item {
    padding-inline: 0;
    border: 0;
    background: transparent;
}

.recipe-page .ingredient-list .list-group-item {
    padding-block: 0.375rem;
}

.recipe-page .step-list .step {
    padding-left: 2.25rem;
}

.recipe-page .step-list .step::before {
    left: 0;
}

.recipe-section-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
}

.recipe-flow {
    max-width: 48rem;
    margin-inline: auto;
}

.flow-steps {
    display: flex;
    gap: 0.5rem;
    margin: 1rem 0 1.5rem;
    padding: 0;
    list-style: none;
}

.flow-step {
    flex: 1;
    padding-top: 0.5rem;
    border-top: 3px solid var(--tblr-border-color);
}

.flow-step.is-done,
.flow-step.is-current {
    border-top-color: var(--tblr-primary);
}

.flow-step-link {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0;
    border: 0;
    background: none;
    color: var(--tblr-secondary);
    font-weight: 500;
}

.flow-step.is-current .flow-step-link {
    color: var(--tblr-body-color);
    font-weight: 600;
}

button.flow-step-link:hover {
    color: var(--tblr-primary);
}

.flow-step-number {
    display: grid;
    place-items: center;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    border: 1px solid var(--tblr-border-color);
    font-size: 0.8125rem;
    font-variant-numeric: tabular-nums;
}

.flow-step.is-done .flow-step-number,
.flow-step.is-current .flow-step-number {
    border-color: var(--tblr-primary);
    background: var(--tblr-primary);
    color: var(--tblr-primary-fg, #fff);
}

/* Dashboard: meals first, with the shopping list and cookbook beside them.
   On a phone the shopping list comes right after the heading, for use in the
   shop. */

.dashboard {
    display: grid;
    gap: 1.5rem;
}

.dashboard-side {
    display: contents;
}

.dashboard-header {
    order: -2;
}

.dashboard-shopping {
    order: -1;
}

@media (min-width: 992px) {
    /* The heading tops the meals only, so the side column starts at the top.
       The side column spans both rows; the second row takes its extra height. */
    .dashboard {
        grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
        grid-template-rows: auto 1fr;
        align-items: start;
    }

    .dashboard-header,
    .dashboard-meals {
        grid-column: 1;
    }

    .dashboard-side {
        grid-column: 2;
        grid-row: 1 / span 2;
        display: flex;
        flex-direction: column;
        gap: 1.5rem;
    }
}

/* Meal picker */

.picker-card {
    overflow: hidden;
    transition: border-color 0.15s, box-shadow 0.15s;
}

.picker-card:has(.picker-check:checked) {
    border-color: var(--tblr-primary);
    box-shadow: 0 0 0 1px var(--tblr-primary);
}

.picker-card:has(.picker-check:focus-visible) {
    outline: 2px solid var(--tblr-primary);
    outline-offset: 2px;
}

.picker-choose {
    position: relative;
    display: block;
    flex: 1;
    cursor: pointer;
}

.picker-check {
    position: absolute;
    top: 0.75rem;
    right: 0.75rem;
    width: 1.5rem;
    height: 1.5rem;
    margin: 0;
    border-radius: 50%;
}

.picker-tile {
    display: grid;
    place-items: center;
    height: 5.5rem;
    font-family: var(--mise-font-display);
    font-size: 2.5rem;
    font-weight: 700;
    background: oklch(93% 0.05 var(--hue));
    color: oklch(45% 0.13 var(--hue));
}

[data-bs-theme="dark"] .picker-tile {
    background: oklch(32% 0.05 var(--hue));
    color: oklch(85% 0.09 var(--hue));
}

.picker-chosen {
    display: none;
    align-items: center;
    gap: 0.5rem;
    padding-block: 0.5rem;
}

.picker-card:has(.picker-check:checked) .picker-chosen {
    display: flex;
}

/*
 * The kitchen settings: a slot for each member and pending invite, and a
 * dashed one while there's room for another.
 */
.member-slots {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 18rem), 1fr));
    gap: 1rem;
}

.member-slot {
    min-height: 4.75rem;
    margin: 0;
}

.member-slot-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.25rem;
    border: 1px dashed var(--tblr-border-color-dark, var(--tblr-border-color));
    border-radius: var(--tblr-border-radius-lg, 0.5rem);
    background: transparent;
    color: var(--tblr-secondary);
}

button.member-slot-empty {
    transition: color 0.15s, border-color 0.15s;
}

button.member-slot-empty:hover,
button.member-slot-empty:focus-visible {
    border-color: var(--tblr-primary);
    color: var(--tblr-primary);
}

.avatar-pending {
    background: transparent;
    border: 1px dashed var(--tblr-border-color-dark, var(--tblr-border-color));
    color: var(--tblr-secondary);
}

.app-dialog {
    width: min(36rem, calc(100vw - 2rem));
    padding: 0;
    border: 0;
    border-radius: var(--tblr-border-radius-lg, 0.5rem);
    background: transparent;
    color: inherit;
}

.app-dialog::backdrop {
    background: rgb(24 36 51 / 0.5);
    backdrop-filter: blur(2px);
}

/* Tabler's modal parts read these from .modal, which a native dialog isn't. */
.app-dialog {
    --tblr-modal-padding: 1.5rem;
    --tblr-modal-color: var(--tblr-body-color);
    --tblr-modal-bg: var(--tblr-bg-surface);
    --tblr-modal-border-color: transparent;
    --tblr-modal-border-width: var(--tblr-border-width);
    --tblr-modal-border-radius: var(--tblr-border-radius-lg);
    --tblr-modal-inner-border-radius: calc(var(--tblr-border-radius-lg) - var(--tblr-border-width));
    --tblr-modal-header-padding: 1.5rem;
    --tblr-modal-header-border-color: var(--tblr-border-color);
    --tblr-modal-header-border-width: var(--tblr-border-width);
    --tblr-modal-title-line-height: 1.4285714286;
    --tblr-modal-footer-gap: 0.75rem;
    --tblr-modal-footer-bg: var(--tblr-bg-surface-tertiary);
    --tblr-modal-footer-border-color: var(--tblr-border-color);
    --tblr-modal-footer-border-width: var(--tblr-border-width);
}

.app-dialog .modal-content {
    border: 0;
    background: var(--tblr-modal-bg);
    color: var(--tblr-modal-color);
    box-shadow: var(--tblr-box-shadow-dropdown, 0 1rem 3rem rgb(0 0 0 / 0.2));
}

.app-dialog .modal-header {
    align-items: flex-start;
    height: auto;
    padding-block: 1.25rem;
}

/* One row per ingredient line, each alternative a large radio button. */
/*
 * The alternatives of a recipe's lines, one segmented control per line: the
 * options side by side on a track, the chosen one raised off it. Options
 * that don't fit side by side wrap within the track.
 */
.variations {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.variation {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    padding: 0.25rem;
    border-radius: var(--tblr-border-radius-lg);
    background: var(--tblr-bg-surface-secondary);
}

.variation-option {
    flex: 1 1 8rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-width: 0;
    padding: 0.5rem 0.75rem;
    border-radius: var(--tblr-border-radius);
    color: var(--tblr-secondary);
    text-align: center;
    cursor: pointer;
    transition: color 0.15s, background-color 0.15s, box-shadow 0.15s;
}

.variation-option:hover {
    color: var(--tblr-body-color);
}

/* The chosen one in the primary colour: tinted, outlined and raised. */
.variation-option:has(:checked) {
    background: color-mix(in oklch, var(--tblr-primary) 10%, var(--tblr-bg-surface));
    color: var(--tblr-primary);
    box-shadow: 0 0 0 2px var(--tblr-primary), 0 1px 3px rgb(0 0 0 / 0.08);
}

.variation-option:has(:checked) .variation-amount {
    color: color-mix(in oklch, var(--tblr-primary) 75%, var(--tblr-body-color));
}

.variation-option:has(:focus-visible) {
    outline: 2px solid var(--tblr-primary);
    outline-offset: 3px;
}

.variation-name {
    font-weight: 600;
    line-height: 1.3;
    overflow-wrap: anywhere;
}

.variation-amount {
    font-size: 0.8125rem;
    color: var(--tblr-secondary);
    font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: reduce) {
    .variation-option {
        transition: none;
    }
}

.meal-cart {
    position: sticky;
    bottom: 1rem;
    z-index: 10;
    margin-top: 1.5rem;
    box-shadow: var(--tblr-box-shadow-dropdown, 0 0.5rem 1.5rem rgb(0 0 0 / 0.12));
}

.meal-cart-icon {
    color: var(--tblr-primary);
}

.meal-cart-picks {
    display: flex;
    gap: 0.5rem;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: thin;
}

.meal-cart-picks:empty {
    display: none;
}

.meal-cart-pick {
    display: inline-flex;
    flex: none;
    align-items: center;
    gap: 0.375rem;
    padding: 0.25rem 0.375rem 0.25rem 0.625rem;
    border-radius: 999px;
    background: var(--tblr-primary-lt, color-mix(in oklch, var(--tblr-primary) 12%, transparent));
    color: var(--tblr-primary);
    font-weight: 500;
    white-space: nowrap;
}

/* Servings typed or stepped on a picked card. */
.picker-servings {
    width: 2.5ch;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-align: center;
    appearance: textfield;
}

.picker-servings::-webkit-inner-spin-button,
.picker-servings::-webkit-outer-spin-button {
    margin: 0;
    appearance: none;
}

.meal-cart-servings {
    display: inline-flex;
    align-items: center;
    gap: 0.125rem;
    font-variant-numeric: tabular-nums;
    opacity: 0.8;
}

.meal-cart-pick .btn-close {
    width: 0.625rem;
    height: 0.625rem;
    padding: 0.25rem;
}

/*
 * The homepage's hero fills the first screen below the navbar, so how it
 * works starts right at the fold. The navbar is as high as its minimum, and
 * the row's gutter pulls it up by as much as its gutter.
 */
.home-hero {
    min-height: calc(100svh - 3.5rem - var(--tblr-page-padding-y) + var(--tblr-gutter-y));
    align-content: center;
}

/*
 * How it works, on the homepage: a row per step, its text beside a mockup
 * of the app on a soft backdrop, alternating sides from large screens up.
 */
.showcase-step + .showcase-step {
    margin-top: 3rem;
}

@media (min-width: 992px) {
    .showcase-step + .showcase-step {
        margin-top: 5rem;
    }
}

.showcase-number {
    display: inline-grid;
    place-items: center;
    width: 2.5rem;
    height: 2.5rem;
    margin-bottom: 1rem;
    border-radius: 50%;
    background: var(--tblr-primary-lt);
    color: var(--tblr-primary);
    font-family: var(--mise-font-display);
    font-size: 1.25rem;
    font-weight: 700;
}

/* The mockup sits on a tinted backdrop, so it reads as a picture of the
   app rather than part of the page. */
.showcase-visual {
    padding: clamp(1rem, 3vw, 2rem);
    border-radius: var(--tblr-border-radius-xl, 1rem);
    background: color-mix(in oklch, var(--tblr-primary) 7%, var(--tblr-bg-surface-secondary));
    user-select: none;
}
