/*
 * Venue dashboard styling, layered on legal.css.
 *
 * legal.css provides the structure -- the header/footer, .wrap.wide, .note and
 * the .plan-cta button system built for the pricing page. Only what is specific
 * to editing a menu lives here, so this page loads exactly two stylesheets and
 * no CDN.
 *
 * ===========================================================================
 * THIS PAGE IS LIGHT. EVERY OTHER PAGE ON THE SITE IS DARK. THAT IS THE POINT.
 * ===========================================================================
 *
 * legal.css opens with a near-black :root because it was written for the policy
 * and pricing pages, which mirror the studio's dark chrome. This file loads
 * AFTER it and replaces that palette wholesale.
 *
 * WHY, given that a consistent product usually means one theme:
 *
 *   1. THIS IS A DIFFERENT PRODUCT, AND IT IS SOLD TO DIFFERENT PEOPLE. The
 *      studio sells QR codes to somebody at a laptop. This sells a menu system
 *      to a restaurateur, and the thing they are building here is a LIGHT page
 *      -- the default template is `linen`, warm paper and quiet ink. A menu
 *      builder wrapped in near-black chrome makes the owner design against a
 *      surface that contradicts the surface they are designing. The preview and
 *      the page around it now agree.
 *   2. IT IS READ IN A RESTAURANT, IN DAYLIGHT, ON A COUNTER. The live order
 *      board sits open for a whole service on a tablet by a window. Dark chrome
 *      is the wrong bet for that room.
 *   3. IT MARKS THE BOUNDARY. Clicking through from the studio should feel like
 *      arriving somewhere, not like the same page with different words on it.
 *
 * WHAT IS DELIBERATELY NOT CHANGED: the wordmark. `Elite<span>QR</span>` keeps
 * its violet QR on every page including this one (pinned below), because the
 * brand should not fork just because the chrome did.
 *
 * COLOURS ARE LITERAL, NOT DERIVED. Same reasoning legal.css gives: there is no
 * theme switcher here and nothing else to reference. --primary is a deep, low-
 * chroma sage that matches the `linen` template's accent in lib/menu-theme.js,
 * so the chrome and the default menu are visibly one thing. If you change one,
 * change the other.
 */

:root {
    --bg: #f7f5f1;                    /* warm paper -- linen's bg */
    --panel: #ffffff;
    --panel-sunk: #faf9f6;            /* inputs and wells, a shade under panel */
    --primary: #4f6f64;               /* linen's accent */
    --primary-soft: rgba(79, 111, 100, 0.10);
    --text: #23211d;
    /*
     * MEASURED, NOT PICKED BY EYE. #7d766c looked right and came out at 4.12:1
     * on the paper -- under the 4.5:1 AA floor for text this size, and this
     * colour carries the descriptions, the hints and the code addresses. Two
     * shades down clears it. _harnesses/venues-skin.mjs prints the ratios.
     */
    --muted: #6f685e;
    --border: rgba(35, 33, 29, 0.11);
    --border-strong: rgba(35, 33, 29, 0.18);

    /* Status colours, re-picked for ink on paper. The dark-theme versions of
       these (#4ade80, #fde047, #fca5a5) are chosen to glow on black and are
       close to illegible here -- they have to be darkened, not reused. */
    --ok: #2f6b45;
    --ok-soft: rgba(47, 107, 69, 0.11);
    --warn: #755408;
    --warn-soft: rgba(138, 100, 16, 0.12);
    --danger: #a02c2c;
    --danger-soft: rgba(160, 44, 44, 0.09);

    /* One shadow, used everywhere something lifts off the page. Warm-tinted
       rather than neutral black so it sits on the paper instead of on top of
       it. */
    --lift: 0 1px 2px rgba(35, 33, 29, 0.04), 0 8px 24px -12px rgba(35, 33, 29, 0.16);
}

/*
 * A very slight warmth at the top of the page. Fixed, not scrolled, so it reads
 * as light falling on paper rather than as a band that slides away.
 */
body {
    background:
        radial-gradient(1200px 520px at 50% -280px, rgba(79, 111, 100, 0.07), transparent 70%),
        var(--bg);
    background-attachment: fixed;
}

/* The brand does not fork. See the header note. */
header.site { background: rgba(255, 255, 255, 0.72); backdrop-filter: blur(8px); }
header.site a.brand span { color: #8b5cf6; }

/*
 * legal.css gives .plan-cta a translucent-white face, which is invisible on
 * paper. The secondary button becomes an outlined one instead.
 */
.plan-cta {
    background: var(--panel);
    border-color: var(--border-strong);
    box-shadow: var(--lift);
}
.plan-cta:hover { background: var(--panel-sunk); }
.plan-cta.is-primary { box-shadow: 0 8px 20px -10px rgba(79, 111, 100, 0.55); }

h2 { padding-bottom: 2px; }

/*
 * `hidden` beats any author display rule. Without this, giving an element
 * display:flex or display:grid silently disables its hidden attribute -- which
 * is exactly what happened on the menu page's cart controls. This page toggles
 * `hidden` on views, the sign-out button and the cancel-edit button, so the
 * same trap is one flex rule away.
 */
[hidden] { display: none !important; }

.muted { color: var(--muted); }

/* A button that reads as a link. Used for sign-out and the back control, both
   of which are actions rather than navigation, so <button> is correct and the
   styling is what has to be talked out of looking like a button. */
.linklike {
    background: none;
    border: 0;
    padding: 0;
    color: var(--muted);
    font: inherit;
    font-size: 13px;
    cursor: pointer;
    text-decoration: underline;
}
.linklike:hover { color: var(--primary); }
.back { margin: 8px 0 16px; display: inline-block; }

.plan-cta.inline { display: inline-block; margin-top: 8px; }

/* ---------- the venue header and tabs ---------- */

.venue-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 18px;
    flex-wrap: wrap;
}
.venue-head h1 { margin: 0 0 4px; }
.venue-head p { margin: 0; }
.venue-head__side { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.venue-head__side .plan-cta { margin-top: 0; padding: 9px 14px; }
/*
 * An unpublished menu 404s for everyone, its owner included. The link still
 * says what it would do rather than disappearing, so the state is legible.
 */
.plan-cta.is-disabled { opacity: .5; pointer-events: none; }

/*
 * SCROLLS SIDEWAYS, NEVER WRAPS.
 *
 * Four tabs wrapping to two lines on a narrow phone would push the panel below
 * the fold and make the bar itself the tallest thing on screen. A single
 * scrolling line keeps its height fixed at every width.
 *
 * STICKY, because a panel can be long -- the menu list on a real venue runs to
 * dozens of items, and switching tabs should not require scrolling back to the
 * top first.
 */
.tabs {
    display: flex;
    gap: 4px;
    margin: 22px 0 26px;
    padding: 4px;
    border-radius: 12px;
    /*
     * OPAQUE, because it is sticky and the page scrolls UNDER it.
     *
     * This was a 5%-alpha tint plus a backdrop blur, which is a fine recipe for
     * a bar sitting on a static background and the wrong one here: menu rows and
     * order cards passed straight through it and the labels became unreadable
     * against whatever happened to be behind them at the time. A blur softens
     * what is behind; it does not hide it.
     *
     * The paper colour with a hair of the accent, so it still reads as a track
     * rather than a hole in the page.
     */
    background: linear-gradient(rgba(79, 111, 100, .05), rgba(79, 111, 100, .05)), var(--bg);
    border: 1px solid var(--border);
    overflow-x: auto;
    scrollbar-width: none;
    position: sticky;
    top: 8px;
    z-index: 10;
    /* Enough shadow to separate it from what slides beneath. */
    box-shadow: 0 6px 16px -12px rgba(35, 33, 29, .5);
}
.tabs::-webkit-scrollbar { display: none; }

.tab {
    flex: 1 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    /* 44px tall including padding -- the smallest comfortable touch target. */
    padding: 11px 16px;
    min-height: 44px;
    border: 0;
    border-radius: 9px;
    background: none;
    color: var(--muted);
    font: inherit;
    font-size: 14px;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
    transition: background .18s ease, color .18s ease;
}
.tab:hover { color: var(--text); }
.tab.is-active {
    background: var(--panel);
    color: var(--text);
    box-shadow: var(--lift);
}

/*
 * THE WAITING-ORDER COUNT.
 *
 * Tabs would otherwise make one thing strictly worse than the old long scroll:
 * an owner on the Menu tab has no way to see that an order arrived. This and the
 * chime are what carry that, and the document title carries it when the tab
 * itself is in the background.
 */
.tab__badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--primary);
    color: #fff;
    font-size: 11px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
}

.tab-panel[hidden] { display: none !important; }
/* The first heading in a panel should not add a second gap under the tab bar. */
.tab-panel > h2:first-child { margin-top: 0; }
.tab-panel > .note:first-child { margin-top: 0; }

/* ---------- venue list ---------- */

.venue-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 16px 18px;
    margin-bottom: 12px;
    border: 1px solid var(--border);
    border-radius: 14px;
    background: var(--panel);
    box-shadow: var(--lift);
    transition: border-color .25s ease, transform .25s ease;
}
.venue-row:hover {
    border-color: color-mix(in srgb, var(--primary) 45%, var(--border));
    transform: translateY(-1px);
}
.venue-row h3 { margin: 0; font-size: 16px; }
.venue-row .sub { font-size: 12px; color: var(--muted); margin-top: 2px; }

/*
 * Service state pills. Three states, and the colours are doing real work:
 * "ordering off" is the DEFAULT for a venue nobody has paid for yet, so it must
 * not read as an error -- grey, not red. Grace is amber because it is genuinely
 * time-limited and the owner should act.
 */
.pill {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 999px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .1em;
    white-space: nowrap;
}
.pill.live  { background: var(--ok-soft);      color: var(--ok); }
.pill.grace { background: var(--warn-soft);    color: var(--warn); }
.pill.off   { background: rgba(35,33,29,.06);  color: var(--muted); }
.pill.draft { background: var(--primary-soft); color: var(--primary); }

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

.new-venue { margin-top: 36px; }

/*
 * Scoped to .wrap rather than to `form`, because not every field on this page is
 * inside one -- the table-count control sits on its own in the Table codes
 * section, and while these selectors said `form` it rendered as a raw unstyled
 * browser input in the middle of a styled page.
 */
.wrap label {
    display: block;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: .1em;
    color: var(--muted);
    font-weight: 700;
    margin: 14px 0 6px;
}
.wrap input[type="text"], .wrap input[type="number"] {
    width: 100%;
    padding: 11px 13px;
    border-radius: 10px;
    border: 1px solid var(--border-strong);
    background: var(--panel);
    color: var(--text);
    font: inherit;
    font-size: 15px;
}
.wrap input::placeholder { color: #b3aca2; }
/* A visible ring, not just a border-colour change. On paper the 1px swap alone
   is easy to miss, and this form is filled in on a phone in a noisy room. */
.wrap input:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px var(--primary-soft);
}
form .plan-cta { margin-top: 18px; width: auto; display: inline-block; padding: 11px 22px; }

.item-form {
    margin-top: 20px;
    padding: 18px;
    border: 1px solid var(--border);
    border-radius: 14px;
    background: var(--panel);
    box-shadow: var(--lift);
}
.item-form__row { display: grid; grid-template-columns: 1fr 1fr 110px; gap: 14px; }
.item-form__row label { margin-top: 0; }
@media (max-width: 640px) {
    .item-form__row { grid-template-columns: 1fr; }
}

/* ---------- live order board ---------- */

.board-head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; }
.board-sub { font-size: 14px; margin: 30px 0 10px; }

/*
 * Cards, not a table. Staff read this from arm's length while carrying plates,
 * so each order is a block with the table number as the largest thing on it --
 * a dense row layout looks tidier on a laptop and is unusable on a counter.
 */
#order-board { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 14px; }

.order-card {
    border: 1px solid var(--border);
    border-radius: 14px;
    background: var(--panel);
    box-shadow: var(--lift);
    padding: 14px 16px;
}
/*
 * A NEW order is the only one with a coloured edge. Everything already accepted
 * is work in progress and should not compete for attention with the order
 * nobody has looked at yet.
 */
.order-card.is-pending { border-color: var(--primary); box-shadow: 0 0 0 1px var(--primary); }
.order-card.is-ready { border-color: rgba(47,107,69,.55); }

.order-card__head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.order-card__table { font-size: 19px; font-weight: 800; letter-spacing: -.01em; }
.order-card__time { font-size: 11px; color: var(--muted); margin-top: 2px; }
.order-card__items { list-style: none; padding: 0; margin: 12px 0 0; font-size: 14px; }
.order-card__items li { padding: 3px 0; }
.order-qty { font-weight: 800; font-variant-numeric: tabular-nums; }
.order-note { color: var(--muted); font-size: 12.5px; }
.order-card__note { margin-top: 10px; font-size: 13px; color: var(--muted); font-style: italic; }
.order-card__foot {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border);
}
.order-card__total { font-weight: 700; font-variant-numeric: tabular-nums; margin-right: auto; font-size: 14px; }

.order-btn {
    font: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
    padding: 8px 16px; border-radius: 999px;
    border: 0; background: var(--primary); color: #fff;
}
.order-btn:disabled { opacity: .5; cursor: default; }
/* Reject is destructive, so it is quiet -- it must never be the easy mis-tap
   next to Accept on a touchscreen in a hurry. */
.order-btn.is-reject { background: none; border: 1px solid var(--border-strong); color: var(--muted); }
.order-btn.is-reject:hover { border-color: var(--danger); color: var(--danger); background: var(--danger-soft); }

.session-row {
    display: flex; align-items: center; justify-content: space-between; gap: 16px;
    padding: 12px 0; border-bottom: 1px solid var(--border);
}
.session-row__table { font-weight: 700; }
.session-row__total { font-weight: 800; font-variant-numeric: tabular-nums; font-size: 16px; }
/* Its own class rather than borrowing .menu-item__actions, which is what let a
   mobile rule written for the menu rows leak onto this one and push the page
   sideways. Three different rows should not share one hook. */
.session-row__actions { display: flex; align-items: center; gap: 14px; flex-shrink: 0; }

/*
 * Close table is a QUIET button, not a primary one. It is the correct end of
 * service and it is also irreversible for that sitting, so it should not be the
 * brightest thing in the row -- but it is used often enough to deserve a real
 * target rather than a text link.
 */
.order-btn.is-quiet {
    background: none;
    border: 1px solid var(--border-strong);
    color: var(--text);
    font-weight: 600;
}
.order-btn.is-quiet:hover { background: var(--panel-sunk); border-color: var(--primary); }
/* The second-tap state, when the table still has orders nobody has accepted.
   Amber rather than red: closing is a normal end of service, it just deserves
   one deliberate tap when there is food outstanding. */
.order-btn.is-confirming {
    border-color: var(--warn);
    background: var(--warn-soft);
    color: var(--warn);
}

/* ---------- design panel ---------- */

/*
 * Controls left, live preview right, and the preview STICKS. The whole point of
 * the panel is watching the menu change as a knob moves; a preview that scrolls
 * away the moment the owner reaches the layout controls would defeat it.
 * Collapses to one column well before the two get cramped.
 */
.design { display: grid; grid-template-columns: 1fr 300px; gap: 28px; align-items: start; }
@media (max-width: 900px) { .design { grid-template-columns: 1fr; } }

.design-preview { position: sticky; top: 20px; }
.preview-note { font-size: 12px; text-align: center; margin: 10px 0 0; }

/*
 * A phone-shaped frame, because that is the only device a menu is ever read on.
 * Previewing a table menu in a 900px-wide box would flatter every layout and
 * tell the owner nothing about the one that matters.
 */
.phone {
    width: 100%;
    max-width: 300px;
    margin: 0 auto;
    aspect-ratio: 9 / 17;
    /* The bezel stays dark -- it is a picture of a phone, and a phone is dark.
       Softened from near-black to a warm graphite so it sits on paper. */
    border: 8px solid #3a3733;
    border-radius: 30px;
    overflow: hidden;
    background: #3a3733;
    box-shadow: 0 26px 60px -26px rgba(35,33,29,.55);
}
.phone iframe { width: 100%; height: 100%; border: 0; display: block; }

.template-picker {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 12px;
}
.template-card {
    text-align: left;
    padding: 10px;
    border-radius: 12px;
    border: 1px solid var(--border);
    background: var(--panel);
    color: var(--text);
    font: inherit;
    cursor: pointer;
    transition: border-color .2s ease;
}
.template-card { box-shadow: var(--lift); }
.template-card:hover { border-color: color-mix(in srgb, var(--primary) 45%, var(--border)); }
.template-card.is-active { border-color: var(--primary); box-shadow: 0 0 0 1px var(--primary); }
/* The swatch is the only place a template's real colours appear in the picker,
   so it needs an edge of its own -- an ivory or linen chip is otherwise a white
   rectangle on a white card. */
.template-card__swatch { border: 1px solid var(--border); }
.template-card__swatch { display: flex; height: 30px; border-radius: 7px; overflow: hidden; }
.template-card__swatch span { flex: 1; }
.template-card__label { font-weight: 700; font-size: 14px; margin-top: 8px; }
.template-card__blurb { font-size: 11.5px; color: var(--muted); margin-top: 2px; line-height: 1.4; }

.custom-panel {
    margin-top: 18px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--panel);
    padding: 0 16px;
}
.custom-panel summary {
    cursor: pointer;
    padding: 14px 0;
    font-weight: 600;
    font-size: 14px;
}
.custom-panel > .linklike { margin: 0 0 16px; }
.custom-panel[open] summary { border-bottom: 1px solid var(--border); margin-bottom: 12px; }

.field-group { margin-bottom: 18px; }
.field-group h4 {
    margin: 0 0 8px;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .12em;
    color: var(--muted);
}
.field-row { display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }
.field-row label { margin: 0; flex: 1; text-transform: none; letter-spacing: 0; font-size: 13px;
                   font-weight: 500; color: var(--text); }
.field-row select {
    padding: 7px 10px;
    border-radius: 8px;
    border: 1px solid var(--border-strong);
    background: var(--panel);
    color: var(--text);
    font: inherit;
    font-size: 13px;
    min-width: 150px;
}
.field-row select:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px var(--primary-soft);
}
.colour-row input[type="color"] {
    width: 42px;
    height: 28px;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: 7px;
    background: none;
    cursor: pointer;
}

.field-label {
    display: block;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: .1em;
    color: var(--muted);
    font-weight: 700;
    margin: 14px 0 6px;
}

/* ---------- image slots ---------- */

.image-fields { display: flex; gap: 18px; flex-wrap: wrap; margin-top: 4px; }
.image-field { flex: 1; min-width: 150px; }

.image-slot {
    border: 1px dashed var(--border);
    border-radius: 12px;
    padding: 10px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
}
.image-slot__thumb { width: 84px; height: 84px; object-fit: cover; border-radius: 9px; }
.image-slot.wide .image-slot__thumb { width: 100%; height: 72px; }
.image-slot__actions { display: flex; gap: 12px; }
.image-slot__add {
    background: none;
    border: 0;
    color: var(--primary);
    font: inherit;
    font-size: 13px;
    cursor: pointer;
    padding: 8px 0;
}
.image-slot__busy { color: var(--muted); font-size: 13px; padding: 8px 0; }

/* ---------- menu items ---------- */

.menu-section-head {
    margin: 26px 0 8px;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .14em;
    color: var(--primary);
    font-weight: 700;
}
.menu-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 12px 0;
    border-bottom: 1px solid var(--border);
}
.menu-item.is-hidden .menu-item__name { text-decoration: line-through; opacity: .55; }
.menu-item__thumb { width: 46px; height: 46px; object-fit: cover; border-radius: 8px; flex-shrink: 0; }
/* Takes the slack, so a row with a thumbnail keeps the price hard right instead
   of letting space-between scatter three children evenly across the row. */
.menu-item__body { flex: 1; min-width: 0; }
.menu-item__name { font-weight: 600; font-size: 15px; }
.menu-item__desc { font-size: 13px; color: var(--muted); margin-top: 2px; }
.menu-item__price { font-variant-numeric: tabular-nums; font-weight: 700; white-space: nowrap; }
.menu-item__actions { display: flex; gap: 10px; flex-shrink: 0; align-items: center; }

/*
 * ON A PHONE THE ROW STACKS.
 *
 * At 390px a thumbnail, a name, a description, a price and five controls do not
 * fit on one line, and flex does not fail loudly -- it just squeezes. The dish
 * name wrapped to two lines and the whole action group compressed into a strip
 * of tap targets a few pixels apart, with Delete sitting beside Hide.
 *
 * That matters more here than on most rows: the stock toggle exists BECAUSE
 * marking a dish sold out happens several times a service, mid-rush, on a phone
 * -- see the note on .stock-toggle. A control designed for that is the one
 * control that must not be cramped on that device, and a mis-tap two pixels to
 * the right of it deletes the dish.
 *
 * So below 640px the actions drop to their own full-width line, where the
 * toggle can be a comfortable target and the destructive links sit well away
 * from it.
 */
/*
 * EVERY SELECTOR HERE IS SCOPED UNDER .menu-item, and that is not tidiness.
 *
 * `.menu-item__actions` is reused by the venue rows and the open-tables rows --
 * js/venues-ui.js builds all three with the same class. Written unscoped, the
 * `width: 100%` below landed on a session row, which is a plain non-wrapping
 * flex row: the block took the full content width while still sitting after the
 * table name, and pushed the whole page 37px wider than the phone. The row
 * itself looked fine; the page just scrolled sideways.
 *
 * Caught by the overflow probe in this file's harness, which names the element
 * rather than only reporting that the document is too wide.
 */
@media (max-width: 640px) {
    .menu-item { flex-wrap: wrap; row-gap: 10px; }
    .menu-item .menu-item__body { flex-basis: 60%; }
    .menu-item .menu-item__actions {
        width: 100%;
        justify-content: flex-start;
        gap: 16px;
        flex-wrap: wrap;
    }
    .menu-item .menu-item__price { margin-right: auto; }
    .menu-item .stock-toggle { padding: 8px 14px; }
}

/*
 * THE STOCK SWITCH. Deliberately the only button-shaped control in the row --
 * everything else there is a text link. Marking a dish sold out happens several
 * times a service, on a phone, mid-rush; editing and deleting happen once a
 * month. The visual weight follows the frequency, not the alphabet.
 *
 * Green reads "available" and grey reads "not today". Red was rejected: nothing
 * has gone wrong when a kitchen sells out of a dish, and an angry-looking row
 * would make a normal evening look like a fault.
 */
.stock-toggle {
    font: inherit;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .08em;
    padding: 5px 11px;
    border-radius: 999px;
    cursor: pointer;
    white-space: nowrap;
    border: 1px solid rgba(47,107,69,.35);
    background: var(--ok-soft);
    color: var(--ok);
    transition: background .15s ease, border-color .15s ease;
}
.stock-toggle:hover { background: rgba(47,107,69,.19); }
.stock-toggle.is-out {
    border-color: var(--border-strong);
    background: rgba(35,33,29,.05);
    color: var(--muted);
}
.stock-toggle.is-out:hover { background: rgba(35,33,29,.1); }

.item-form.is-editing { border-color: var(--primary); }
.item-form h3 { margin: 0 0 4px; font-size: 15px; }
.item-form__actions { display: flex; align-items: center; gap: 16px; }
.item-form__actions .plan-cta { margin-top: 18px; }

.empty-note { color: var(--muted); padding: 22px 0; }

/*
 * THE PRINTED-CODES WARNING.
 *
 * Deliberately a full-width banner and not a tooltip. Unpublishing is the one
 * control in this product that can dark a physical object -- a sticker already
 * on a table, which the owner cannot recall. The whole lapse design exists to
 * avoid doing that to a venue, so the one place an owner can do it to
 * themselves has to be impossible to click past without reading.
 */
.danger-banner {
    border: 1px solid rgba(160,44,44,.35);
    background: var(--danger-soft);
    border-radius: 12px;
    padding: 16px 18px;
    margin: 16px 0;
}
.danger-banner strong { color: var(--danger); }
.danger-banner p { margin: 0 0 8px; color: #7a2323; font-size: 14px; }
.danger-banner p:last-child { margin-bottom: 0; }

/* The unsaved-design marker. Amber rather than red: nothing is broken and
   nothing is lost -- the saved design is still what diners see. */
.unsaved {
    margin: 16px 0 0;
    padding: 9px 13px;
    border-radius: 9px;
    border: 1px solid rgba(138,100,16,.3);
    background: var(--warn-soft);
    color: var(--warn);
    font-size: 13px;
    font-weight: 600;
}

/* ---------- table codes ---------- */

.table-count { display: flex; align-items: center; gap: 12px; margin-bottom: 18px; flex-wrap: wrap; }
/*
 * `.wrap input[type="number"]` is (0,2,1) and would beat a plain
 * `.table-count input` at (0,1,1) -- so this control rendered full-width, with
 * its label wrapped onto two lines beside a text box wide enough for a street
 * address to hold a number under 200. Matching the attribute here levels the
 * specificity and source order does the rest.
 */
.table-count label { margin: 0; white-space: nowrap; }
.table-count input[type="number"] { width: 92px; }
.table-code-row + .plan-cta { margin-top: 18px; width: auto; display: inline-block; }

.table-code-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid var(--border);
    font-size: 14px;
}
.table-code-row code {
    color: var(--muted);
    font-size: 12px;
    word-break: break-all;
}

/* ---------- toasts ---------- */

#toast-host {
    position: fixed;
    left: 50%;
    bottom: 24px;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    gap: 8px;
    z-index: 50;
    pointer-events: none;
}
.toast {
    padding: 11px 18px;
    border-radius: 10px;
    font-size: 14px;
    border: 1px solid var(--border-strong);
    background: var(--panel);
    color: var(--text);
    box-shadow: 0 12px 34px -12px rgba(35,33,29,.35);
}
.toast.error { border-color: rgba(160,44,44,.45); color: var(--danger); }
.toast.success { border-color: rgba(47,107,69,.45); color: var(--ok); }

/* ---------- menu-view stats ---------- */

/*
 * A KPI ROW, not a chart. Four unrelated headline numbers have no shape to
 * compare -- putting them in a four-bar chart makes them harder to read, not
 * easier.
 */
.stat-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 12px;
    margin: 14px 0 22px;
}
.stat {
    padding: 14px 16px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--panel);
    box-shadow: var(--lift);
}
.stat__label {
    font-size: 11px; font-weight: 700; letter-spacing: .1em;
    text-transform: uppercase; color: var(--muted);
}
/*
 * PROPORTIONAL figures, deliberately. tabular-nums gives every digit the width
 * of a zero, which makes a standalone number like 121 look loose at this size.
 * Tabular belongs in columns that must align vertically -- the axis ticks below
 * keep it for exactly that reason.
 */
.stat__value { font-size: 28px; font-weight: 700; letter-spacing: -.02em; margin-top: 4px; line-height: 1.1; }
.stat__sub { font-size: 12px; color: var(--muted); margin-top: 2px; }

.chart { margin: 0 0 10px; }
.chart__svg { width: 100%; height: auto; display: block; overflow: visible; }

/* One hue: this is magnitude over time, not identity, so a second colour would
   have nothing to mean. */
.chart__bar { fill: var(--primary); }
/* Recessive: hairline, solid, one step off the surface. Never dashed. */
.chart__grid { stroke: var(--border-strong); stroke-width: 1; }
.chart__tick {
    font-size: 10px; fill: var(--muted); text-anchor: end;
    font-variant-numeric: tabular-nums;
}
.chart__axis { font-size: 10px; fill: var(--muted); }
/* Text wears text tokens, never the series colour. */
.chart__value { font-size: 11px; font-weight: 700; fill: var(--text); }
/* The whole band is the target -- a one-view day is a 2px sliver otherwise. */
.chart__hit { fill: transparent; cursor: default; }
.chart__hit:hover { fill: var(--primary-soft); }

/* ---------- which dishes get ordered ---------- */

/*
 * A RANKED BAR LIST BUILT FROM DIVS, not an SVG chart, and that is a considered
 * choice rather than a shortcut. This is one series of magnitudes against text
 * labels: the dish names are the axis, they are of wildly different lengths, and
 * the number belongs beside its own bar. In SVG that is a label-collision problem
 * to solve on every phone width; in CSS the row simply wraps.
 *
 * Same single hue as the day chart above, for the same reason -- there is one
 * series, so a second colour would have nothing to mean, and no legend is needed
 * because the heading names what is plotted.
 */
.dish-lede { font-size: 14px; color: var(--text); margin: 2px 0 14px; }

.dish-list { display: flex; flex-direction: column; gap: 14px; }

.dish__head {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 12px; margin-bottom: 5px;
}
.dish__name {
    font-size: 14px; font-weight: 600; color: var(--text);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The value is a DIRECT LABEL, so the bar never carries the number alone.
   Tabular here, unlike .stat__value, because these do align down a column. */
.dish__qty {
    font-size: 13px; font-weight: 700; color: var(--text);
    font-variant-numeric: tabular-nums; flex: none;
}

/*
 * The track is the full width so the bars share one scale a reader can compare
 * along -- without it each bar is its own unit and the ranking is the only
 * information left.
 */
.dish__track {
    height: 8px; border-radius: 999px;
    background: var(--border); overflow: hidden;
}
.dish__bar {
    height: 100%; background: var(--primary);
    /* 4px rounded data-end, square at the start: the bar keeps its foot on the
       baseline exactly as the day chart's columns do. */
    border-radius: 0 4px 4px 0;
    /* No min-width: a zero-sold dish must draw nothing at all. The visibility
       floor for small non-zero values is applied to the width in JS instead,
       where it can tell zero apart from small. */
}

.dish__sub {
    display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px;
    margin-top: 6px; font-size: 12px; color: var(--muted);
}
.dish__money { font-variant-numeric: tabular-nums; }
/*
 * The excuse chip. Recessive on purpose -- it qualifies a number rather than
 * competing with it, and a dish that is merely sold out must not look like an
 * alert. Never a status colour: those are reserved.
 */
.dish__flag {
    font-size: 11px; font-weight: 600; letter-spacing: .02em;
    padding: 1px 7px; border-radius: 999px;
    border: 1px solid var(--border-strong); color: var(--muted);
}

.dish-more { font-size: 12px; color: var(--muted); margin-top: 12px; }

/*
 * The dishes nobody ordered -- the actionable half, so it gets a surface of its
 * own rather than being a line of muted text under the list. Still not a
 * warning colour: this is information, and a red panel about a slow-selling
 * starter is the dashboard crying wolf.
 */
.dish-quiet {
    margin-top: 18px; padding: 14px 16px;
    border: 1px solid var(--border); border-left: 3px solid var(--primary);
    border-radius: 10px; background: var(--panel);
}
.dish-quiet__title { font-size: 13px; font-weight: 700; color: var(--text); }
.dish-quiet__body { font-size: 14px; color: var(--text); margin-top: 6px; }
.dish-quiet__hint { font-size: 12px; color: var(--muted); margin-top: 8px; }

@media (max-width: 480px) {
    /* The name gets its own line rather than being ellipsised down to nothing
       next to the count -- a dish you cannot read is a row that says nothing. */
    .dish__head { flex-wrap: wrap; gap: 2px; }
    .dish__name { white-space: normal; }
}

/* ---------- what ordering costs ---------- */

/*
 * Reuses .stat-row / .stat wholesale -- these are three single values, which is
 * a KPI row and not a chart, and they should read as the same kind of object as
 * the menu-view tiles six inches above rather than as a new component.
 *
 * The one addition is a tint on the "Elite QR took ₹0" tile, because that number
 * is the product's whole argument and an undifferentiated third of a grey row
 * buries it. A tint and not a status colour: nothing here is an alert, and the
 * good/warning/serious/critical steps stay reserved for state.
 */
/*
 * EMPHASIS, NOT A TINT. The first version filled this tile with --primary-soft
 * and it read as DISABLED beside its two white neighbours -- a 10%-alpha wash
 * over a warm panel is the same move most design systems use for "unavailable",
 * so the one tile carrying the product's whole argument looked like the one that
 * had been switched off. Only a screenshot shows that; every assertion passed.
 *
 * So: same surface as its neighbours, lifted by a coloured edge and a ring.
 */
.stat--good {
    border-color: var(--primary);
    box-shadow: var(--lift), 0 0 0 3px var(--primary-soft);
}
.stat--good .stat__value { color: var(--primary); }

.commission-line {
    font-size: 13px; color: var(--text);
    margin: 2px 0 10px;
}

/* MENU COACHING. A panel, not a warning: nothing here is broken, and a menu
   missing veg marks is not an error state. Same surface as the stat tiles so it
   reads as information about the venue rather than as something the product is
   complaining about. */
.coach {
    margin: 16px 0 22px; padding: 14px 16px;
    border: 1px solid var(--border); border-left: 3px solid var(--primary);
    border-radius: 10px; background: var(--panel);
}
.coach__title { font-size: 13px; font-weight: 700; color: var(--text); }
.coach__list { margin: 8px 0 0; padding-left: 18px; }
.coach__list li { font-size: 13px; color: var(--muted); line-height: 1.55; }
.coach__list li + li { margin-top: 6px; }

/* The trial banner's loss line -- the venue's own takings, stated plainly.
   Normal body type, not a callout box: it is a fact about their restaurant, and
   dressing it as an alert would turn a true sentence into a pressure tactic. */
.trial-loss { font-size: 14px; color: var(--text); margin: 10px 0 0; }

/* A note under a field, for something the owner cannot infer from the label --
   today, that the venue address is published on the diner's page. Tied to the
   input with aria-describedby so a screen reader reads it as part of the field
   rather than as loose text after it. */
.field-note { font-size: 12px; margin: 4px 0 0; }

/* The spice level in the owner's own item list. Recessive: it is there so a
   forgotten dish is noticeable while scanning, not to compete with the name. */
.menu-item__spice {
    margin-left: 8px; padding: 1px 7px; border-radius: 999px;
    border: 1px solid var(--border-strong); color: var(--muted);
    font-size: 11px; font-weight: 600; letter-spacing: .02em;
    text-transform: uppercase; vertical-align: 1px;
}

/* ---------- reordering ---------- */

/*
 * Arrows, not drag-and-drop. Dragging needs a pointer-events library, does not
 * work with a screen reader, and on a phone competes with the scroll the owner
 * is already doing to reach the row. Two buttons are unambiguous everywhere.
 */
.move-group { display: inline-flex; gap: 2px; flex-shrink: 0; }
.move-btn {
    width: 30px; min-height: 30px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--panel);
    color: var(--muted);
    font: inherit; font-size: 13px; line-height: 1;
    cursor: pointer;
}
.move-btn:hover:not(:disabled) { border-color: var(--primary); color: var(--primary); }
/* Disabled rather than hidden at the ends of a list: a control that disappears
   makes the row reflow under a thumb that is already moving. */
.move-btn:disabled { opacity: .3; cursor: default; }

.menu-section-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }

.board-alerts { display: inline-flex; gap: 16px; align-items: center; }

/* ---------- sizes and extras ---------- */

.opt-panel {
    margin-top: 16px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--panel-sunk);
    padding: 0 14px;
}
.opt-panel summary { cursor: pointer; padding: 12px 0; font-weight: 600; font-size: 14px; }
.opt-panel[open] summary { border-bottom: 1px solid var(--border); margin-bottom: 10px; }
.opt-panel > .linklike { margin: 0 0 14px; display: inline-block; }
.opt-hint { font-size: 12px; margin: 0 0 8px; }
.opt-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 10px; }
.opt-row { display: flex; gap: 8px; align-items: center; }
.opt-row input[type="text"] { flex: 1; min-width: 0; }
.opt-row input[type="number"] { width: 96px; flex-shrink: 0; }

@media (max-width: 640px) {
    /* The Remove link drops under the two fields rather than squeezing them to
       nothing on a narrow screen. */
    .opt-row { flex-wrap: wrap; }
    .opt-row input[type="text"] { flex-basis: 100%; }
}

/* ---------- the veg mark ---------- */

/*
 * The same square-outline-with-a-dot the diner sees, so the owner is auditing
 * their menu against the exact mark that gets printed. Duplicated from
 * lib/menu-theme.js rather than shared: that file generates a stylesheet for a
 * document served from a route, and this one is a static sheet. Two contexts,
 * twelve lines, and menu-theme.js carries the reasoning.
 */
.diet {
    display: inline-block;
    width: 12px; height: 12px;
    border: 1.5px solid; border-radius: 2px;
    position: relative; margin-right: 7px;
    flex-shrink: 0;
}
.diet::after {
    content: ""; position: absolute; inset: 2px;
    border-radius: 50%; background: currentColor;
}
.diet--veg { color: #1f8a3b; }
.diet--nonveg { color: #9e2b25; }
.diet--egg { color: #b5820a; }

.diet-picker { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 2px; }
.diet-chip {
    display: inline-flex; align-items: center;
    /* 40px tall: this gets set while typing an item on a phone. */
    min-height: 40px;
    padding: 8px 14px;
    border-radius: 999px;
    border: 1px solid var(--border-strong);
    background: var(--panel);
    color: var(--muted);
    font: inherit; font-size: 13px; font-weight: 600;
    cursor: pointer;
    transition: border-color .15s ease, color .15s ease, background .15s ease;
}
.diet-chip:hover { border-color: var(--primary); }
.diet-chip.is-active { color: var(--text); border-color: var(--primary); box-shadow: 0 0 0 1px var(--primary); }
.diet-chip--veg.is-active { border-color: #1f8a3b; box-shadow: 0 0 0 1px #1f8a3b; background: rgba(31,138,59,.08); }
.diet-chip--nonveg.is-active { border-color: #9e2b25; box-shadow: 0 0 0 1px #9e2b25; background: rgba(158,43,37,.08); }
.diet-chip--egg.is-active { border-color: #b5820a; box-shadow: 0 0 0 1px #b5820a; background: rgba(181,130,10,.10); }

/* ---------- calls for staff ---------- */

/*
 * Amber, not the order board's sage. A call is not work in progress -- it is a
 * person waiting -- and it should read as a different KIND of thing at a glance
 * from across a counter, not as another order card.
 */
.call-row {
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    padding: 12px 16px; margin-bottom: 10px;
    border: 1px solid rgba(138, 100, 16, .35);
    border-radius: 12px;
    background: var(--warn-soft);
}
.call-row__table { font-weight: 800; font-size: 17px; }
.call-row .order-btn { background: var(--warn); }
.call-row .sub { font-size: 12.5px; color: var(--warn); margin-top: 2px; }

@media (max-width: 640px) {
    .call-row { flex-wrap: wrap; row-gap: 10px; }
    .call-row .order-btn { width: 100%; min-height: 44px; }
}

/* ---------- allergens ---------- */

.allergen-picker { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 2px; }
.allergen-chip {
    /* Smaller than the veg chips on purpose: fourteen of these are a checklist,
       and the veg mark is a single decision that deserves more weight. Still 34px
       tall, which is a usable target for something ticked once per dish. */
    min-height: 34px;
    padding: 6px 12px;
    border-radius: 999px;
    border: 1px solid var(--border-strong);
    background: var(--panel);
    color: var(--muted);
    font: inherit; font-size: 12.5px; font-weight: 600;
    cursor: pointer;
}
.allergen-chip:hover { border-color: var(--warn); }
.allergen-chip.is-on {
    border-color: var(--warn);
    background: var(--warn-soft);
    color: var(--warn);
}

/* ---------- table code actions and previews ---------- */

.code-actions { display: flex; gap: 10px; flex-wrap: wrap; margin: 18px 0 8px; }
.code-actions .plan-cta { margin-top: 0; width: auto; padding: 11px 18px; }

.table-code-row__actions { display: flex; gap: 14px; align-items: center; flex-shrink: 0; }

.code-preview {
    display: flex;
    align-items: center;
    gap: 18px;
    flex-wrap: wrap;
    padding: 16px;
    margin: 4px 0 14px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--panel);
    box-shadow: var(--lift);
}
/* A white plate under the code even if the panel ever stops being white. A QR
   needs its quiet zone light, and "light" cannot be left to inheritance. */
.code-preview__img {
    width: 168px;
    height: 168px;
    background: #fff;
    border-radius: 8px;
    border: 1px solid var(--border);
}
.code-preview .plan-cta { margin-top: 0; width: auto; }

/* ==========================================================================
   THE PRINT SHEET
   ==========================================================================

   Hidden on screen, and the ONLY thing on paper. Everything else on the page is
   dashboard chrome that would waste a sheet.

   Sizes are in mm because the output is a physical object: three cards to a row
   across A4 with room to cut, and 42mm of that is the code itself -- comfortably
   above the point where a phone camera starts hunting at arm's length across a
   table.
*/

.print-sheet { display: none; }

@media print {
    /*
     * The dashboard, the chrome and the toasts all go.
     *
     * SCOPED TO .venue-app. menu-guide.html loads this stylesheet for the light
     * palette, and unscoped this rule would hide the entire guide when somebody
     * printed it -- a blank sheet, from the one page most likely to be printed
     * and handed to a member of staff.
     */
    body.venue-app > *:not(.print-sheet) { display: none !important; }

    @page { margin: 10mm; }

    html, body { background: #fff !important; color: #000 !important; }

    .print-sheet {
        display: grid !important;
        grid-template-columns: repeat(3, 1fr);
        gap: 6mm;
    }

    .tent {
        /* The dashed edge is a cut line. Restaurants cut these with scissors, so
           it has to be on the paper rather than implied by whitespace. */
        border: 1px dashed #999;
        border-radius: 3mm;
        padding: 5mm 3mm;
        text-align: center;
        /* A card split across a page break is wasted paper and a wasted cut. */
        break-inside: avoid;
        page-break-inside: avoid;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: flex-start;
    }

    .tent__head { font-size: 11pt; font-weight: 800; line-height: 1.2; margin-bottom: 1mm; }
    .tent__sub { font-size: 7pt; color: #444; line-height: 1.3; margin-bottom: 2mm; }
    .tent__qr {
        width: 42mm;
        height: 42mm;
        /* Already 1-bit black on white; let the printer have it at full contrast
           rather than smoothed. */
        image-rendering: pixelated;
    }
    /*
     * THE TABLE NUMBER IS THE LARGEST TEXT ON THE CARD.
     *
     * A stack of freshly cut cards is otherwise indistinguishable -- the code is
     * unreadable to a human -- and somebody has to walk round the room putting
     * the right one on the right table.
     */
    .tent__table { font-size: 13pt; font-weight: 800; margin-top: 2mm; }
    .tent__cta { font-size: 7.5pt; color: #333; margin-top: 0.5mm; }
}

/* ==========================================================================
   THE PHONE
   ==========================================================================

   A restaurant owner does this job on a phone. Not as a fallback -- as the
   primary device: marking a dish sold out happens mid-service, standing up, and
   the order board is read on whatever is in a pocket. Everything below is about
   that, and none of it removes a control.

   The tab bar above is the largest single change; these are the rest.
*/

/*
 * iOS SAFARI ZOOMS THE WHOLE PAGE when a focused input's font-size is under
 * 16px. Every field here was 15px, so tapping "Item" zoomed the layout and left
 * the owner pinching back out after every single field. It is not a preference,
 * it is a hard threshold -- 16px exactly is enough.
 *
 * Applied at all widths on touch-capable pointers rather than at a breakpoint:
 * an iPad in landscape is wider than most desktop breakpoints and does the same
 * thing.
 */
@media (pointer: coarse) {
    .wrap input[type="text"],
    .wrap input[type="number"],
    .field-row select,
    .sheet__note { font-size: 16px; }
}

@media (max-width: 900px) {
    /*
     * THE PREVIEW COMES FIRST ON A NARROW SCREEN.
     *
     * The two-column grid collapses here, and in source order that puts the
     * preview BELOW every control -- so the owner taps a template and sees
     * nothing happen, because the thing that changed is a full screen further
     * down. The whole feature is watching the menu change as a knob moves.
     *
     * Not sticky: a phone-shaped frame pinned to the top of a phone is most of
     * the screen. First and compact is the better trade.
     */
    .design { grid-template-columns: 1fr; }
    .design-preview { order: -1; position: static; }
    .phone { max-width: 230px; }
}

@media (max-width: 640px) {
    .wrap { padding: 24px 16px 72px; }

    .venue-head { gap: 12px; }
    .venue-head__side { width: 100%; justify-content: space-between; }

    /* Two per row rather than one: a template is chosen by its colours, and a
       single column means scrolling to compare two of them. */
    .template-picker { grid-template-columns: repeat(2, 1fr); gap: 10px; }
    .template-card__blurb { display: none; }

    /*
     * ACCEPT AND REJECT BECOME REAL BUTTONS.
     *
     * This is the one control in the product that gets used under pressure, by
     * somebody holding something in their other hand. 8px of padding on a text
     * label is not a target; Reject sitting a few pixels from Accept is a
     * mis-tap that sends a diner away.
     */
    .order-card__foot { gap: 10px; }
    .order-btn { min-height: 44px; padding: 12px 20px; flex: 1 0 auto; }
    .order-card__total { flex-basis: 100%; margin-bottom: 4px; }

    /* Edit / Hide / Delete are text links, which are poor targets. Give them
       vertical room without turning the row into a wall of buttons. */
    .menu-item .menu-item__actions .linklike { padding: 10px 0; }

    .session-row { flex-wrap: wrap; row-gap: 10px; }
    .session-row__actions { width: 100%; display: flex; align-items: center;
                            justify-content: space-between; gap: 12px; }

    /* One per row. Two 150px slots at 342px leaves each one too narrow to show
       the cover photo it is previewing. */
    .image-fields { gap: 14px; }
    .image-field { flex-basis: 100%; }

    .board-head { flex-wrap: wrap; gap: 8px; }
    .design-controls > .plan-cta { width: 100%; }
    .item-form__actions .plan-cta { width: 100%; }
    .item-form__actions { flex-wrap: wrap; }

    /* The address is the longest unbroken string on the page and the one most
       likely to force a sideways scroll. */
    .table-code-row { flex-wrap: wrap; row-gap: 6px; }
    .table-code-row code { font-size: 11px; }

    footer.site a { display: inline-block; padding: 6px 10px; }
}

/* Very narrow -- an older or smaller phone, where two template cards no longer
   fit side by side without the labels breaking mid-word. */
@media (max-width: 360px) {
    .template-picker { grid-template-columns: 1fr; }
    .tab { padding: 11px 12px; font-size: 13px; }
}

@media (prefers-reduced-motion: reduce) {
    * { animation: none !important; transition: none !important; }
}

/* ---- Import a printed menu ----------------------------------------------
   Sits above the item list, so it reads as a starting point rather than an
   afterthought. Bordered rather than filled: it is a tool, not a warning. */
.import-menu {
    margin: 1rem 0 1.5rem;
    padding: 1rem;
    border: 1px solid var(--line, #e2ddd4);
    border-radius: 10px;
}
.import-menu__hint { margin: .5rem 0 0; font-size: .9rem; }
.import-review__list { list-style: none; margin: .75rem 0; padding: 0; }
.import-review__list li { padding: .35rem 0; }
.import-review__list label {
    display: flex;
    gap: .6rem;
    align-items: flex-start;
    cursor: pointer;
}
/* 44px targets under a coarse pointer -- these are ticked in a restaurant, on
   a phone, standing up. Matches the rest of the mobile pass in this file. */
@media (pointer: coarse) {
    .import-review__list label { min-height: 44px; align-items: center; }
    .import-review__list input[type="checkbox"] { width: 20px; height: 20px; }
}

/* ---------------- the staff link ----------------
 *
 * A credential displayed on screen, so it is monospaced (a code read aloud from
 * a proportional font loses the difference between similar glyphs) and full
 * width (a truncated URL invites sending half of one).
 */
.staff-link-field {
    width: 100%;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 16px;   /* 16px minimum, or iOS Safari zooms on focus */
    padding: 0.7rem 0.8rem;
    border-radius: 10px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: inherit;
}

.staff-link-actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-top: 0.6rem;
}

/* Armed state on "Replace link" -- it signs the whole floor out, so the second
   tap should not look like the first. */
.staff-link-actions .is-danger {
    border-color: rgba(180, 40, 40, 0.6);
    color: #b42828;
}

/* The saved UPI address, shown back to the owner. Monospaced because a payment
   address is read character by character when somebody is checking it. */
.pay-current {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-weight: 700;
    margin: 0 0 0.25rem;
}

.pay-confirm {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    margin: 0.7rem 0 0.3rem;
    cursor: pointer;
}

.pay-confirm input { margin-top: 0.2rem; width: 1.05rem; height: 1.05rem; flex-shrink: 0; }
.pay-confirm__text { font-size: 0.85rem; }

/* ---------------- serving windows ---------------- */

.time-window {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}

/* 16px minimum, or iOS Safari zooms the page on focus and never zooms back. */
.time-window input[type="time"] {
    font-size: 16px;
    padding: 0.55rem 0.6rem;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: inherit;
}

/* Visually hidden but read aloud. Each time field needs its own label -- "and"
   between two boxes is meaningless to a screen reader. */
.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* ---------------- what diners said ---------------- */

.feedback-row {
    display: flex;
    align-items: baseline;
    gap: 0.7rem;
    padding: 0.6rem 0;
    border-top: 1px solid var(--border);
}
.feedback-row__score { font-weight: 800; font-variant-numeric: tabular-nums; }
.feedback-row__note { flex: 1; }
.feedback-row__meta { color: var(--muted); font-size: 0.78rem; white-space: nowrap; }
