/* ============================================================
   03-app.css  (3 of 6)

   Customer screens: category tabs, quantity steppers, menu cards, deals rail,
   outlet picker, sticky cart, cart, orders, item detail, account, search, auth.

   Part of an ordered set. The browser concatenates these in the order they
   are linked in fragments/head.html, and that order IS the cascade. Do not
   reorder the <link> tags, and do not move a rule between files without
   checking what it would then stop overriding.
   ============================================================ */

/* ============================================================
   CATEGORY TABS

   The app design replaces the circular illustrated chips with a plain
   underlined tab bar: a scrolling row of labels on a hairline, the active
   one in primary with a 2px rule beneath it. Quieter, and it stops the
   category row competing with the food photography below it.
   ============================================================ */

.category-chips-wrapper {
    margin: 0 0 var(--stack-lg);
    border-bottom: 1px solid var(--color-border);
}

.category-chips {
    display: flex;
    gap: 32px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    margin-bottom: -1px;
}
.category-chips::-webkit-scrollbar { display: none; }

.category-chip {
    position: relative;
    display: flex;
    align-items: center;
    flex: none;
    padding: 0 0 var(--stack-sm);
    border: none;
    background: transparent;
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
    -webkit-tap-highlight-color: transparent;
}

/* The illustrated pucks have no place in a text tab bar. */
.cat-chip-icon,
.cat-icon-img { display: none; }

.cat-chip-label {
    font-family: var(--font-body);
    font-size: var(--text-label-lg);
    line-height: var(--lh-label-lg);
    letter-spacing: 0.01em;
    font-weight: 600;
    color: var(--color-ink-muted);
    transition: color 150ms ease;
}

.category-chip:hover .cat-chip-label { color: var(--color-ink); }

.category-chip.active .cat-chip-label { color: var(--color-primary); }

/* The active rule sits on the wrapper's hairline rather than under the label, so the
   two line up exactly however tall the label happens to be. */
.category-chip.active::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: -1px;
    height: 2px;
    background: var(--color-primary);
    border-radius: 2px 2px 0 0;
}

/* ============================================================
   QUANTITY STEPPER (+ / - buttons replacing number input)
   ============================================================ */

.qty-stepper,
.cart-control__stepper {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    overflow: hidden;
    background: var(--color-surface);
    padding: 3px;
    box-shadow: 0 2px 6px rgba(70, 45, 25, 0.05);
}

.qty-stepper button,
.cart-control__stepper button {
    width: 30px;
    height: 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 50%;
    background: var(--color-primary-tint);
    color: var(--color-primary-dark);
    font-size: 0.95rem;
    font-weight: 700;
    cursor: pointer;
    transition: all 120ms ease;
    -webkit-tap-highlight-color: transparent;
}

.qty-stepper button:hover,
.cart-control__stepper button:hover {
    background: var(--color-primary);
    color: #fff;
}
.qty-stepper button:active,
.cart-control__stepper button:active {
    transform: scale(0.88);
}

.qty-stepper .qty-value,
.cart-control__stepper .cart-qty-value {
    min-width: 28px;
    text-align: center;
    font-weight: 700;
    font-size: 0.92rem;
    color: var(--color-ink);
    font-family: var(--font-display);
    user-select: none;
}

/* ---------- Add / stepper swap on menu cards ----------
   The card used to show a stepper reading "1" beside an Add button, on an
   item that was not in the cart at all. Two controls, one of which was
   lying: the 1 described what would be added, but read as what was already
   there. Now the stepper only exists once the item is in the cart, so any
   number on screen is a number in the cart.

   Both controls are always in the DOM and .is-active picks between them.
   That keeps the swap instant and, more importantly, keeps the no-JS path
   honest: the server renders the correct one on load. */
.cart-control__stepper { display: none; }
.cart-control.is-active .cart-control__add { display: none; }
.cart-control.is-active .cart-control__stepper { display: inline-flex; }

/* Only the number changes on +/-, and it changes under the user's finger,
   so it gets a short pop to confirm the tap registered. Anything longer
   would lag behind repeated presses. */
.cart-qty-value.is-bumped { animation: qtyBump 180ms ease; }
@keyframes qtyBump {
    0%   { transform: scale(1); }
    45%  { transform: scale(1.28); }
    100% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
    .cart-qty-value.is-bumped { animation: none; }
}

/* Solid sage pill with lively tactile micro-press */
/* ============================================================
   ADD BUTTON

   In the app design the add control is a small filled square that floats
   over the bottom-right of the food photo, not a pill sitting in a row of
   text. It stays the same object on the detail screen and the deals rail.
   ============================================================ */

.btn-add {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: none;
    border-radius: var(--radius-sm);
    background: var(--color-primary);
    color: #fff;
    font-family: var(--font-body);
    font-size: 0;              /* the label is for screen readers; the glyph carries it */
    line-height: 0;
    box-shadow: var(--shadow-md);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: transform 120ms ease, background-color 150ms ease;
}

.btn-add::before {
    content: 'add';
    font-family: 'Material Symbols Outlined';
    font-size: 20px;
    line-height: 1;
    font-weight: 400;
}

.btn-add:hover  { background: var(--color-primary-dark); }
.btn-add:active { transform: scale(0.9); }

/* ============================================================
   MENU CARD

   Two-up grid of square-cropped photos on pure-white cards with a hairline
   and the lightest shadow — the app design's main feed. The previous
   horizontal row layout is gone: at two columns the photo does the work of
   identifying the dish, so the text below it is only name, price, rating.
   ============================================================ */

.menu-card {
    display: flex;
    flex-direction: column;
    height: 100%;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    overflow: hidden;
    box-shadow: var(--shadow-sm);
    transition: box-shadow 200ms ease, transform 200ms ease;
}

.menu-card:hover  { box-shadow: var(--shadow-md); }
.menu-card:active { transform: scale(0.99); }

/* The row wrapper survives from the old markup but no longer lays anything out
   sideways — the card is a column now. */
.menu-card-row {
    display: flex;
    flex-direction: column;
    height: 100%;
}

.menu-card-photo {
    position: relative;
    display: block;
    width: 100%;
    aspect-ratio: 1 / 1;
    background: var(--color-surface-deep);
    overflow: hidden;
}

.menu-card-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 500ms cubic-bezier(0.16, 1, 0.3, 1);
}

.menu-card:hover .menu-card-photo img { transform: scale(1.05); }

/* Generated illustrations are line art, not photography: contain them and sit them
   on the tonal fill rather than cropping them to the square. */
.menu-card-photo.is-illustration {
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-surface-food);
}

.menu-card-photo.is-illustration img {
    width: 62%;
    height: 62%;
    object-fit: contain;
}

.menu-card:hover .menu-card-photo.is-illustration img { transform: scale(1.06); }

.menu-card-body {
    display: flex;
    flex-direction: column;
    gap: var(--stack-xs);
    padding: var(--stack-sm);
    flex: 1;
}

.menu-card-name {
    margin: 0;
    font-size: var(--text-label-lg);
    line-height: var(--lh-label-lg);
    letter-spacing: 0.01em;
    font-weight: 600;
    color: var(--color-ink);
    /* One line, clipped — a long dish name must not push the price row out of
       alignment with the card beside it. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.menu-card-price {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: var(--text-label-lg);
    line-height: var(--lh-label-lg);
    font-weight: 600;
    color: var(--color-primary);
}

/* The add control floats over the photo, but it cannot live inside it: the photo is a
   link to the dish page and a <form> nested in an <a> is invalid markup that browsers
   recover from unpredictably. So the two are siblings inside a positioned media wrapper
   — the button overlaps the image without ever being a descendant of the anchor. */
.menu-card-media {
    position: relative;
}

.menu-card-actions {
    position: absolute;
    right: 8px;
    bottom: 8px;
    z-index: 2;
}

/* An item that cannot be ordered shows no control at all; the reason is stated in the
   card body instead. Keeps a dead button off a sold-out card. */
.menu-card-actions:empty { display: none; }


/* ============================================================
   TODAY'S DEALS / SPECIALS (Foochi-style featured specials cards)
   ============================================================ */

.featured-scroll {
    display: flex;
    gap: 16px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    margin: 0 -1rem 12px;
    padding: 6px 1rem 12px;
    scroll-snap-type: x mandatory;
}
.featured-scroll::-webkit-scrollbar { display: none; }

.deal-card {
    flex: 0 0 170px;
    width: 170px;
    background: var(--color-surface-food);
    border: 1px solid rgba(240, 220, 199, 0.6);
    border-radius: var(--radius-lg);
    overflow: hidden;
    box-shadow: 0 4px 14px -6px rgba(70, 45, 25, 0.1);
    padding: 10px;
    scroll-snap-align: start;
    transition: all 200ms cubic-bezier(0.16, 1, 0.3, 1);
    position: relative;
}
.deal-card:hover {
    background: #FADEC8;
    transform: translateY(-4px);
    box-shadow: 0 14px 26px -8px rgba(70, 45, 25, 0.18);
}
.deal-card:active { transform: scale(0.96); }

.deal-card-photo {
    width: 100%;
    aspect-ratio: 1;
    position: relative;
    overflow: hidden;
    border-radius: var(--radius-md);
    background: radial-gradient(circle at 45% 40%, #FFFDF9 10%, #F5D5BE 100%);
    box-shadow: inset 0 2px 6px rgba(0,0,0,0.06);
    display: flex;
    align-items: center;
    justify-content: center;
}
.deal-card-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: transform 300ms ease;
}
.deal-card:hover .deal-card-photo img {
    transform: scale(1.08);
}
.deal-card-photo.is-illustration {
    padding: 10px;
    background: linear-gradient(160deg, #FFF0DE, var(--color-coral));
}
.deal-card-photo.is-illustration img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    opacity: 1;
}
.deal-card:hover .deal-card-photo.is-illustration img {
    transform: none;
}

.deal-card-body {
    padding: 10px 4px 4px;
}

.deal-card-name {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.92rem;
    margin: 0 0 6px;
    line-height: 1.25;
    display: -webkit-box;
    -webkit-line-clamp: 1;
    -webkit-box-orient: vertical;
    overflow: hidden;
    color: var(--color-ink);
}

.deal-card-price {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.05rem;
    color: var(--color-accent-strong);
}

.deal-card-add {
    min-width: 0;
    padding: 6px 12px;
    font-size: 0.76rem;
}

/* ============================================================
   OUTLET PICKER (choose-your-canteen screen)
   ============================================================ */

.outlet-card {
    display: flex;
    align-items: center;
    gap: 16px;
    background: var(--color-surface-food);
    border: 1px solid rgba(240, 220, 199, 0.6);
    border-radius: var(--radius-lg);
    box-shadow: 0 4px 14px -6px rgba(70, 45, 25, 0.08);
    padding: 20px 22px;
    transition: all 180ms ease;
    color: inherit;
}
.outlet-card:hover {
    background: var(--color-surface-deep);
    color: inherit;
    transform: translateY(-2px);
    box-shadow: 0 10px 22px -8px rgba(70, 45, 25, 0.16);
}
.outlet-card:active {
    transform: scale(0.98);
}

/* Cream disc on peach — the icon reads as a plate set on the surface */
.outlet-card-icon {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-surface);
    color: var(--color-accent-strong);
    font-size: 1.6rem;
    flex-shrink: 0;
    box-shadow: 0 4px 12px -4px rgba(70, 45, 25, 0.12);
}

.outlet-card-name {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.15rem;
    color: var(--color-ink);
    margin: 0;
}

.outlet-card-hint {
    font-size: 0.84rem;
    color: var(--color-ink-muted);
    margin: 2px 0 0;
}

.outlet-card-chevron {
    margin-left: auto;
    color: var(--color-ink-muted);
    font-size: 1.3rem;
}

/* ============================================================
   STICKY CART BAR (Glassmorphism & glowing action pill)
   ============================================================ */

.sticky-cart-bar {
    position: fixed;
    left: 0;
    right: 0;
    z-index: 1040;
    padding: 10px 16px;
    animation: slide-up 320ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

@media (max-width: 767.98px) {
    .sticky-cart-bar {
        bottom: calc(var(--bottom-nav-height) + var(--safe-area-bottom) + 8px);
    }
}
@media (min-width: 768px) {
    .sticky-cart-bar {
        bottom: 12px;
    }
}

.sticky-cart-inner {
    max-width: 540px;
    margin: 0 auto;
    background: rgba(69, 124, 92, 0.94);
    backdrop-filter: blur(16px) saturate(180%);
    -webkit-backdrop-filter: blur(16px) saturate(180%);
    color: #fff;
    border-radius: var(--radius-pill);
    padding: 14px 22px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    box-shadow: 0 12px 30px -8px rgba(56, 102, 75, 0.5), 0 0 0 1px rgba(255,255,255,0.2) inset;
    cursor: pointer;
    text-decoration: none;
    transition: all 150ms ease;
    animation: cart-bar-glow 3s ease-in-out infinite alternate;
}

@keyframes cart-bar-glow {
    0% { box-shadow: 0 10px 24px -8px rgba(56, 102, 75, 0.45); }
    100% { box-shadow: 0 14px 34px -6px rgba(69, 124, 92, 0.7); }
}

.sticky-cart-inner:hover {
    transform: scale(1.02);
    color: #fff;
}

.sticky-cart-inner:active {
    transform: scale(0.97);
}

.sticky-cart-info {
    font-size: 0.88rem;
    font-weight: 600;
}

.sticky-cart-info strong {
    font-size: 1.05rem;
    font-weight: 800;
}

.sticky-cart-action {
    display: flex;
    align-items: center;
    gap: 6px;
    font-weight: 700;
    font-size: 0.95rem;
    color: #fff;
    background: rgba(255, 255, 255, 0.2);
    padding: 6px 14px;
    border-radius: var(--radius-pill);
}

@keyframes slide-up {
    from { transform: translateY(100%); opacity: 0; }
    to   { transform: translateY(0); opacity: 1; }
}

/* ============================================================
   CART PAGE (card-based layout)
   ============================================================ */

/* ---------- Cart, ported from the Stitch "Your Order" comp ----------
   The comp introduces two things the page lacked: a named pickup block, so
   you can see which counter you are collecting from before paying, and
   small section labels that break a long scroll into "where" / "what" /
   "how much".

   The comp's address line and its Subtotal / Taxes & Fees rows are not
   here: Outlet has no address column and the app has no fee concept at all
   (Order carries a single totalAmount). Rendering either would mean
   inventing numbers, so the summary shows the one figure that is real.
   ============================================================ */
.section-label {
    font-family: var(--font-display);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--color-ink-muted);
    margin: 0 0 0.6rem;
}

.pickup-card {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    background: var(--color-surface-food);
    border-radius: var(--radius-md);
    padding: 14px 16px;
    margin-bottom: 1.75rem;
}
.pickup-card__icon {
    display: grid;
    place-items: center;
    width: 42px;
    height: 42px;
    flex: 0 0 42px;
    border-radius: var(--radius-pill);
    background: var(--color-primary-tint);
    color: var(--color-primary);
    font-size: 1.25rem;
}
.pickup-card__name {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.02rem;
    color: var(--color-ink);
    margin: 0;
}
.pickup-card__meta {
    margin: 0;
    font-size: 0.84rem;
    color: var(--color-ink-muted);
}

.cart-summary {
    background: var(--color-surface-food);
    border-radius: var(--radius-md);
    padding: 14px 18px;
    margin-bottom: 1.25rem;
}
.cart-summary__row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
}
.cart-summary__row dt {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1rem;
    color: var(--color-ink);
    margin: 0;
}
.cart-summary__row dd {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.3rem;
    color: var(--color-accent-strong);
    margin: 0;
}

.cart-item-card {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px;
    background: var(--color-surface-food);
    border: 1px solid rgba(240, 220, 199, 0.6);
    border-radius: var(--radius-lg);
    margin-bottom: 12px;
    box-shadow: 0 4px 12px -6px rgba(70, 45, 25, 0.08);
}

.cart-item-photo {
    width: 68px;
    height: 68px;
    border-radius: var(--radius-md);
    overflow: hidden;
    flex-shrink: 0;
    background: radial-gradient(circle, #FFFDF9 10%, #F5D5BE 100%);
    box-shadow: inset 0 2px 4px rgba(0,0,0,0.06);
    display: flex;
    align-items: center;
    justify-content: center;
}

.cart-item-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.cart-item-photo.is-illustration {
    padding: 8px;
}
.cart-item-photo.is-illustration img {
    object-fit: contain;
}

.cart-item-info {
    flex: 1;
    min-width: 0;
}

.cart-item-name {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1rem;
    margin: 0 0 2px;
    color: var(--color-ink);
}

.cart-item-price {
    font-weight: 600;
    font-size: 0.88rem;
    color: var(--color-ink-muted);
}

.cart-item-right {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 8px;
}

.cart-item-subtotal {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.05rem;
    color: var(--color-accent-strong);
}

/* Sticky pay button at bottom of cart */
.sticky-pay-bar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 1040;
    background: rgba(251, 228, 208, 0.92);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border-top: 1px solid rgba(240, 220, 199, 0.8);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    box-shadow: var(--shadow-sticky);
    padding: 16px 18px;
    padding-bottom: calc(16px + var(--safe-area-bottom));
}

@media (max-width: 767.98px) {
    .sticky-pay-bar {
        bottom: calc(var(--bottom-nav-height) + var(--safe-area-bottom));
        padding-bottom: 14px;
    }
}

.sticky-pay-inner {
    max-width: 540px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.sticky-pay-total {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.35rem;
    color: var(--color-accent-strong);
}

.sticky-pay-total small {
    display: block;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--color-ink-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* ============================================================
   ORDERS PAGE (rich cards instead of list-group)
   ============================================================ */

.order-card {
    background: var(--color-surface-food);
    border: 1px solid rgba(240, 220, 199, 0.6);
    border-radius: var(--radius-lg);
    padding: 18px 20px;
    margin-bottom: 14px;
    text-decoration: none;
    color: var(--color-ink);
    display: block;
    transition: all 180ms ease;
    box-shadow: 0 4px 12px -6px rgba(70, 45, 25, 0.08);
}

.order-card:hover {
    background: var(--color-surface-deep);
    color: var(--color-ink);
    transform: translateY(-2px);
    box-shadow: 0 10px 22px -8px rgba(70, 45, 25, 0.16);
}
.order-card:active {
    transform: scale(0.98);
}

.order-card-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    margin-bottom: 8px;
}

.order-card-token {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.05rem;
    letter-spacing: 0.02em;
    color: var(--color-ink);
}

.order-card-items {
    font-size: 0.88rem;
    color: var(--color-ink-muted);
    margin-bottom: 10px;
    line-height: 1.5;
}

.order-card-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.order-card-total {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.15rem;
    color: var(--color-accent-strong);
}

.order-card-date {
    font-size: 0.8rem;
    color: var(--color-ink-muted);
}

/* ---------- Order history, ported from the Stitch comp ----------
   The card previously ran its items as one truncated line, which on a
   three-item order showed "2 x Veg Biryani, 1 x Masala Ch…" and hid the
   rest. The comp lists them, which is both what a receipt does and the
   thing you actually scan for when finding an old order. */
.order-card-lines {
    list-style: none;
    margin: 0 0 12px;
    padding: 0;
    display: grid;
    gap: 2px;
}
.order-card-lines li {
    font-size: 0.88rem;
    color: var(--color-ink);
    line-height: 1.5;
}
.order-card-lines .qty {
    font-family: var(--font-display);
    font-weight: 700;
    color: var(--color-ink-muted);
    margin-right: 0.35rem;
}
.order-card-lines .more {
    font-size: 0.82rem;
    color: var(--color-ink-muted);
}

/* The whole card is the link, so this is an affordance rather than a
   second target: it tells you the card is clickable without adding a
   nested interactive element inside an anchor. */
.order-card-track {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    margin-top: 12px;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.85rem;
    color: var(--color-primary);
}
.order-card-track i { font-size: 1rem; transition: transform 180ms ease; }
.order-card:hover .order-card-track i { transform: translateX(3px); }

.page-header-sub {
    margin: 0.35rem 0 0;
    color: var(--color-ink-muted);
    font-size: 0.95rem;
}

/* ============================================================
   ITEM DETAIL — ported from the Stitch "Dish Details" comp.

   The comp is mostly modifiers: Add Protein, Extras, Special
   Instructions, dietary tags, a favourite toggle. None of that exists
   on MenuItem, which carries name, category, photo, price and an
   optional discount and nothing else. So this page is the honest
   subset: a bigger photo, the price with its strike-through, where to
   collect it, and the add control. It is the right shape to hang
   modifiers on if they ever get modelled.
   ============================================================ */
/* The card name is now a link; it should not look like one until you
   reach for it, or every card in the grid turns into a wall of blue. */
.menu-card-name__link {
    color: inherit;
    text-decoration: none;
}
.menu-card-name__link:hover,
.menu-card-name__link:focus-visible {
    color: var(--color-accent-strong);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.detail-back {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin: 0.5rem 0 1rem;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.88rem;
    color: var(--color-ink-muted);
    text-decoration: none;
}
.detail-back:hover { color: var(--color-ink); }
.detail-back i { font-size: 1.05rem; transition: transform 180ms ease; }
.detail-back:hover i { transform: translateX(-3px); }

.detail-hero {
    position: relative;
    border-radius: var(--radius-lg);
    overflow: hidden;
    background: var(--color-surface-food);
    aspect-ratio: 16 / 10;
    margin-bottom: 1.25rem;
}
.detail-hero img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Illustrations are line art on a transparent ground, so cropping them to
   fill would cut the drawing; they get padded and contained instead. */
.detail-hero.is-illustration { background: var(--color-surface-deep); }
.detail-hero.is-illustration img { object-fit: contain; padding: 12%; }

.detail-eyebrow {
    font-family: var(--font-display);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--color-ink-muted);
    margin: 0 0 0.3rem;
}
.detail-name {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(1.7rem, 6vw, 2.2rem);
    line-height: 1.15;
    letter-spacing: -0.02em;
    color: var(--color-ink);
    margin: 0 0 0.5rem;
}
.detail-price {
    display: flex;
    align-items: baseline;
    gap: 0.6rem;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.5rem;
    color: var(--color-accent-strong);
    margin-bottom: 0.75rem;
}
.detail-meta {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--color-ink-muted);
    margin-bottom: 1.75rem;
}
.detail-meta i { color: var(--color-primary); font-size: 1.05rem; }

.detail-unavailable {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    background: var(--color-danger-tint);
    color: var(--color-danger);
    font-weight: 600;
    font-size: 0.92rem;
    border-radius: var(--radius-md);
    padding: 14px 16px;
    margin-bottom: 2rem;
}

.detail-add {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    margin-bottom: 2.5rem;
}
.detail-add__btn {
    flex: 1;
    padding: 0.9rem 1rem;
    font-size: 1rem;
    border-radius: var(--radius-md);
}

/* ============================================================
   ACCOUNT PAGE (sectioned list)
   ============================================================ */

.account-section {
    background: transparent;
    border: none;
    border-radius: 0;
    overflow: visible;
    margin-bottom: 24px;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.account-section-title {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-ink-muted);
    padding: 0 4px 8px;
}

.account-row {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 16px 20px;
    text-decoration: none;
    color: var(--color-ink);
    background: var(--color-surface-food);
    border-top: none;
    transition: background 120ms ease, transform 120ms ease;
    box-shadow: 0 2px 6px -2px rgba(70, 45, 25, 0.04);
}

/* Round only the outer corners of the stack so it reads as one grouped block */
.account-section-title + .account-row,
.account-section > .account-row:first-child {
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
.account-section > .account-row:last-child {
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}
.account-section > .account-row:only-of-type {
    border-radius: var(--radius-lg);
}

.account-row:hover {
    background: var(--color-surface-deep);
    color: var(--color-ink);
}
.account-row:active {
    background: var(--color-surface-deep);
}

.account-row i {
    font-size: 1.35rem;
    color: var(--color-accent-strong);
    width: 28px;
    text-align: center;
}

.account-row-content {
    flex: 1;
}

.account-row-label {
    font-weight: 700;
    font-size: 0.95rem;
}

.account-row-detail {
    font-size: 0.82rem;
    color: var(--color-ink-muted);
}

.account-row-chevron {
    color: var(--color-ink-muted);
    font-size: 1rem;
}

/* ============================================================
   SEARCH BAR (menu page — Foochi pill search)
   ============================================================ */

.search-bar {
    position: relative;
    margin-bottom: 20px;
}

.search-bar input {
    width: 100%;
    padding: 15px 18px 15px 50px;
    border: 1.5px solid transparent;
    border-radius: var(--radius-pill);
    background: var(--color-surface-food);
    font-size: 0.96rem;
    font-family: var(--font-body);
    color: var(--color-ink);
    box-shadow: 0 4px 12px -4px rgba(70, 45, 25, 0.08);
    transition: all 180ms ease;
}

.search-bar input:focus {
    border-color: var(--color-primary);
    background: var(--color-surface);
    box-shadow: 0 0 0 4px var(--color-primary-tint), 0 6px 18px -4px rgba(70, 45, 25, 0.1);
    outline: none;
}

.search-bar input::placeholder {
    color: var(--color-ink-muted);
}

.search-bar i {
    position: absolute;
    left: 20px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--color-ink-muted);
    font-size: 1.2rem;
    pointer-events: none;
}

/* ============================================================
   PRICE DISPLAY
   ============================================================ */

.card-price {
    font-family: var(--font-display);
    font-weight: 700;
}

.price-strike {
    text-decoration: line-through;
    color: var(--color-ink-muted);
    font-size: 0.85em;
    margin-right: 0.4em;
    opacity: 0.75;
}

.token-badge {
    font-family: var(--font-display);
    font-weight: 800;
    letter-spacing: 0.03em;
}

.list-group-item {
    border-color: var(--color-border);
}
.list-group-item-action:hover {
    background: var(--color-primary-tint);
}

/* ============================================================
   AUTH PAGES — split panel on desktop, single column on mobile.

   A 420px card centred in ~1400px of cream left the whole right and left
   thirds doing nothing. The brief asked to use width intentionally at
   large sizes, so desktop gets a peach brand panel beside the form. The
   form itself sits directly on the canvas at every size now — no card —
   which also permanently removes the bug where an input painted the same
   colour as the card it sat on became invisible.
   ============================================================ */

.auth-shell {
    min-height: 100dvh;
    display: grid;
    grid-template-columns: 1fr;
    background: var(--color-bg);
}

.auth-main {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2.5rem 1.25rem 3rem;
}

.auth-card {
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: 400px;
    background: transparent;
    border: none;
    border-radius: 0;
    box-shadow: none;
    padding: 0;
}

/* Compact lockup above the form — carries the brand on mobile, where the
   brand panel is hidden. */
.auth-lockup {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    margin-bottom: 1.75rem;
}
.auth-lockup img { width: 34px; height: 34px; }
.auth-lockup span {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.3rem;
    color: var(--color-accent-strong);
}

.auth-kicker {
    display: inline-block;
    font-family: var(--font-display);
    font-size: 0.74rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--color-accent-strong);
    background: var(--color-accent-tint);
    padding: 0.35rem 0.85rem;
    border-radius: var(--radius-pill);
    margin-bottom: 0.75rem;
}

/* ============================================================
   EDITORIAL AUTH FIELDS — ported from the Stitch "Sign In" comp.

   The comp's one real idea is that form fields stop being boxes.
   Bootstrap's .input-group draws an icon tile, a 1px border and a white
   fill around every field: three pieces of chrome on a page that only
   asks two questions. The comp replaces all of it with a single hairline
   under the text, so the screen reads as type on cream rather than
   widgets on a card.

   The field icons come off entirely. An envelope glyph beside a field
   labelled "Email" is decoration, and it was the thing forcing the boxed
   treatment in the first place.

   Scoped to .auth-card so the canteen and admin portals — same
   stylesheet, deliberately not part of this redesign — keep their dense
   bordered forms.
   ============================================================ */
.auth-head { margin-bottom: 2rem; }
.auth-head__title {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(1.9rem, 7vw, 2.35rem);
    line-height: 1.12;
    letter-spacing: -0.02em;
    color: var(--color-ink);
    margin: 0 0 0.4rem;
}
.auth-head__sub {
    font-size: 0.95rem;
    color: var(--color-ink-muted);
    margin: 0;
}

.field { margin-bottom: 1.4rem; }
.field__label {
    display: block;
    font-family: var(--font-display);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--color-ink-muted);
    margin-bottom: 0.35rem;
}
.field__wrap { position: relative; }
.field__input {
    width: 100%;
    background: transparent;
    border: 0;
    border-bottom: 1.5px solid var(--color-field-rule);
    border-radius: 0;
    padding: 0.5rem 0;
    font-family: var(--font-body);
    font-size: 1.05rem;
    color: var(--color-ink);
    transition: border-color 0.18s ease;
}
/* 0.55 dropped the placeholder to 2.42:1. Every field here already has a
   visible label, so the placeholder is supplementary — but it is still text,
   and 1.4.3 does not exempt it. 0.85 resolves to #806E5D at 4.51:1. */
.field__input::placeholder { color: var(--color-ink-muted); opacity: 0.85; }
/* Focus is carried by the rule itself rather than a ring, to keep the
   field flat. Thickening to 2px means it still reads for anyone who
   can't rely on the hue change alone; the padding claws back the 0.5px
   so the baseline doesn't hop. */
.field__input:focus {
    outline: none;
    box-shadow: none;
    border-bottom-color: var(--color-primary);
    border-bottom-width: 2px;
    padding-bottom: calc(0.5rem - 0.5px);
}
/* Chrome paints autofilled inputs pale blue, which on a transparent
   field shows up as a floating blue slab. */
.field__input:-webkit-autofill,
.field__input:-webkit-autofill:focus {
    -webkit-text-fill-color: var(--color-ink);
    -webkit-box-shadow: 0 0 0 100px var(--color-bg) inset;
}
.field__input--pw { padding-right: 2.75rem; }
.field__toggle {
    position: absolute;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    background: none;
    border: 0;
    padding: 0.4rem;
    line-height: 1;
    color: var(--color-ink-muted);
    cursor: pointer;
}
.field__toggle:hover, .field__toggle:focus-visible { color: var(--color-ink); }
.field__toggle i { font-size: 1.15rem; }

/* Select gets the same underline treatment. Bootstrap's .form-select paints
   its own border, fill and arrow, so all three are stripped and the chevron
   is redrawn inline in --color-ink-muted to match the field text. */
.field__select {
    width: 100%;
    background-color: transparent;
    border: 0;
    border-bottom: 1.5px solid var(--color-field-rule);
    border-radius: 0;
    padding: 0.5rem 1.75rem 0.5rem 0;
    font-family: var(--font-body);
    font-size: 1.05rem;
    color: var(--color-ink);
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%236A5644' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.15rem center;
    background-size: 1rem;
    transition: border-color 0.18s ease;
}
.field__select:focus {
    outline: none;
    box-shadow: none;
    border-bottom-color: var(--color-primary);
    border-bottom-width: 2px;
    padding-bottom: calc(0.5rem - 0.5px);
}
/* The "choose one" placeholder option should read as unfilled, like a
   placeholder does, rather than as a real selection. */
.field__select:has(option[value=""]:checked) { color: #806E5D; }

/* "(Optional)" sits with the label rather than in the field, so the field
   itself stays clean. Lowercase against the uppercase label so it reads as
   an aside and not part of the field name. */
.field__optional {
    text-transform: none;
    letter-spacing: 0;
    font-weight: 500;
    font-size: 0.72rem;
    opacity: 0.75;
    margin-left: 0.4rem;
}

.field__hint {
    margin: 0.4rem 0 0;
    font-size: 0.8rem;
    color: var(--color-ink-muted);
}

/* Validation copy. --color-danger is 5.11:1 on cream, so it carries as text
   without a tinted box behind it. */
.field__error {
    margin: 0.4rem 0 0;
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--color-danger);
}
/* A field that failed validation says so on the rule too, not by colour
   alone — the message below it is the non-colour cue. */
.field__input.is-invalid,
.field__select.is-invalid {
    border-bottom-color: var(--color-danger);
    border-bottom-width: 2px;
    padding-bottom: calc(0.5rem - 0.5px);
}

/* The comp runs a ~56px CTA. That height is what makes a two-field form
   feel finished rather than cramped. */
.btn-auth {
    width: 100%;
    padding: 0.95rem 1rem;
    font-size: 1rem;
    border-radius: var(--radius-md);
}

.auth-foot {
    margin-top: 1.75rem;
    text-align: center;
    font-size: 0.92rem;
    color: var(--color-ink-muted);
}
.auth-foot a { font-weight: 700; }
.auth-legal {
    margin-top: 0.85rem;
    text-align: center;
    font-size: 0.78rem;
}


/* ---------- Brand panel (desktop only) ---------- */

.auth-brand { display: none; }

@media (min-width: 992px) {
    .auth-shell { grid-template-columns: 1.05fr 1fr; }

    .auth-brand {
        display: flex;
        align-items: center;
        padding: 4rem 3.5rem;
        background: var(--color-surface-food);
        position: relative;
        overflow: hidden;
    }

    /* Oversized brand mark bled off the corner — the identity as pattern
       rather than a logo sitting politely in a box. */
    .auth-brand::after {
        content: '';
        position: absolute;
        right: -14%;
        bottom: -18%;
        width: 62%;
        aspect-ratio: 1;
        background: url('/img/logo-mark-pastel.svg') center / contain no-repeat;
        opacity: 0.32;
        pointer-events: none;
    }

    .auth-lockup { display: none; }
}

.auth-brand__inner { position: relative; z-index: 1; max-width: 420px; }

.auth-brand__lockup {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-bottom: 2.5rem;
}
.auth-brand__lockup img { width: 40px; height: 40px; }
.auth-brand__lockup span {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.55rem;
    color: var(--color-accent-strong);
}

.auth-brand__headline {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 2.6rem;
    line-height: 1.12;
    color: var(--color-ink);
    margin: 0 0 1rem;
}

.auth-brand__sub {
    font-size: 1.02rem;
    color: var(--color-ink-muted);
    margin: 0 0 2.5rem;
    max-width: 34ch;
}

/* Three dishes on the brand panel, so the first screen of a food app
   actually shows food. */
.auth-brand__dishes { display: flex; gap: 0.9rem; }

.auth-brand__dish {
    width: 92px;
    height: 92px;
    border-radius: var(--radius-md);
    background: var(--color-bg);
    display: grid;
    place-items: center;
    padding: 12px;
}
.auth-brand__dish img { width: 100%; height: 100%; object-fit: contain; }

/* The middle tile used to be lifted 14px as a staggered flourish, which suited the old
   peach panel. On the flat one it just reads as a tile that failed to line up, so the
   row is level now. */

/* These three illustrations are not the same shape: the chai is portrait (202x320)
   while the dosa and puff are landscape (320x215, 320x193). object-fit: contain sizes
   each to the tile, so the portrait one alone fills the full height and lands about 50%
   taller than its neighbours — level with them, but visually looming. Capping its height
   matches the optical weight of the other two rather than their bounding boxes.

   Tagged by class rather than :nth-child so it stays correct if the dishes are
   reordered, which the position-based rule did not. */
.auth-brand__dish--portrait img { max-height: 72%; }

/* ---------- Password visibility toggle ---------- */

.toggle-password {
    border: 1.5px solid var(--color-field-border) !important;
    border-left: none !important;
    background: var(--color-field) !important;
    color: var(--color-ink-muted) !important;
}
.toggle-password:hover {
    color: var(--color-ink) !important;
    background: var(--color-field) !important;
}
.toggle-password:focus-visible {
    z-index: 3;
}
