@layer tokens, base, components, layouts, screens;

@layer tokens {
  /* The font of DESIGN.md: Plus Jakarta Sans, variable 200-800, latin subset, SIL OFL
     (fonts/OFL.txt). It is in SHELL of sw.js (SW-2), so it shows offline. */
  @font-face {
    font-family: "Plus Jakarta Sans";
    src: url("fonts/plus-jakarta-sans.woff2") format("woff2");
    font-weight: 200 800;
    font-display: swap;
  }

  /* The Warm Gourmet look of DESIGN.md: clotted cream, paprika and basil. Each colour has a
     light and a dark value. Text on --primary and on --done is at least 4.5:1 in both themes. */
  :root {
    --font: "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

    --bg: light-dark(#faf8f5, #16120f); /* clotted cream */
    --surface: light-dark(#ffffff, #201a16); /* cards, rows, header, sheets */
    --surface-2: light-dark(#f3eeea, #2a231e); /* trays, fields, filter sheets */
    --text: light-dark(#1a1a1a, #f5f0eb); /* charred truffle */
    --muted: light-dark(#6b564c, #b9aa9f);
    --line: light-dark(#e9e2da, #3a312a);
    --control: light-dark(#d7ccc8, #4a4039);
    --primary: light-dark(#b33f00, #ff8f59); /* paprika, dark enough for white text: 5.8:1 */
    --on-primary: light-dark(#ffffff, #2a0e00); /* 5.8:1 light, 8.0:1 dark */
    --paprika: light-dark(#e65100, #ff7a2f); /* the brand hue for art and the wheel; text on it is --on-wheel-1, never white */
    --done: light-dark(#2e7d32, #7cc57f); /* basil */
    --on-done: light-dark(#ffffff, #0b1f0c); /* 5.1:1 light, 8.4:1 dark */
    --done-soft: light-dark(#e8f5e9, #1e3320);
    --ink: light-dark(#1a1a1a, #f5f0eb);
    --on-ink: light-dark(#ffffff, #1a1a1a);
    --secondary: light-dark(#fbe9e7, #3d2a20); /* a paprika tint: the current nav item */
    --wheel-1: var(--paprika); /* the segments of the roulette */
    --wheel-2: light-dark(#2e7d32, #66bb6a); /* basil */
    --wheel-3: light-dark(#f4511e, #ff7043); /* saffron */
    --wheel-4: light-dark(#5d4037, #a1887f); /* cocoa */
    /* The text on each segment of the wheel: 4.5:1 or more in both themes. */
    --on-wheel-1: light-dark(#000000, #1a1a1a); /* 5.5:1 light, 6.7:1 dark */
    --on-wheel-2: light-dark(#ffffff, #1a1a1a); /* 5.1:1 light, 7.4:1 dark */
    --on-wheel-3: light-dark(#000000, #1a1a1a); /* 6.0:1 light, 6.3:1 dark */
    --on-wheel-4: light-dark(#ffffff, #1a1a1a); /* 9.3:1 light, 5.3:1 dark */
    --wheel-size: 400px; /* the most that the wheel grows */
    --roulette-max: 1040px; /* the Roulette from 840px: the wheel and the result side by side */
    --spin-ease: cubic-bezier(0.15, 0.85, 0.2, 1); /* the ease-out of a spin */
    /* The grounds of a cuisine tile: a soft tint of each wheel colour. The tile holds an emoji
       only, never text. */
    --tile-1: color-mix(in srgb, var(--wheel-1) 18%, var(--surface));
    --tile-2: color-mix(in srgb, var(--wheel-2) 18%, var(--surface));
    --tile-3: color-mix(in srgb, var(--wheel-3) 18%, var(--surface));
    --tile-4: color-mix(in srgb, var(--wheel-4) 18%, var(--surface));

    --radius-control: 16px; /* inputs, chips */
    --radius-m: var(--radius-pill); /* buttons are capsules */
    --radius-l: 24px; /* cards, groups, banner */
    --radius-card: 32px; /* the hero card */
    --radius-xl: 32px; /* top of a sheet */

    --shadow-l: 0 16px 40px -6px rgb(26 26 26 / 0.12), 0 0 0 1px var(--line); /* floating bar, sheets, toasts */
  }
}

@layer base {
  body {
    margin: 0;
    display: flex;
    flex-direction: column;
    height: 100dvh;
    background: var(--bg);
    color: var(--text);
    font: var(--text-m)/1.4 var(--font);
    -webkit-tap-highlight-color: transparent;
    /* The page keeps out of a cutout on either side (LAY-4); from 600px the rail takes its side. */
    padding-inline-start: env(safe-area-inset-left);
    padding-inline-end: env(safe-area-inset-right);
  }

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

  /* From 600px the fixed rail stands at the side of the hand (LAY-2): the body pads that side (LAY-4). */
  @media (min-width: 600px) {
    body {
      padding-right: calc(var(--rail-width) + env(safe-area-inset-right));
    }

    [data-hand="left"] body {
      padding-right: env(safe-area-inset-right);
      padding-left: calc(var(--rail-width) + env(safe-area-inset-left));
    }
  }
}

@layer screens {
  /* @component explore-search
     @scope explore
     @summary The search of Explore, at the top of the list: a capsule input. It matches the name, the area, the cuisine and the dishes of a place.
     @example <input class="input explore-search" type="search" placeholder="Search places, dishes or cuisines"> */
  .explore-search {
    display: block;
    width: calc(100% - 2 * var(--space-4));
    margin: var(--space-3) var(--space-4);
    padding-inline: var(--space-5);
    border-radius: var(--radius-pill);
  }

  /* @component filter-bar
     @scope explore
     @summary The filter chips under the search of Explore and of the roulette: one row (cluster scroll) that scrolls sideways. A chip with a value is pressed, in --ink.
     @part filter-chip  One chip: Price, Max price, Distance, Favourites or Cuisine. A chip that opens the filter sheet has aria-haspopup="dialog".
     @state data-state  On filter-chip: `waiting` (a dashed border) while the distance has no fix or a read runs, `error` (a --danger border) after a read that failed, also on a pressed chip whose older fix still filters.
     @example <div class="cluster scroll filter-bar" style="width: 100%"><button class="chip filter-chip" type="button" aria-pressed="true"><span>€ – €€</span></button><button class="chip filter-chip" type="button" aria-pressed="false" data-state="waiting"><svg class="icon small" aria-hidden="true"><use href="icons.svg#pin"/></svg><span>&lt; 2 km · no position</span></button><button class="chip filter-chip" type="button" aria-pressed="false" data-state="error"><svg class="icon small" aria-hidden="true"><use href="icons.svg#pin"/></svg><span>No position</span></button><button class="chip filter-chip" type="button" aria-pressed="false"><svg class="icon small" aria-hidden="true"><use href="icons.svg#heart"/></svg><span>Favourites</span></button></div> */
  .filter-bar {
    margin: 0 0 var(--space-3);
    padding-inline-start: var(--space-4);
    /* The last chip clears the fade at the end of the row. */
    padding-inline-end: var(--space-7);
    scroll-padding-inline: var(--space-4);
  }

  .filter-chip {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    white-space: nowrap;
  }

  .filter-chip[data-state="waiting"] {
    border-style: dashed;
    color: var(--muted);
  }

  .filter-chip[data-state="error"] {
    border-color: var(--danger);
    color: var(--danger);
  }

  /* A pressed chip keeps its --on-ink text for contrast; a --danger ring marks the failed read. */
  .filter-chip[aria-pressed="true"][data-state="error"] {
    color: var(--on-ink);
    box-shadow: 0 0 0 2px var(--danger);
  }

  /* @component decide
     @scope explore
     @summary The "Can't decide?" card of Explore, in --primary: a title, a line and the button that goes to the roulette. It hides while the roulette module is off.
     @part decide-text   The title and the line.
     @part decide-title  The title.
     @part decide-lead   The line below the title.
     @example <div class="decide" style="width: 100%"><div class="decide-text"><h2 class="decide-title">Can't decide?</h2><p class="decide-lead">Spin the roulette over the places of these filters.</p></div><button class="button tonal" type="button"><svg class="icon small" aria-hidden="true"><use href="icons.svg#wheel"/></svg><span>Go to the roulette</span></button></div> */
  .decide {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin: 0 var(--space-4) var(--space-4);
    padding: var(--space-4) var(--space-5);
    border-radius: var(--radius-l);
    background: var(--primary);
    color: var(--on-primary);
  }

  .decide-text {
    min-width: 0;
  }

  .decide-title {
    margin: 0;
    font-size: var(--text-h);
    font-weight: var(--weight-strong);
  }

  .decide-lead {
    margin: var(--space-1) 0 0;
    font-size: var(--text-s);
  }

  /* The --secondary fill of a tonal button is close to --primary, so the button stands on --surface. */
  .decide > .button.tonal {
    background: var(--surface);
    color: var(--text);
  }

  /* @component filter-sheet
     @scope explore
     @summary The parts of the filter sheet: one shows at a time, by the chip that opened it. Price is two tier-pickers (From and To); Distance and Cuisine are clusters of chips; Max price is a price field with Apply.
     @part filter-part  One part of the sheet.
     @part filter-hint  A line of help above a field, in muted text.
     @example <div class="filter-part"><p class="filter-hint">Dishes with no price or a higher price drop out.</p><div class="input-row"><input class="input" type="text" inputmode="decimal" aria-label="Max price"><button class="button primary" type="button">Apply</button></div></div> */
  .filter-part {
    min-width: 0;
  }

  .filter-hint {
    margin: var(--space-2) 0;
    color: var(--muted);
    font-size: var(--text-s);
  }

  /* @component place-list
     @scope explore
     @summary The cards of Explore, newest first. A card slides left to show Delete (item-row-swipe).
     @part place-card       One place: a rounded card on --surface.
     @part place-card-body  The card itself, which slides over its actions: the open button and the heart.
     @part place-card-open  The button that opens the detail: the tile and the text.
     @part place-card-text  The name, the cuisine and the area, the facts and the star dishes.
     @part place-card-name  The name of the place.
     @part place-card-meta  The cuisine and the area, in muted text.
     @part place-card-dishes  Up to two star dishes.
     @part place-card-dish  One star dish: a star and its name in a capsule.
     @state aria-current  On place-card-body: the place open in the detail, from 840px.
     @example <ul class="place-list" style="width: 100%"><li class="place-card"><div class="item-row-swipe"><div class="place-card-body"><button class="place-card-open" type="button"><span class="place-tile" data-wheel="3">🌮</span><span class="place-card-text"><span class="place-card-name">La Taquería del Sol</span><span class="place-card-meta">Mexicana · Chueca</span><span class="place-facts"><span>€€</span><span class="place-rating"><svg class="icon small" aria-hidden="true"><use href="icons.svg#star"/></svg><span>4</span></span></span><span class="place-card-dishes"><span class="place-card-dish"><svg class="icon small" aria-hidden="true"><use href="icons.svg#star"/></svg><span>Tacos de birria</span></span></span></span></button><button class="button icon place-fav" type="button" aria-pressed="true" aria-label="Favourite"><svg class="icon" aria-hidden="true"><use href="icons.svg#heart"/></svg></button></div></div></li></ul> */
  .place-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin: 0;
    padding: 0 var(--space-4) var(--space-4);
    list-style: none;
  }

  .place-card > .item-row-swipe {
    border: 1px solid var(--line);
    border-radius: var(--radius-l);
  }

  .place-card-body {
    display: flex;
    align-items: flex-start;
    gap: var(--space-1);
    padding: var(--space-3) var(--space-1) var(--space-3) var(--space-3);
    background: var(--surface);
    touch-action: pan-y;
    user-select: none;
    transition: transform var(--motion-fast) var(--ease), background var(--motion-fast);
  }

  .place-card-body.dragging {
    transition: none;
  }

  .place-card-body[aria-current="true"] {
    background: var(--secondary);
  }

  .place-card-open {
    flex: 1;
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    min-width: 0;
    padding: 0;
    border-radius: 0;
    text-align: left;
  }

  .place-card-text {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
  }

  .place-card-name {
    font-size: var(--text-h);
    font-weight: var(--weight-strong);
    overflow-wrap: anywhere;
  }

  .place-card-meta {
    color: var(--muted);
    font-size: var(--text-s);
  }

  .place-card-dishes {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    margin-top: var(--space-1);
  }

  .place-card-dish {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--surface-2);
    font-size: var(--text-xs);
  }

  .place-card-dish > .icon {
    color: var(--primary);
    fill: currentColor;
  }

  /* @component place-tile
     @scope explore
     @summary The emoji of the cuisine of a place on a soft tint of a wheel colour. The tile holds no text.
     @variant large  The tile of the detail head.
     @state data-wheel  1 to 4: the wheel colour, by the index of the cuisine (PLC-21).
     @example <span class="place-tile" data-wheel="1">🥘</span><span class="place-tile" data-wheel="2">🍣</span><span class="place-tile" data-wheel="3">🌮</span><span class="place-tile" data-wheel="4">🍝</span><span class="place-tile large" data-wheel="1">🍕</span> */
  .place-tile {
    flex: none;
    display: grid;
    place-items: center;
    width: var(--tap-l);
    height: var(--tap-l);
    border-radius: var(--radius-control);
    background: var(--tile-1);
    font-size: var(--text-l);
    line-height: 1;
  }

  .place-tile[data-wheel="2"] {
    background: var(--tile-2);
  }

  .place-tile[data-wheel="3"] {
    background: var(--tile-3);
  }

  .place-tile[data-wheel="4"] {
    background: var(--tile-4);
  }

  .place-tile.large {
    width: calc(var(--tap-l) * 1.5);
    height: calc(var(--tap-l) * 1.5);
    border-radius: var(--radius-l);
    font-size: var(--text-xl);
  }

  /* @component place-facts
     @scope explore
     @summary The tier of a place, its distance from a fresh fix when it has a location, then its own rating: a star and the number.
     @part place-rating  The rating, with its star in --primary.
     @example <p class="place-facts"><span>€€€</span><span class="place-rating"><svg class="icon small" aria-hidden="true"><use href="icons.svg#star"/></svg><span>5</span></span></p> */
  .place-facts {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin: 0;
    font-size: var(--text-s);
    font-weight: var(--weight-medium);
  }

  .place-rating {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
  }

  .place-rating > .icon {
    color: var(--primary);
    fill: currentColor;
  }

  /* @component place-fav
     @scope explore
     @summary The heart of a place, a button icon. A favourite has aria-pressed="true": a full heart in --primary.
     @example <button class="button icon place-fav" type="button" aria-pressed="false" aria-label="Favourite"><svg class="icon" aria-hidden="true"><use href="icons.svg#heart"/></svg></button><button class="button icon place-fav" type="button" aria-pressed="true" aria-label="Favourite"><svg class="icon" aria-hidden="true"><use href="icons.svg#heart"/></svg></button> */
  .place-fav[aria-pressed="true"] {
    color: var(--primary);
  }

  .place-fav[aria-pressed="true"] > .icon {
    fill: currentColor;
  }

  /* @component place-view
     @scope explore
     @summary The detail of a place in the pane: the head, the actions, the note and the dishes, star dishes first.
     @part place-head        The tile, the text and the heart.
     @part place-head-text   The name, the cuisine and the area, the facts.
     @part place-title       The name of the place.
     @part place-meta        The cuisine and the area.
     @part place-remark      The note of the place. Its line breaks stay.
     @part place-dishes-head The title above the dishes, and Add dish at its end.
     @part place-dishes-title  The title above the dishes.
     @part dish-list         The dishes. A deleted row closes before it leaves.
     @part dish-row          One dish, a rounded row on --surface.
     @part dish-row-open     The button that edits the dish: a star for a star dish, the text and the price.
     @part dish-row-text     The name, then the rating and the note.
     @part dish-row-name     The name of a dish.
     @part dish-row-meta     The rating and the note of a dish, in muted text.
     @part dish-row-note     The note of a dish, on one line.
     @part dish-row-price    The price of a dish, in --primary.
     @example <div class="place-view" style="width: 100%"><header class="place-head"><span class="place-tile large" data-wheel="3">🌮</span><div class="place-head-text"><h2 class="place-title">La Taquería del Sol</h2><p class="place-meta">Mexicana · Chueca</p><p class="place-facts"><span>€€</span></p></div></header><p class="place-remark">Ask for the terrace.</p><div class="place-dishes-head"><h3 class="place-dishes-title">Dishes</h3><button class="button outline" type="button">Add dish</button></div><ul class="dish-list"><li class="dish-row"><button class="dish-row-open" type="button"><svg class="icon small" role="img" aria-label="Star dish"><use href="icons.svg#star"/></svg><span class="dish-row-text"><span class="dish-row-name">Tacos de birria</span><span class="dish-row-meta"><span class="place-rating"><svg class="icon small" aria-hidden="true"><use href="icons.svg#star"/></svg><span>5</span></span><span class="dish-row-note">With extra consommé</span></span></span><span class="dish-row-price">14,50 €</span></button></li></ul></div> */
  .place-view {
    max-width: var(--content-max);
  }

  .place-head {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
  }

  .place-head-text {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
  }

  .place-title {
    margin: 0;
    font-size: var(--text-l);
    overflow-wrap: anywhere;
  }

  .place-meta {
    margin: 0;
    color: var(--muted);
  }

  .place-remark {
    margin: var(--space-3) 0;
    white-space: pre-line;
    overflow-wrap: anywhere;
  }

  .place-dishes-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin: var(--space-5) 0 var(--space-2);
  }

  .place-dishes-title {
    margin: 0;
    font-size: var(--text-h);
  }

  .dish-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
  }

  /* `collapse` in motion.js sets the height of a row that leaves. */
  .dish-list > .leaving,
  .place-list > .leaving {
    overflow: hidden;
    min-height: 0;
    opacity: 0;
    transition: height var(--motion) var(--ease), opacity var(--motion) var(--ease);
  }

  .dish-row {
    border: 1px solid var(--line);
    border-radius: var(--radius-l);
    background: var(--surface);
  }

  .dish-row-open {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    min-height: var(--tap);
    padding: var(--space-2) var(--space-4);
    border: 0;
    border-radius: inherit;
    background: none;
    color: inherit;
    font: inherit;
    text-align: start;
  }

  .dish-row-open > .icon {
    flex: none;
    color: var(--primary);
    fill: currentColor;
  }

  .dish-row-text {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
  }

  .dish-row-name {
    overflow-wrap: anywhere;
  }

  .dish-row-meta {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
    color: var(--muted);
    font-size: var(--text-s);
  }

  .dish-row-note {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .dish-row-price {
    flex: none;
    color: var(--primary);
    font-weight: var(--weight-strong);
  }

  /* @component place-form
     @scope place
     @summary The parts of the place sheet that a field does not cover: the cuisine select, the tier and the rating.
     @part place-group    A group of buttons with its name (a field-label legend) above it.
     @part tier-picker    The segmented of the four tiers, € to €€€€.
     @part rating-picker  Five star buttons. A tap on the current rating clears it.
     @part rating-star    One star, a button icon. The stars up to the rating have aria-pressed="true".
     @part place-location       The location group: the pair, Use my position and Clear, then the link and Apply.
     @part place-location-pair  The location as "lat, lng", or no location.
     @example <fieldset class="place-group" style="width: 100%"><legend class="field-label">Price per person</legend><div class="segmented tier-picker"><button class="segment" type="button" aria-pressed="false">€</button><button class="segment" type="button" aria-pressed="true">€€</button><button class="segment" type="button" aria-pressed="false">€€€</button><button class="segment" type="button" aria-pressed="false">€€€€</button></div></fieldset>
     @example <div class="rating-picker"><button class="button icon rating-star" type="button" aria-pressed="true" aria-label="1 star"><svg class="icon" aria-hidden="true"><use href="icons.svg#star"/></svg></button><button class="button icon rating-star" type="button" aria-pressed="false" aria-label="2 stars"><svg class="icon" aria-hidden="true"><use href="icons.svg#star"/></svg></button></div> */
  .place-group {
    min-width: 0;
    margin: var(--space-4) 0 0;
    padding: 0;
    border: 0;
  }

  .place-group > .field-label {
    display: block;
    padding: 0;
  }

  .tier-picker {
    margin: 0;
  }

  .tier-picker:has(> .segment:nth-child(4)) {
    --segment-count: 4;
  }

  .tier-picker:has(> .segment:nth-child(4)[aria-pressed="true"]) {
    --segment-index: 3;
  }

  .place-location-pair {
    margin: var(--space-2) 0 0;
    font-variant-numeric: tabular-nums;
  }

  .place-location > .cluster {
    margin: var(--space-2) 0;
  }

  .rating-picker {
    display: flex;
    gap: var(--space-1);
  }

  .rating-star[aria-pressed="true"] {
    color: var(--primary);
  }

  .rating-star[aria-pressed="true"] > .icon {
    fill: currentColor;
  }

  /* The select of a field draws the border of an input. */
  .select.field-input {
    min-height: var(--tap);
    border: 2px solid var(--control);
    border-radius: var(--radius-control);
  }

  .select.field-input:focus {
    border-color: var(--text);
  }

  /* A text area of a field grows with its rows. */
  .field-input:is(textarea) {
    height: auto;
    padding-block: var(--space-2);
    resize: vertical;
  }

  /* @component roulette
     @scope roulette
     @summary The Roulette section: the Places and Dishes switch, the filter row, then the stage with the wheel and the result card. One centred column; from 840px the wheel and the result stand side by side.
     @part roulette-mode   The Places and Dishes switch (segmented), at most --content-max wide.
     @part roulette-stage  The wheel and the result card. Hidden with no candidate, where the empty state shows.
     @part roulette-board  The title, the "N of M" count, the wheel and the hint. Hidden with one candidate.
     @part roulette-title  The question above the wheel.
     @part roulette-count  "12 of N": the count of the wheel when it shows a sample of the candidates.
     @part roulette-hint   The muted line under the wheel.
     @example <section class="roulette" style="width: 100%"><div class="segmented roulette-mode"><button class="segment" type="button" aria-pressed="true">Places</button><button class="segment" type="button" aria-pressed="false">Dishes</button></div><div class="roulette-stage"><div class="roulette-board"><h2 class="roulette-title">Where do we eat today?</h2><p class="roulette-count">12 of 15</p><p class="roulette-hint">Tap the centre to decide</p></div></div></section> */
  .roulette {
    width: 100%;
    max-width: var(--content-max);
    margin-inline: auto;
  }

  .roulette-mode {
    max-width: var(--content-max);
    margin: var(--space-3) var(--space-4);
  }

  .roulette-stage {
    display: grid;
    gap: var(--space-6);
    padding: 0 var(--space-4) var(--space-4);
  }

  .roulette-board {
    display: grid;
    justify-items: center;
    gap: var(--space-2);
    text-align: center;
  }

  .roulette-title {
    margin: 0;
    font-size: var(--text-h);
    font-weight: var(--weight-strong);
  }

  .roulette-count {
    margin: 0;
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-pill);
    background: var(--surface-2);
    font-size: var(--text-s);
    font-weight: var(--weight-medium);
  }

  .roulette-hint {
    margin: 0;
    color: var(--muted);
    font-size: var(--text-s);
  }

  @media (min-width: 840px) {
    .roulette {
      max-width: var(--roulette-max);
    }

    /* The switch and the chips stand centred over the wheel. */
    .roulette-mode {
      margin-inline: auto;
    }

    .roulette .filter-bar {
      justify-content: safe center;
    }

    .roulette-stage:has(> .roulette-result:not([hidden])) {
      grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
      align-items: center;
    }
  }

  /* @component wheel
     @scope roulette
     @summary The wheel of the roulette: a disc of up to 12 segments in the four wheel colours, the pointer at the top and the centre button that spins. It is at most --wheel-size wide.
     @part wheel-pointer    The arrow at the top, in --ink. The winner stops under it.
     @part wheel-disc       The disc that turns. Its segments are a conic gradient that the view writes, and it turns over SPIN_MS with an ease-out.
     @part wheel-label      The text of one segment, from the hub out to the rim, in the --on-wheel colour of its segment (4.5:1 or more).
     @part wheel-label-name The short name, cut with an ellipsis.
     @part wheel-label-emoji The emoji of the cuisine, at the rim.
     @part wheel-hub        The centre button, Spin: a round --primary button over the disc.
     @state data-wheel      On wheel-label: 1 to 4, the colour of its segment.
     @example <div class="wheel" style="width: 280px"><span class="wheel-pointer"></span><div class="wheel-disc" style="background-image: conic-gradient(var(--wheel-1) 0deg 90deg, var(--wheel-2) 90deg 180deg, var(--wheel-3) 180deg 270deg, var(--wheel-4) 270deg 360deg)"><span class="wheel-label" data-wheel="1" style="--at: 45deg"><span class="wheel-label-name">Casa Lucio</span><span class="wheel-label-emoji">🥘</span></span><span class="wheel-label" data-wheel="2" style="--at: 135deg"><span class="wheel-label-name">Sora Nikkei</span><span class="wheel-label-emoji">🍣</span></span><span class="wheel-label" data-wheel="3" style="--at: 225deg"><span class="wheel-label-name">Taquería</span><span class="wheel-label-emoji">🌮</span></span><span class="wheel-label" data-wheel="4" style="--at: 315deg"><span class="wheel-label-name">Trattoria</span><span class="wheel-label-emoji">🍝</span></span></div><button class="button wheel-hub" type="button"><svg class="icon" aria-hidden="true"><use href="icons.svg#wheel"/></svg><span>Spin</span></button></div> */
  .wheel {
    position: relative;
    width: min(100%, var(--wheel-size));
    aspect-ratio: 1;
    margin-top: var(--space-3);
  }

  .wheel-pointer {
    position: absolute;
    top: calc(-1 * var(--space-3));
    left: 50%;
    z-index: 1;
    width: var(--space-6);
    height: var(--space-7);
    background: var(--ink);
    clip-path: polygon(0 0, 100% 0, 50% 100%);
    transform: translateX(-50%);
  }

  .wheel-disc {
    position: absolute;
    inset: 0;
    overflow: hidden;
    border: var(--space-2) solid var(--surface);
    border-radius: var(--radius-round);
    box-shadow: var(--shadow-l);
    transition-property: transform;
    transition-timing-function: var(--spin-ease);
  }

  .wheel-label {
    position: absolute;
    top: 50%;
    left: 50%;
    display: flex;
    align-items: center;
    gap: var(--space-1);
    width: 50%;
    /* The text starts out of the hub and ends short of the rim. */
    padding: 0 3% 0 17%;
    color: var(--on-wheel-1);
    font-size: var(--text-s);
    font-weight: var(--weight-strong);
    line-height: 1.2;
    transform-origin: 0 50%;
    transform: translateY(-50%) rotate(calc(var(--at) - 90deg));
  }

  .wheel-label[data-wheel="2"] {
    color: var(--on-wheel-2);
  }

  .wheel-label[data-wheel="3"] {
    color: var(--on-wheel-3);
  }

  .wheel-label[data-wheel="4"] {
    color: var(--on-wheel-4);
  }

  .wheel-label-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-align: end;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .wheel-label-emoji {
    flex: none;
  }

  .wheel-hub {
    position: absolute;
    top: 50%;
    left: 50%;
    z-index: 1;
    flex-direction: column;
    gap: 0;
    width: 30%;
    min-width: var(--tap-l);
    aspect-ratio: 1;
    padding: 0;
    border: var(--space-1) solid var(--surface);
    border-radius: var(--radius-round);
    background: var(--primary);
    color: var(--on-primary);
    box-shadow: var(--shadow-l);
    font-weight: var(--weight-strong);
    transform: translate(-50%, -50%);
  }

  /* The hub stays solid while the wheel turns, so that the disc does not show through it. */
  .wheel-hub:disabled {
    opacity: 1;
  }

  /* @component roulette-result
     @scope roulette
     @summary The result card of the roulette: the cuisine tile, the name, for a dish its place and price, the cuisine and the area, the facts, then Let's go, Open and Spin again.
     @part roulette-result-kicker  The line above the result, in --primary.
     @part roulette-result-head    The tile, the texts and the price.
     @part roulette-result-text    The name, the place of a dish, the cuisine and the area, the facts.
     @part roulette-result-name    The name of the place or of the dish. It takes the focus after a spin.
     @part roulette-result-place   For a dish: the place where it is.
     @part roulette-result-meta    The cuisine and the area.
     @part roulette-result-price   For a dish with a price: the price, in --primary.
     @part roulette-result-more    Open and Spin again, side by side.
     @state aria-disabled  On Let's go: the place has no location, so there is no route.
     @example <article class="roulette-result" style="width: 100%"><p class="roulette-result-kicker">Decided!</p><div class="roulette-result-head"><span class="place-tile large" data-wheel="3">🌮</span><div class="roulette-result-text"><h3 class="roulette-result-name">Tacos de birria</h3><p class="roulette-result-place">At La Taquería del Sol</p><p class="roulette-result-meta">Mexican · Chueca</p><p class="place-facts"><span>€€</span><span>650 m</span></p></div><span class="roulette-result-price">€14.50</span></div><a class="button primary wide"><svg class="icon small" aria-hidden="true"><use href="icons.svg#route"/></svg><span>Let's go</span></a><div class="roulette-result-more"><button class="button tonal" type="button">Open</button><button class="button tonal" type="button"><svg class="icon small" aria-hidden="true"><use href="icons.svg#refresh"/></svg><span>Spin again</span></button></div></article> */
  .roulette-result {
    display: grid;
    gap: var(--space-4);
    padding: var(--space-5);
    border-radius: var(--radius-card);
    background: var(--surface);
    box-shadow: var(--shadow-l);
  }

  .roulette-result-kicker {
    margin: 0;
    color: var(--primary);
    font-weight: var(--weight-strong);
  }

  .roulette-result-head {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
  }

  .roulette-result-text {
    flex: 1;
    min-width: 0;
    display: grid;
    gap: var(--space-1);
  }

  .roulette-result-name {
    margin: 0;
    font-size: var(--text-h);
    font-weight: var(--weight-strong);
    overflow-wrap: anywhere;
  }

  .roulette-result-place,
  .roulette-result-meta {
    margin: 0;
    color: var(--muted);
  }

  .roulette-result-price {
    flex: none;
    color: var(--primary);
    font-weight: var(--weight-strong);
  }

  .roulette-result > .button[aria-disabled="true"] {
    opacity: 0.4;
    cursor: default;
    pointer-events: none;
  }

  .roulette-result-more {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
  }

  .roulette-result-more > .button {
    flex: 1 1 auto;
    white-space: nowrap;
  }

  /* @component version-status
     @scope settings
     @summary The state of the installed version: a sign, and a text for the outdated state only.
     @part version-status-text  The text of the state. With a sign it stays for screen readers only.
     @example <span class="version-status" data-status="current" role="status"><svg data-for="current" class="icon small" aria-hidden="true"><use href="icons.svg#check-circle"/></svg><span class="version-status-text">Up to date</span></span> */
  .version-status {
    display: flex;
    align-items: center;
    gap: var(--space-1);
  }

  .version-status [data-for] {
    display: none;
  }

  .version-status[data-status='checking'] [data-for='checking'],
  .version-status[data-status='current'] [data-for='current'],
  .version-status[data-status='outdated'] [data-for='outdated'],
  .version-status[data-status='unknown'] [data-for='unknown'] {
    display: block;
  }

  .version-status[data-status='checking'] .icon {
    animation: spin var(--motion-slow) linear infinite;
  }

  .version-status[data-status='current'] {
    color: var(--done);
  }

  .version-status[data-status='outdated'] {
    flex-basis: 100%;
    justify-content: center;
    color: var(--warning);
  }

  .version-status[data-status='unknown'] {
    color: var(--danger);
  }

  .version-status:not([data-status='outdated']) .version-status-text {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  @keyframes spin {
    to {
      transform: rotate(1turn);
    }
  }

  /* @component settings
     @scope settings
     @summary The Settings section: groups of settings rows (list-group) under a list-group-head, then the about lines. One centred column from 600px. A row of Preferences holds a real select laid over it, so a tap opens the native picker.
     @example <section class="settings" style="width: 100%"><h2 class="list-group-head">Preferences</h2><div class="list-group"><div class="settings-row"><span class="settings-row-label">Language</span><span class="settings-row-value">English</span><span class="chevron" aria-hidden="true">›</span><select class="select" aria-label="Language"><option>English</option></select></div></div></section> */
  .settings {
    width: 100%;
    max-width: var(--content-max);
    margin-inline: auto;
  }

  /* @extends list-group */
  .settings .settings-row {
    position: relative;
  }

  /* The select is invisible: the row shows the ring when the select has the keyboard focus. */
  .settings .settings-row:has(> .select:focus-visible) {
    outline: 2px solid var(--text);
    outline-offset: -2px;
  }

  .settings .settings-row > .select {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
  }

  /* @component whatsnew
     @scope whatsnew
     @summary The release notes in a sheet: one block for each version, newest first.
     @part whatsnew-body     The body of the sheet, with the blocks.
     @part whatsnew-entry    One version: its line and its notes.
     @part whatsnew-version  The version and its day.
     @part whatsnew-notes    The notes of a version, as a list.
     @example <section class="whatsnew-entry"><h3 class="whatsnew-version">Version 1.2.0 · 20 October 2026</h3><ul class="whatsnew-notes"><li>A new menu.</li></ul></section> */
  .whatsnew-body {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
  }

  .whatsnew-version {
    margin: 0 0 var(--space-2);
    color: var(--muted);
    font-size: var(--text-xs);
    font-weight: 600;
  }

  .whatsnew-notes {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin: 0;
    padding-left: var(--space-5);
  }

  /* @component about
     @scope settings
     @summary The version lines at the end of Settings.
     @part about-line  One line: the version and its state.
     @example <footer class="about"><p class="about-line"><span>Version 0.1.0</span></p></footer> */
  .about {
    margin: var(--space-6) var(--space-3) 0;
    color: var(--muted);
    font-size: var(--text-xs);
    text-align: center;
  }

  .about-line {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: var(--space-1) var(--space-2);
    margin: 0;
  }

  /* @component dust
     @scope nav
     @summary The canvas of the dust effect of a nav item that goes away or comes back.
     @example <p>The dust canvas is drawn by dust.js; it has no example of its own.</p> */
  .dust {
    position: fixed;
    z-index: 40;
    pointer-events: none;
  }

  /* @component onboarding
     @scope onboarding
     @summary The walkthrough of the first start, over the full app: a page, the dots, the buttons.
     @part onboarding-logo     The app icon, in the middle of the band above the page. It stays while the pages change.
     @part onboarding-page     The page in view: its drawing, its title and its text.
     @part onboarding-title    The title of a page.
     @part onboarding-text     The text of a page.
     @part onboarding-key      A control named in a text, such as ↻ or +: a key with a border, as inline code.
     @part onboarding-dots     One dot for each page.
     @part onboarding-dot      One dot.
     @part onboarding-actions  Saltar and the next button, side by side. On the last page the next button fills the bar.
     @part onboarding-switch   The switch of the sample data on the last page. It keeps its room on each page.
     @state away               On onboarding-switch: a page with no switch. The room stays, so nothing moves.
     @state on                 On onboarding-dot: the page in view.
     @state enter-next         On onboarding-page: it comes in from the right.
     @state enter-previous     On onboarding-page: it comes in from the left.
     @example <div class="onboarding-actions" style="width: 100%"><button class="button outline quiet" type="button">Skip</button><button class="button primary" type="button">Next</button></div>
     @example <div class="onboarding-dots"><span class="onboarding-dot on"></span><span class="onboarding-dot"></span><span class="onboarding-dot"></span></div> */
  .onboarding {
    position: fixed;
    inset: 0;
    z-index: 30;
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    padding: calc(var(--space-5) + env(safe-area-inset-top)) calc(var(--space-5) + env(safe-area-inset-right))
      calc(var(--space-5) + env(safe-area-inset-bottom)) calc(var(--space-5) + env(safe-area-inset-left));
    background: var(--bg);
    /* A horizontal slide changes the page, so the browser must not take it. */
    touch-action: pan-y;
    overflow: hidden auto;
  }

  /* The free space of the layer is three equal margins: above the logo, below it and below the
     page. The logo thus sits in the middle of the band above the drawing. */
  .onboarding-logo {
    flex: none;
    align-self: center;
    margin-block: auto;
    width: var(--logo);
    height: var(--logo);
  }

  .onboarding-page {
    display: flex;
    flex: none;
    margin-bottom: auto;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-6);
    text-align: center;
  }

  .onboarding-page.enter-next,
  .onboarding-page.enter-previous {
    animation: enter var(--motion) ease-out;
  }

  .onboarding-page.enter-next {
    --enter-from: 48px;
  }

  .onboarding-page.enter-previous {
    --enter-from: -48px;
  }

  /* A title can take two lines in some catalogs. It keeps the room of two, with its last line
     next to the text, so the drawing does not move. */
  .onboarding-title {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    min-height: 2lh;
    margin: 0 0 var(--space-2);
    font-size: var(--text-l);
  }

  /* The longest text of a page, in any catalog, is five lines at 32ch. The text keeps room for
     five, so each page has the same height and the drawing and the logo do not move. */
  .onboarding-text {
    max-width: 32ch;
    /* A line break of a catalog text starts a new line. */
    white-space: pre-line;
    min-height: 5lh;
    margin: 0;
    color: var(--muted);
  }

  .onboarding-switch {
    align-self: stretch;
    border-radius: var(--radius-l);
    background: var(--surface);
  }

  .onboarding-switch.away {
    visibility: hidden;
  }

  .onboarding-key {
    padding: 0 var(--space-1);
    border: 1px solid var(--line);
    border-radius: var(--radius-s);
    background: var(--surface);
    color: var(--text);
    font-family: var(--font-mono);
    white-space: nowrap;
  }

  /* The icon of a key sits on the line of the text, with a small gap before its text. */
  .onboarding-key > .icon {
    display: inline-block;
    width: 1em;
    height: 1em;
    margin-right: var(--space-1);
    vertical-align: -0.2em;
  }

  .onboarding-key > .icon:only-child {
    margin-right: 0;
  }

  .onboarding-dots {
    display: flex;
    flex: none;
    justify-content: center;
    gap: var(--space-2);
  }

  .onboarding-dot {
    width: var(--space-2);
    height: var(--space-2);
    border-radius: var(--radius-round);
    background: var(--line);
  }

  .onboarding-dot.on {
    background: var(--ink);
  }

  /* Saltar sits beside the next button, on the side away from the thumb. */
  .onboarding-actions {
    display: flex;
    flex: none;
    gap: var(--space-2);
  }

  .onboarding-actions > .button {
    flex: 1 1 50%;
  }

  [data-hand="left"] .onboarding-actions {
    flex-direction: row-reverse;
  }

  /* @component onboarding-art
     @scope onboarding
     @summary The line drawing of a walkthrough page, inline in the page. Its shapes take these parts.
     @part art-card     A card shape, filled with --surface.
     @part art-accent   A --primary stroke.
     @part art-soft     A --done-soft fill with a --primary stroke.
     @part art-solid    A solid --primary fill.
     @part art-on-solid A stroke on a solid fill.
     @example <div class="onboarding-art"><svg viewBox="0 0 240 160" aria-hidden="true"><rect class="art-card art-accent" x="20" y="20" width="90" height="120" rx="10"/><circle class="art-solid" cx="160" cy="80" r="13"/><path class="art-on-solid" d="M160 74v12M154 80h12"/></svg></div> */
  .onboarding-art > svg {
    display: block;
    width: min(var(--art-width), 70vw);
    height: auto;
    fill: none;
    stroke: var(--muted);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
  }

  .art-card {
    fill: var(--surface);
  }

  .art-accent {
    stroke: var(--primary);
  }

  .art-soft {
    fill: var(--done-soft);
    stroke: var(--primary);
  }

  .art-solid {
    fill: var(--primary);
    stroke: none;
  }

  .art-on-solid {
    stroke: var(--on-primary);
  }

  /* @component account
     @scope account
     @summary The screens of the account over the full app (ACC-2): Sign in and Waiting for approval.
       One page shows at a time, in the width of the column, centred. Over the walkthrough.
     @part account-page    One screen.
     @part account-logo    The app icon, at the top of Sign in.
     @part account-title   The name of the screen.
     @part account-text    The line below the title.
     @part account-wait    The large icon of Waiting for approval.
     @example <div class="account-page" style="width: 100%"><h2 class="account-title">Iniciar sesión</h2><p class="account-text">El administrador aprueba cada cuenta nueva.</p><button class="button tonal wide" type="button"><svg class="icon small" aria-hidden="true"><use href="icons.svg#google"/></svg>Continuar con Google</button></div> */
  .account {
    position: fixed;
    inset: 0;
    /* Over the walkthrough and the dust: the sign-in of a first start comes first. */
    z-index: 50;
    display: flex;
    flex-direction: column;
    padding: calc(var(--space-5) + env(safe-area-inset-top)) calc(var(--space-5) + env(safe-area-inset-right))
      calc(var(--space-5) + env(safe-area-inset-bottom)) calc(var(--space-5) + env(safe-area-inset-left));
    background: var(--bg);
    overflow: hidden auto;
  }

  @media (min-width: 600px) {
    .account {
      padding-left: max(var(--space-5) + env(safe-area-inset-left), (100% - var(--content-max)) / 2);
      padding-right: max(var(--space-5) + env(safe-area-inset-right), (100% - var(--content-max)) / 2);
    }
  }

  .account-page {
    display: flex;
    flex: 1 0 auto;
    flex-direction: column;
    justify-content: center;
    gap: var(--space-3);
  }

  .account-logo {
    align-self: center;
    width: var(--logo);
    height: var(--logo);
  }

  .account-title {
    margin: 0;
    font-size: var(--text-l);
    text-align: center;
  }

  .account-title:focus {
    outline: none;
  }

  .account-text {
    margin: 0 0 var(--space-2);
    color: var(--muted);
    text-align: center;
  }

  .account-wait {
    align-self: center;
    width: var(--logo);
    height: var(--logo);
    color: var(--muted);
  }

  .account-page > .button.accent {
    align-self: center;
  }
}
