/* The restaurant theme, as rules.

   Everything here reads from custom properties and declares no colour of its own. The properties
   are written by RestaurantThemeScope as an inline style on the wrapper — which means they are
   present in the server-rendered HTML, before any script runs, and a themed page never flashes
   platform colours on its way to brand ones.

   The consequence worth knowing when writing pages: a page placed inside the scope is themed
   because it uses MudBlazor components and these selectors reach them. It does not need to know a
   theme exists, and it must not hard-code a colour — a hex in a page is a colour that stops
   following the restaurant. Reach for a token or one of the .rt-* classes at the bottom instead.

   Loaded via an @import in app.css, which every host already links; there is no per-host wiring to
   forget. The rules are inert until a .restaurant-theme wrapper exists. */

/* Defaults for every token — the design's own reference theme, tour 6.

   Cream paper, near-black ink, burgundy brand, brass accent. This is what a carte looks like before
   any restaurant has published colours of its own, because it is what the design's client screens
   look like: warm, printed, a menu rather than a dashboard. The hub keeps Industry's steel — that
   is the platform's identity, and a diner reading a carte is not on the platform, they are in a
   restaurant.

   Without these a carte rendered outside a restaurant's app — the manager's preview, a listing with
   no theme yet — would read `var(--pap)` and get nothing. The tokens always resolve; a restaurant
   theme is an override on the wrapper, not the only source. That is also what lets the .rt-* classes
   below be used anywhere in the product rather than only inside the white-label shell. */
:root {
    --pap: #F6F1E7;
    --ink: #241C16;
    --surf: #F1E9DA;
    --field: #FBF7EF;
    --line: rgba(36, 28, 22, .16);
    --chip: rgba(36, 28, 22, .35);
    --mut: rgba(36, 28, 22, .82);
    --faint: rgba(36, 28, 22, .5);
    --bt: #7B2D26;
    --gold: #C9A227;
    /* The brass as text. Brass is a rule-and-leaf colour: #C9A227 on this paper is 2.2:1, so its
       text form is walked down its own lightness axis until it clears 4.5:1. Restated here only so
       the static defaults answer the same questions the derived ones do. */
    --gold-text: #6B5200;
    --brand: #7B2D26;
    --on-brand: #F6F1E7;
    --price: #7B2D26;
    --allergen: #241C16;

    /* Square, per the handoff: 0–2px everywhere except a snack theme, which sets its own. */
    --rt-radius: 2px;
    --rt-scale: 1;
    --rt-row-pad: 13px;
    --rt-font-display: 'Playfair Display', Georgia, serif;
    --rt-font-body: 'Barlow', system-ui, sans-serif;
}

.restaurant-theme {
    background-color: var(--pap);
    color: var(--ink);
    font-family: var(--rt-font-body);
    font-size: calc(15px * var(--rt-scale, 1));
    line-height: 1.5;
}

/* ── Type ─────────────────────────────────────────────────────────────────────
   Two families, and the split is the handoff's: the display face carries names,
   prices and buttons — the things a diner scans — while descriptions and labels
   stay on the body face, which reads better small. */

.restaurant-theme h1, .restaurant-theme h2, .restaurant-theme h3,
.restaurant-theme h4, .restaurant-theme h5, .restaurant-theme h6,
.restaurant-theme .mud-typography-h1, .restaurant-theme .mud-typography-h2,
.restaurant-theme .mud-typography-h3, .restaurant-theme .mud-typography-h4,
.restaurant-theme .mud-typography-h5, .restaurant-theme .mud-typography-h6,
.restaurant-theme .mud-typography-subtitle1, .restaurant-theme .mud-typography-subtitle2 {
    font-family: var(--rt-font-display);
    font-weight: 700;
    line-height: 1.12;
    color: var(--ink);
}

.restaurant-theme .mud-typography-body1,
.restaurant-theme .mud-typography-body2,
.restaurant-theme p {
    font-family: var(--rt-font-body);
    color: var(--ink);
}

.restaurant-theme .mud-typography-caption,
.restaurant-theme .rt-muted {
    color: var(--mut);
}

/* ── Surfaces ─────────────────────────────────────────────────────────────── */

.restaurant-theme .mud-paper,
.restaurant-theme .mud-card {
    background-color: var(--surf);
    color: var(--ink);
    border-radius: var(--rt-radius);
    background-image: none;
}

.restaurant-theme .mud-paper-outlined,
.restaurant-theme .mud-card-outlined {
    border: 1px solid var(--line);
}

/* Flat is the default elevation: the handoff's objects are line drawings, and a drop shadow under
   every card turns a carte into a stack of receipts. A theme opting into "raised" gets it back. */
.restaurant-theme[data-elevation="flat"] .mud-elevation-1,
.restaurant-theme[data-elevation="flat"] .mud-elevation-2,
.restaurant-theme[data-elevation="flat"] .mud-elevation-3,
.restaurant-theme[data-elevation="flat"] .mud-elevation-4 {
    box-shadow: none;
    border: 1px solid var(--line);
}

.restaurant-theme .mud-divider {
    border-color: var(--line);
}

/* ── Controls ─────────────────────────────────────────────────────────────── */

.restaurant-theme .mud-button-root {
    font-family: var(--rt-font-display);
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    border-radius: var(--rt-radius);
    /* The handoff's mobile target floor. A carte is used one-handed, standing, in a dim room. */
    min-height: 44px;
}

.restaurant-theme .mud-button-filled-primary {
    background-color: var(--brand);
    color: var(--on-brand);
}

.restaurant-theme .mud-button-text-primary,
.restaurant-theme .mud-button-outlined-primary {
    color: var(--bt);
}

.restaurant-theme .mud-button-outlined-primary {
    border-color: var(--chip);
}

.restaurant-theme .mud-icon-button {
    color: var(--bt);
    min-height: 44px;
    min-width: 44px;
}

.restaurant-theme .mud-chip {
    background-color: transparent;
    border: 1px solid var(--chip);
    color: var(--ink);
    border-radius: var(--rt-radius);
}

.restaurant-theme .mud-chip.mud-chip-color-primary,
.restaurant-theme .mud-chip-filled.mud-chip-color-primary {
    background-color: var(--brand);
    border-color: var(--brand);
    color: var(--on-brand);
}

.restaurant-theme .mud-input-root,
.restaurant-theme .mud-input-slot {
    background-color: var(--field);
    color: var(--ink);
    border-radius: var(--rt-radius);
}

.restaurant-theme .mud-input-label,
.restaurant-theme .mud-input-helper-text {
    color: var(--mut);
}

.restaurant-theme .mud-input-outlined-border {
    border-color: var(--chip);
}

.restaurant-theme .mud-checkbox .mud-icon-root,
.restaurant-theme .mud-radio .mud-icon-root {
    color: var(--chip);
}

.restaurant-theme .mud-checkbox.mud-checked .mud-icon-root,
.restaurant-theme .mud-radio.mud-checked .mud-icon-root {
    color: var(--brand);
}

.restaurant-theme a:not(.mud-button-root):not(.mud-nav-link) {
    color: var(--bt);
    text-underline-offset: 3px;
}

.restaurant-theme .mud-progress-linear-bar {
    background-color: var(--brand);
}

/* Keyboard focus is the theme's accent, never the browser's blue ring. */
.restaurant-theme :focus-visible {
    outline: 2px solid var(--bt);
    outline-offset: 2px;
}

/* ── Semantic classes for bespoke markup ──────────────────────────────────────
   Where a page needs its own element rather than a MudBlazor one, these carry the
   same guarantees so it still follows the theme. */

.rt-brand-fill {
    background-color: var(--brand);
    color: var(--on-brand);
}

.rt-brand-fill .rt-label,
.rt-brand-fill .rt-overline {
    color: var(--gold);
}

/* A price is scanned down a right-hand column, so it never wraps and its figures are tabular —
   proportional digits make a column of prices visibly ragged. */
/* Le prix plein reste lisible, barré : une remise appliquée sans dire d'où elle vient
   ressemble à une erreur de prix — c'est-à-dire à quelque chose qu'on vient contester. */
.rt-was { opacity: .5; margin-right: 6px; font-weight: 400; }
.rt-now { color: var(--gold, #b8860b); font-weight: 700; }

/* « prix sur demande » — un plat que ni la carte ni la caisse n'ont tarifé.
   En italique, plus discret et sans chasse fixe : ce n'est pas un montant, et l'aligner
   sur la colonne des prix le ferait lire comme un nombre qu'on n'arrive pas à déchiffrer. */
.rt-unpriced {
    font-style: italic;
    font-weight: 400;
    opacity: .65;
    font-variant-numeric: normal;
}

.rt-price {
    font-family: var(--rt-font-display);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--price);
    white-space: nowrap;
    flex: none;
}

/* 20 px et non 18 : demandé le 2026-09-12, « le menu pourrait être affiché plus grand pour occuper
   plus de place dans l'écran ». C'est le nom du plat — la ligne qu'on lit en premier et parfois la
   seule — et deux points de plus la font passer de « lisible » à « lue de loin », ce qui est le cas
   d'usage réel : un téléphone posé sur une table, pas tenu devant les yeux.

   La description suit d'un point pour garder l'écart entre les deux : la hiérarchie vient du rapport
   des tailles, et monter le titre seul l'aurait creusé. */
.rt-dish-name {
    font-family: var(--rt-font-display);
    font-weight: 700;
    font-size: calc(20px * var(--rt-scale, 1));
    line-height: 1.25;
    color: var(--ink);
}

/* A dish description is content, not chrome.

   It was printed at the secondary-text weight, which is the right strength for a caption and the
   wrong one for the sentence somebody reads to decide what to eat. Full ink, one step down in size
   — the hierarchy comes from the type, not from fading the words. */
.rt-desc {
    font-family: var(--rt-font-body);
    font-size: calc(14px * var(--rt-scale, 1));
    line-height: 1.5;
    color: var(--ink);
}

/* Allergens are ink and never brand-coloured, never below 12px: this is the one line on a carte
   that someone may need for a medical reason, and it is not available for decoration. */
.rt-allergen {
    font-family: var(--rt-font-body);
    font-size: max(12px, calc(11px * var(--rt-scale, 1)));
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--allergen);
    border: 1px solid var(--chip);
    border-radius: var(--rt-radius);
    padding: 1px 6px;
    display: inline-block;
}

.rt-label, .rt-overline {
    font-family: var(--rt-font-body);
    font-size: calc(11px * var(--rt-scale, 1));
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--mut);
}

.rt-hairline {
    border: 0;
    border-top: 1px solid var(--line);
    margin: 0;
}

/* A dish row: text that may shrink, a price that may not. Without min-width:0 the text block
   cannot go below its longest unbroken word and pushes the price off the right edge. */
.rt-row {
    display: flex;
    align-items: baseline;
    gap: 12px;
    padding: var(--rt-row-pad) 0;
    border-bottom: 1px solid var(--line);
}

.rt-row > .rt-row-text {
    min-width: 0;
    overflow-wrap: anywhere;
    flex: 1 1 auto;
}

/* The tick on a choice row. accent-color is what makes it the restaurant's colour instead of the
   browser's blue — one property, and it keeps the native control's own focus ring and hit area,
   which a re-drawn box loses. align-self because .rt-row aligns on the baseline and a checkbox
   has none, so it would otherwise hang below the text it belongs to. */
/* The sheet of table codes, on paper.

   A code that lands half on one page and half on the next is a code nobody can scan, so each block
   is kept whole. Black on white regardless of the theme: this is going through a printer, and a
   cream background costs ink and contrast for nothing. */
@media print {
    .qr-block {
        break-inside: avoid;
        page-break-inside: avoid;
        padding: 8px 0 16px;
    }

    .qr-block svg {
        width: 100%;
        height: auto;
    }

    .qr-label {
        color: #000;
    }
}

.rt-choice {
    accent-color: var(--brand);
    align-self: center;
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    margin: 0;
    cursor: pointer;
}

/* Sold out stays legible: struck through and dimmed, never removed mid-read. */
.rt-soldout {
    opacity: .5;
}

.rt-soldout .rt-dish-name {
    text-decoration: line-through;
}

/* ── The carte ────────────────────────────────────────────────────────────────
   The list rendering: no photographs, and none missed. A printed carte has been
   setting names against prices with a rule of dots for a century, and it fits
   six or seven dishes on a phone screen where a thumbnail grid fits four. */

.rt-carte-header {
    background-color: var(--brand);
    color: var(--on-brand);
    padding: 14px 20px 16px;
}

.rt-carte-header .rt-carte-name {
    font-family: var(--rt-font-display);
    font-weight: 700;
    font-size: calc(21px * var(--rt-scale, 1));
    line-height: 1.05;
    margin: 0;
}

.rt-carte-header .rt-label {
    color: var(--gold);
}

.rt-carte-logo {
    width: 38px;
    height: 38px;
    flex: none;
    border: 1px solid var(--gold);
    border-radius: var(--rt-radius);
    object-fit: cover;
    background: transparent;
}

/* A restaurant with no uploaded logo gets its initials rather than an empty frame. */
.rt-monogram {
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--rt-font-display);
    font-weight: 700;
    font-size: 17px;
    letter-spacing: .04em;
    color: var(--gold);
}

/* Category pills. Sticky under the header, and the active one is tracked by scroll position rather
   than by the last tap: someone who scrolls past three sections should see the pills follow them. */
.rt-cats {
    position: sticky;
    top: 0;
    z-index: 3;
    display: flex;
    gap: 8px;
    overflow-x: auto;
    scrollbar-width: none;
    padding: 8px 20px;
    background-color: var(--pap);
    border-bottom: 1px solid var(--line);
}

.rt-cats::-webkit-scrollbar {
    display: none;
}

.rt-cat {
    flex: none;
    font-family: var(--rt-font-display);
    font-weight: 700;
    font-size: 12.5px;
    letter-spacing: .08em;
    text-transform: uppercase;
    padding: 6px 12px;
    border: 1px solid var(--chip);
    border-radius: var(--rt-radius);
    background: transparent;
    color: var(--ink);
    cursor: pointer;
    /* The pill is 32px tall but the tap target is not: a carte is read one-handed while sitting down. */
    min-height: 44px;
    display: inline-flex;
    align-items: center;
}

.rt-cat.rt-cat-active {
    background-color: var(--bt);
    border-color: var(--bt);
    color: var(--pap);
}

.rt-section {
    padding: 0 20px;
    /* Anchored scrolling has to clear the sticky pill row, or a tapped section lands under it. */
    scroll-margin-top: 64px;
}

.rt-section-title {
    font-family: var(--rt-font-display);
    font-weight: 700;
    font-size: calc(24px * var(--rt-scale, 1));
    line-height: 1.1;
    margin: 22px 0 2px;
    color: var(--ink);
}

/* The rule of dots between a dish and its price. Drawn on a filler span that takes the slack, so it
   stretches with the row instead of being a fixed string of periods that wraps on a narrow screen. */
.rt-leader {
    flex: 1 1 auto;
    min-width: 12px;
    border-bottom: 1px dotted var(--chip);
    transform: translateY(-4px);
}

.rt-dish {
    display: flex;
    align-items: baseline;
    gap: 8px;
    width: 100%;
    padding: var(--rt-row-pad) 0;
    border-bottom: 1px solid var(--line);
    background: transparent;
    border-left: 0;
    border-right: 0;
    border-top: 0;
    text-align: left;
    cursor: pointer;
    color: inherit;
    font: inherit;
}

.rt-dish-main {
    min-width: 0;
    overflow-wrap: anywhere;
    flex: 0 1 auto;
}

.rt-dish-extra {
    padding: 0 0 12px;
    border-bottom: 1px solid var(--line);
}

/* The last row in a section drops its rule: a hairline directly above a section title reads as a
   mistake rather than as a separator. */
.rt-section > :last-child > .rt-dish:last-child,
.rt-section > :last-child > .rt-dish-extra:last-child {
    border-bottom: 0;
}

/* Thumbnail layout. The frame is the same 76px whether or not there is a picture: a dish without one
   gets a dotted outline and the monogram, so a single missing photograph does not break the rhythm
   of the column the eye is scanning down. */
.rt-dish-thumb {
    align-items: center;
    gap: 13px;
}

/* 96 et non 76 : demandé le 2026-09-12, « les images quand disponible devraient être plus grandes ».
   Une vignette de 76 px sur un téléphone moderne montre une assiette de la taille d'une pièce de
   monnaie — assez pour savoir qu'il y a une photo, pas assez pour reconnaître le plat, ce qui est
   pourtant la seule raison de la mettre. Le cadre reste carré et identique avec ou sans photo, donc
   le rythme de la colonne que l'œil descend ne bouge pas. */
.rt-thumb {
    width: 96px;
    height: 96px;
    flex: none;
    object-fit: cover;
    border: 1px solid var(--line);
    border-radius: var(--rt-radius);
    background-color: var(--surf);
}

.rt-thumb-empty {
    border-style: dotted;
    border-color: var(--chip);
    font-size: 21px;
    opacity: .32;
}

/* Hero layout. The gradient is not decoration: it is what guarantees the name and price stay legible
   over a photograph nobody vetted — a bright plate under white text is otherwise unreadable. */
.rt-dish-hero {
    display: block;
    position: relative;
    width: 100%;
    padding: 0;
    margin-bottom: 14px;
    border: 1px solid var(--line);
    border-radius: var(--rt-radius);
    overflow: hidden;
    background: transparent;
    cursor: pointer;
    color: inherit;
    font: inherit;
}

/* Une hauteur qui suit l'écran plutôt qu'un nombre fixe. 184 px étaient une bande sur un téléphone
   tenu à la verticale et une timbre-poste sur un écran large ; `clamp` donne une image qui occupe à
   peu près la moitié de la largeur disponible, bornée pour qu'un moniteur de bureau ne serve pas une
   photographie d'un demi-mètre. Demandé le 2026-09-12 avec la vignette. */
.rt-dish-hero img {
    display: block;
    width: 100%;
    height: clamp(200px, 46vw, 340px);
    object-fit: cover;
}

.rt-dish-hero-caption {
    position: absolute;
    inset: auto 0 0 0;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 28px 14px 12px;
    background: linear-gradient(180deg, transparent 38%, rgba(36, 28, 22, .86));
    text-align: left;
}

/* Category band. Four photographs dress a whole carte instead of forty uneven ones. */
.rt-cat-banner {
    position: relative;
    height: 112px;
    margin: 22px 0 2px;
    border: 1px solid var(--line);
    border-radius: var(--rt-radius);
    overflow: hidden;
}

.rt-cat-banner img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.rt-cat-banner-name {
    position: absolute;
    left: 12px;
    bottom: 8px;
    font-family: var(--rt-font-display);
    font-weight: 700;
    font-size: calc(24px * var(--rt-scale, 1));
    color: var(--pap);
}

.rt-cat-banner-count {
    position: absolute;
    right: 12px;
    bottom: 12px;
    font-family: var(--rt-font-body);
    font-size: 11px;
    letter-spacing: .14em;
    color: var(--gold);
}

.rt-cat-banner::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, transparent 40%, rgba(36, 28, 22, .82));
    pointer-events: none;
}

.rt-cat-banner-name,
.rt-cat-banner-count {
    z-index: 1;
}

.rt-carte-footer {
    background-color: var(--surf);
    border-top: 1px solid var(--line);
    padding: 11px 20px 24px;
}

/* The count on the order button. Sits on the brass so it reads against the brand fill without
   borrowing the price colour, which means something else. */
.rt-order-badge {
    position: absolute;
    top: -4px;
    right: -4px;
    min-width: 18px;
    height: 18px;
    padding: 0 4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background-color: var(--gold);
    color: var(--ink);
    border-radius: 9px;
    font-family: var(--rt-font-display);
    font-weight: 700;
    font-size: 11.5px;
    line-height: 1;
    pointer-events: none;
}

/* ── The order panel ──────────────────────────────────────────────────────── */

.rt-scrim {
    position: fixed;
    inset: 0;
    z-index: 1400;
    background: rgba(36, 28, 22, .5);
    opacity: 0;
    visibility: hidden;
    transition: opacity .3s ease, visibility .3s;
}

.rt-scrim-on {
    opacity: 1;
    visibility: visible;
}

.rt-panel {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 1401;
    width: min(322px, 100vw);
    background-color: var(--pap);
    border-left: 1px solid var(--line);
    box-shadow: -14px 0 34px rgba(36, 28, 22, .22);
    transform: translateX(100%);
    transition: transform .38s cubic-bezier(.22, .9, .24, 1);
}

.rt-panel-on {
    transform: translateX(0);
}

@media (prefers-reduced-motion: reduce) {
    .rt-panel {
        transition: transform .01s linear;
    }
}

/* ── QR landing ───────────────────────────────────────────────────────────────
   The brand block that covers the screen while the carte loads. Fixed rather than
   in flow: it has to cover the app bar too, or the sequence ends with the
   platform's chrome sitting above the restaurant's own colours. */

.rt-qr {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: grid;
    place-items: center;
    background-color: var(--rt-qr-fill);
    color: var(--rt-qr-on);
    transition: opacity .45s ease, transform .6s cubic-bezier(.22, .9, .24, 1);
}

.rt-qr-in {
    opacity: 1;
    transform: scale(1);
}

.rt-qr-out {
    opacity: 0;
    /* Pulling away rather than fading flat: the block reads as lifting off the carte underneath. */
    transform: scale(1.12);
}

.rt-qr-gone {
    display: none;
}

.rt-qr-brand {
    text-align: center;
    padding: 24px;
}

.rt-qr-logo {
    width: 82px;
    height: 82px;
    margin: 0 auto 14px;
    display: block;
    border: 1px solid var(--gold);
    border-radius: var(--rt-radius);
    object-fit: cover;
}

.rt-qr-logo.rt-monogram {
    font-size: 34px;
    color: var(--rt-qr-on);
}

.rt-qr-name {
    font-family: var(--rt-font-display);
    font-weight: 700;
    font-size: 30px;
    line-height: 1.05;
}

.rt-qr-welcome {
    margin-top: 8px;
    color: var(--rt-qr-on);
    opacity: .75;
}

/* Someone who asked not to be moved is not shown a 600ms animation to look at. */
@media (prefers-reduced-motion: reduce) {
    .rt-qr {
        transition: opacity .01s linear;
    }

    .rt-qr-out {
        transform: none;
    }
}

/* ── Dish sheet ───────────────────────────────────────────────────────────── */

.rt-sheet {
    background-color: var(--pap);
    color: var(--ink);
    min-height: 100%;
}

.rt-sheet-header {
    background-color: var(--brand);
    color: var(--on-brand);
    padding: 14px 20px 18px;
}

.rt-sheet-header .rt-sheet-name {
    font-family: var(--rt-font-display);
    font-weight: 700;
    font-size: calc(34px * var(--rt-scale, 1));
    line-height: 1.05;
    margin: 6px 0 0;
}

/* Without a photograph the price carries the block, in the brass the header block already uses. */
.rt-sheet-header .rt-sheet-price {
    font-family: var(--rt-font-display);
    font-weight: 700;
    font-size: calc(30px * var(--rt-scale, 1));
    font-variant-numeric: tabular-nums;
    color: var(--gold);
}

.rt-sheet-rule {
    border: 0;
    border-top: 1px solid var(--gold);
    margin: 12px 0 10px;
    opacity: .6;
}

.rt-sheet-body {
    padding: 16px 20px 28px;
}

.rt-sheet-photo {
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    display: block;
}

/* ── Checkout ─────────────────────────────────────────────────────────────────

   Three questions between the basket and the kitchen: how you want to be served, where you are
   sitting, and how you intend to pay. Built from the tokens the carte already uses, so a
   restaurant's own palette dresses its checkout without anything here knowing which one it is. */

.rt-seg {
    display: flex;
    gap: 0;
    border: 1px solid var(--chip);
    border-radius: var(--rt-radius);
    overflow: hidden;
    margin-top: 8px;
}

/* Equal widths rather than content widths: a segmented control whose halves jump about as the
   labels change language stops reading as one control. */
.rt-seg-option {
    flex: 1 1 0;
    min-width: 0;
    font-family: var(--rt-font-display);
    font-weight: 700;
    font-size: 12.5px;
    letter-spacing: .08em;
    text-transform: uppercase;
    padding: 10px 8px;
    border: 0;
    border-left: 1px solid var(--chip);
    background: transparent;
    color: var(--ink);
    cursor: pointer;
}

.rt-seg-option:first-child {
    border-left: 0;
}

.rt-seg-on {
    background: var(--brand);
    color: var(--on-brand);
}

/* The same control, wrapping, for a room rather than a choice of two.

   Two services fit a row; forty tables do not, and equal widths would give each one a sliver. So the
   flex basis goes back to the content and the rows wrap — every other rule above still applies, and
   a table reads as the same kind of thing as a service because it is chosen the same way.

   Tall enough for a thumb: 44px is the smallest target a phone should carry, and this one is tapped
   by somebody sitting at a table holding the phone one-handed. */
.rt-seg-wrap {
    flex-wrap: wrap;
    gap: 1px;
    background: var(--chip);
}

.rt-seg-wrap .rt-seg-option {
    flex: 0 1 auto;
    min-width: 64px;
    min-height: 44px;
    border-left: 0;
    background: var(--pap);
    text-transform: none;
    letter-spacing: .04em;
}

.rt-seg-wrap .rt-seg-on {
    background: var(--brand);
    color: var(--on-brand);
}

/* A framed statement, not a field. The table number is read off the QR code and never typed — a
   number typed blind is a plate carried to strangers — so this says where it came from instead of
   inviting a correction. */
.rt-box {
    border: 1px solid var(--chip);
    border-radius: var(--rt-radius);
    padding: 10px 12px;
    margin-top: 8px;
}

.rt-box-gold {
    border-color: var(--gold);
}

/* The seat: where it came from, and what it is — on one row.

   It used to read "Table détectée par le QR — n° 12", so the one thing a diner checks against the
   card in front of them was the last two characters of a line of prose, set exactly like the prose.
   Then it became a caption above a 34px number, which read correctly and took a block of the screen
   for two facts nobody rereads. Baseline-aligned on one row it keeps the order — provenance, then
   value — at a third of the height.

   The number keeps the weight; it is what gets checked against the card on the table. It no longer
   keeps 34px: that was sized as a heading, and it is a value in a row. */
.rt-seat {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 4px 10px;
}

.rt-seat-from {
    display: inline-flex;
    align-items: center;
    gap: 5px;
}

/* MudBlazor's smallest icon is 20px, which is nearly twice the 11px uppercase caption it sits in and
   reads as the subject rather than the mark. Tied to the line's own size instead. */
.rt-seat-from .mud-icon-root {
    font-size: 1.25em;
    width: 1.25em;
    height: 1.25em;
}

.rt-seat-number {
    font-family: var(--rt-font-display);
    font-weight: 700;
    font-size: calc(22px * var(--rt-scale, 1));
    line-height: 1.15;
    letter-spacing: .01em;
    color: var(--gold-text);
}

/* Pushed to the end of the row rather than dropped below it. */
.rt-seat-action {
    margin-left: auto;
}

/* Payment options as outlined rows. The chosen one takes the brand colour, which is the only
   affordance a radio group of one still needs to read as a choice rather than as a notice. */
.rt-radio {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    width: 100%;
    text-align: left;
    border: 1px solid var(--chip);
    border-radius: var(--rt-radius);
    padding: 12px;
    margin-top: 8px;
    background: transparent;
    color: var(--ink);
    cursor: pointer;
}

.rt-radio-on {
    border-color: var(--brand);
    border-width: 2px;
    /* Keeps the row from shifting a pixel when the border thickens under the selection. */
    padding: 11px;
}

.rt-radio-dot {
    flex: none;
    width: 16px;
    height: 16px;
    margin-top: 2px;
    border-radius: 50%;
    border: 2px solid var(--chip);
}

.rt-radio-on .rt-radio-dot {
    border-color: var(--brand);
    background:
        radial-gradient(circle at center, var(--brand) 0 4px, transparent 4px);
}

/* ── Following an order ───────────────────────────────────────────────────────

   The page a notification lands on. It answers three questions in about two seconds — what is my
   number, where has it got to, what did I order — so the first of them is the largest thing on it. */

.rt-track-code {
    font-family: var(--rt-font-display);
    font-weight: 700;
    /* Read at arm's length across a counter while somebody else reads it back. */
    font-size: calc(54px * var(--rt-scale, 1));
    line-height: 1.05;
    letter-spacing: .02em;
    color: var(--gold-text);
}

/* The walk, as a column. Grid rather than a list so the markers and the text share one baseline and
   the connecting rule can run between them without being drawn per row. */
.rt-track {
    display: grid;
    grid-template-columns: 26px 1fr;
    row-gap: 0;
    margin-top: 8px;
}

.rt-track-mark {
    display: flex;
    flex-direction: column;
    align-items: center;
}

.rt-track-dot {
    width: 19px;
    height: 19px;
    border: 2px solid var(--chip);
    border-radius: 3px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    line-height: 1;
    color: var(--on-brand);
}

/* Passed: filled, with the tick. Current: outlined in the brand and breathing, so the eye lands on
   the one row that is happening now rather than on the last one that is complete. */
.rt-track-done .rt-track-dot {
    background: var(--brand);
    border-color: var(--brand);
}

.rt-track-now .rt-track-dot {
    border-color: var(--brand);
    border-width: 2px;
    animation: rt-track-pulse 1.6s ease-in-out infinite;
}

@keyframes rt-track-pulse {
    0%, 100% { transform: scale(1); }
    50%      { transform: scale(1.12); }
}

@media (prefers-reduced-motion: reduce) {
    .rt-track-now .rt-track-dot { animation: none; }
}

/* The rule between two markers. Solid behind a step already taken, dotted ahead of it — the same
   distinction the timeline makes with its dots, so it survives being read in greyscale. */
.rt-track-rule {
    flex: 1 1 auto;
    width: 0;
    min-height: 22px;
    border-left: 2px solid var(--chip);
}

.rt-track-done .rt-track-rule {
    border-left-style: solid;
    border-left-color: var(--brand);
}

.rt-track-ahead .rt-track-rule {
    border-left-style: dotted;
}

.rt-track-label {
    padding: 0 0 14px 10px;
    font-family: var(--rt-font-body);
    font-size: calc(15px * var(--rt-scale, 1));
    color: var(--ink);
}

/* A step not reached yet is legible but plainly not the subject. Opacity rather than a paler ink, so
   it dims consistently whatever palette the restaurant published. */
.rt-track-ahead .rt-track-label {
    opacity: .5;
}

/* Five stars, in the restaurant's own colours.

   Buttons rather than a rating component from the library: this panel is hand-styled down to the
   hairline and a themed control would fight the establishment's palette for it. Big enough for a
   thumb — 44px is the smallest target a phone should carry, and this one is tapped by somebody who
   has just finished eating and is holding the phone one-handed. */
.rt-stars {
    display: flex;
    gap: 2px;
    margin-top: 6px;
}

.rt-star {
    min-width: 44px;
    min-height: 44px;
    padding: 0;
    border: 0;
    background: transparent;
    cursor: pointer;
    font-size: calc(28px * var(--rt-scale, 1));
    line-height: 1;
    /* Unfilled stars are outlines, not absences: a row of five is the affordance, and showing only
       the chosen ones would make a three-star rating look like a three-star control. */
    color: var(--chip);
}

.rt-star-on {
    color: var(--gold);
}

/* The score on a listing. Small, beside the name, and absent entirely when nobody has rated the
   place — zero stars and no stars are different facts. */
.rt-score {
    display: inline-flex;
    align-items: baseline;
    gap: 4px;
    color: var(--gold-text);
    font-family: var(--rt-font-display);
    font-weight: 700;
}

.rt-score-count {
    font-family: var(--rt-font-body);
    font-weight: 400;
    font-size: calc(12px * var(--rt-scale, 1));
    color: var(--mut);
}

/* A dish's score, beside its name.

   A number rather than a row of stars: forty rows of five glyphs turns a carte into a scoreboard,
   and the dish is still the subject. Small, muted, and absent entirely when nobody has rated it. */
/* Les piments imprimés sur la carte. Sur la ligne du nom et non en dessous, à la différence de la
   note : c'est une propriété du plat qu'on lit en même temps que son nom, pas un commentaire. */
.rt-dish-heat {
    margin-left: 6px;
    font-size: calc(12px * var(--rt-scale, 1));
    letter-spacing: -.05em;
    white-space: nowrap;
}

.rt-dish-score {
    display: block;
    margin-top: 2px;
    font-family: var(--rt-font-body);
    font-size: calc(11.5px * var(--rt-scale, 1));
    letter-spacing: .04em;
    color: var(--gold-text);
}

/* Le compteur d'un choix répétable. Assez large pour le pouce, assez discret pour ne pas
   voler la ligne au nom du plat. */
.rt-stepper { display:inline-flex; align-items:center; gap:2px; }
.rt-step { width:26px; height:26px; border:1px solid var(--rt-line, rgba(0,0,0,.2)); background:transparent;
           border-radius:6px; font-size:16px; line-height:1; cursor:pointer; color:inherit; }
.rt-step:disabled { opacity:.3; cursor:default; }
.rt-step-count { min-width:18px; text-align:center; font-variant-numeric:tabular-nums; }
