html, body {
    font-family: 'Inter', 'Helvetica Neue', Helvetica, Arial, sans-serif;
    height: 100%;
    overflow: hidden; /* the document itself never scrolls — .body-container is the one and only scroll container */
}

/* Make all buttons flex containers so icons center by layout, not line-box math.
   min-height matches Bootstrap's form-control height so icon-only buttons (which shrink
   to icon height via line-height:1 on .btn .bi) stay the same height as adjacent inputs. */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: calc(1.5em + 0.75rem + 2px); /* = form-control height */
    gap: 0.375em;
}

/* Bootstrap Icons render the glyph via ::before as inline-block with vertical-align:-.125em.
   Flexbox on the button only centers the <i> element, not the glyph inside it.
   Making <i> itself a flex container turns ::before into a flex item where vertical-align is ignored,
   so the glyph is centered by layout rather than font metrics. */
.btn .bi {
    display: inline-flex;
    align-items: center;
    line-height: 1;
}

/* Add-to-meal-plan picker rows: override .btn's centered justify-content so the
   thumbnail/icon and name are left-aligned. */
.api-item-btn {
    justify-content: flex-start;
}

/* Icon-only buttons: equal padding on all sides, 36px touch target.
   Override Bootstrap's CSS custom properties so var(--bs-btn-padding-x/y)
   resolves to the same value, making buttons square regardless of btn-sm etc. */
.btn.btn-icon {
    --bs-btn-padding-x: 0.375rem;
    --bs-btn-padding-y: 0.375rem;
    padding: 0.375rem;
    min-width: 2.25rem;
    min-height: 2.25rem;
}

/* Meal detail's primary actions (cook / undo cook / add item). They sit with the
   meal header rather than the bottom of the page, and are the main touch targets on
   the fridge, so they get the full 48px minimum rather than btn-icon's 36px. */
.meal-actions .btn {
    min-height: 3rem;
    --bs-btn-padding-x: 0.75rem;
    padding-left: 0.75rem;
    padding-right: 0.75rem;
}

/* Fixed width for the pantry grid's Actions column so it doesn't shift
   between collapsed rows (2 buttons) and expanded item rows (5 buttons). */
.pantry-actions-col {
    width: 14rem;
}

/* QuantityStepper: hide the tiny native number spinner and replace it with - / +
   buttons sized to match the row's other icon buttons (e.g. the delete button).
   The stepper fills its column; the input flexes between the two buttons. */
.quantity-stepper {
    flex-wrap: nowrap;
    width: 100%;
}

.quantity-stepper-btn {
    flex: 0 0 auto;
    min-width: 2rem;
}

.quantity-stepper-input {
    min-width: 2.5rem;
    -moz-appearance: textfield;
    appearance: textfield;
}

.quantity-stepper-input::-webkit-outer-spin-button,
.quantity-stepper-input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

/* Ingredient editor table: keep Qty/Unit/actions tight so the free-text
   Ingredient and Preparation columns get the width instead. */
.recipe-ingredient-table .col-qty {
    width: 8.5rem;
}

.recipe-ingredient-table .col-unit {
    width: 6rem;
}

.recipe-ingredient-table .col-actions {
    width: 5.5rem;
}

/* An imported line that didn't read as food. Outlined rather than dimmed: it is asking
   for a decision, and it is dropped on save unless the cook keeps it.

   Every side needs !important. atebit-theme.css forces `border-bottom-color` on every
   table cell with !important of its own, to undo the inset box-shadow Bootstrap 5 paints
   cells with, and !important beats specificity however specific this selector gets. The
   first version of this rule left the box open at the bottom: three red sides and a
   fourth silently repainted the theme's border colour. The other three sides are marked
   the same way so the rule cannot half-survive a future theme change. */
.recipe-ingredient-table tr.recipe-ingredient-unconfirmed td {
    border-top: 2px solid var(--bs-danger) !important;
    border-bottom: 2px solid var(--bs-danger) !important;
}

.recipe-ingredient-table tr.recipe-ingredient-unconfirmed td:first-child {
    border-left: 2px solid var(--bs-danger) !important;
}

.recipe-ingredient-table tr.recipe-ingredient-unconfirmed td:last-child {
    border-right: 2px solid var(--bs-danger) !important;
}

.content {
    padding-top: 1.1rem;
}

h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1zPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBvdmVyZmxvdz0iaGlkZGVuIj48ZGVmcz48Y2xpcFBhdGggaWQ9ImNsaXAwIj48cmVjdCB4PSIyMzUiIHk9IjUxIiB3aWR0aD0iNTYiIGhlaWdodD0iNDkiLz48L2NsaXBQYXRoPjwvZGVmcz48ZyBjbGlwLXBhdGg9InVybCgjY2xpcDApIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjM1IC01MSkiPjxwYXRoIGQ9Ik0yNjMuNTA2IDUxQzI2NC43MTcgNTEgMjY1LjgxMyA1MS40ODM3IDI2Ni42MDYgNTIuMjY1OEwyNjcuMDUyIDUyLjc5ODcgMjY3LjUzOSA1My42MjgzIDI5MC4xODUgOTIuMTgzMSAyOTAuNTQ1IDkyLjc5NSAyOTAuNjU2IDkyLjk5NkMyOTAuODc3IDkzLjUxMyAyOTEgOTQuMDgxNSAyOTEgOTQuNjc4MiAyOTEgOTcuMDY1MSAyODkuMDM4IDk5IDI4Ni42MTcgOTlMMjQwLjM4MyA5OUMyMzcuOTYzIDk5IDIzNiA5Ny4wNjUxIDIzNiA5NC42NzgyIDIzNiA5NC4zNzk5IDIzNi4wMzEgOTQuMDg4NiAyMzYuMDg5IDkzLjgwNzJMMjM2LjMzOCA5My4wMTYyIDIzNi44NTggOTIuMTMxNCAyNTkuNDczIDUzLjYyOTQgMjU5Ljk2MSA1Mi43OTg1IDI2MC40MDcgNTIuMjY1OEMyNjEuMiA1MS40ODM3IDI2Mi4yOTYgNTEgMjYzLjUwNiA1MVpNMjYzLjU4NiA2Ni4wMTgzQzI2MC43MzcgNjYuMDE4MyAyNTkuMzEzIDY3LjEyNDUgMjU5LjMxMyA2OS4zMzcgMjU5LjMxMyA2OS42MTAyIDI1OS4zMzIgNjkuODYwOCAyNTkuMzcxIDcwLjA4ODdMMjYxLjc5NSA4NC4wMTYxIDI2NS4zOCA4NC4wMTYxIDI2Ny44MjEgNjkuNzQ3NSAyNjcuODYgNjkuNzMwOSAyNjcuODc5IDY5LjU4NzcyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

/* Admin impersonation banner (AB#978): an in-flow bar at the very top of the page - above the nav bar
   (AB#1078) - shown on every page while a platform admin is viewing as another member. Because it pushes
   the nav bar down by its own height, the fixed nav fold-out menu and backdrop are re-anchored via
   --nav-overlay-top below, and the scroll container's max-height is reduced by the same height so nothing
   is clipped. */
.impersonating {
    --nav-overlay-top: calc(3.5rem + 3rem); /* nav height + impersonation-banner min-height */
}

.impersonation-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    min-height: 3rem;
    padding: 0.25rem 0.75rem;
    background-color: #b45309; /* amber-700 — high-contrast, clearly not a normal chrome colour */
    color: #fff;
    font-size: 0.9rem;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35);
    z-index: 900;
}

.impersonation-banner-text {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.impersonation-banner-form {
    margin: 0;
    flex-shrink: 0;
}

.impersonation-banner-exit {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    min-height: 2.5rem;
    padding: 0.375rem 0.75rem;
    background-color: rgba(0, 0, 0, 0.25);
    color: #fff;
    border: 1px solid rgba(255, 255, 255, 0.6);
    border-radius: 4px;
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
}

.impersonation-banner-exit:hover {
    background-color: rgba(0, 0, 0, 0.4);
}

/* Reclaim the banner's height from the one scroll container so its bottom isn't clipped. */
.impersonating .body-container {
    max-height: calc(100vh - 4.6rem - 3rem);
}

/* Local-only dev sign-in bypass banner (AB#710). Development + direct-localhost only, so it never
   renders on a deployed instance. Distinct hazard colour so a bypassed session is never mistaken for
   a real one. */
.local-dev-bypass-banner {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 2.25rem;
    padding: 0.25rem 0.75rem;
    background-color: #6d28d9; /* violet-700 — distinct from the amber impersonation banner */
    color: #fff;
    font-size: 0.85rem;
    font-weight: 600;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35);
    z-index: 900;
}

/* Dev-only shortcut to the authenticated home, shown on the anonymous landing over direct localhost
   (AB#710). Fixed to a corner so it overlays the marketing landing without disturbing its layout. */
.local-dev-login-link {
    position: fixed;
    top: 0.75rem;
    right: 0.75rem;
    z-index: 1000;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.4rem 0.75rem;
    min-height: 2.25rem;
    background-color: #6d28d9; /* matches the bypass banner */
    color: #fff;
    font-size: 0.85rem;
    font-weight: 600;
    text-decoration: none;
    border-radius: 4px;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35);
}

.local-dev-login-link:hover {
    background-color: #5b21b6; /* violet-800 */
    color: #fff;
}

/* Admin member-directory search box: cap the width so it sits neatly in the card header. */
.impersonate-search {
    max-width: 18rem;
}

/* Idle-timeout overlay shown once the client disconnects an inactive Blazor circuit (AB#1160).
   Covers the full viewport since the app underneath is inert (circuit is down) - "click
   anywhere" needs the whole screen as the target. Styled as an arcade "PAUSED" screen to match
   the arcade theme (AB#959).

   z-index note: Blazor.pauseCircuit() closes the SignalR transport, which triggers this
   app's built-in Blazor reconnect UI (#components-reconnect-modal) - an unstyled white
   "Resume" dialog rendered inside an open shadow root at z-index 10001. That state lives
   entirely inside the shadow tree (the host div itself carries no distinguishing class or
   attribute), so it can't be targeted/suppressed from outside via a state-specific CSS
   selector. Instead of hiding it, out-stack it: keep our z-index above 10001 so this overlay
   fully covers it, and since our click-to-reconnect handler is a document-level listener
   (idleTimeout.js), clicks land on us regardless of paint order - the native "Resume" button
   underneath never becomes the actual click target. Leave the native modal itself alone so
   genuine network-drop reconnection UI unrelated to idle timeout still renders normally. */
.idle-timeout-banner {
    position: fixed;
    inset: 0;
    z-index: 10010;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1.25rem;
    padding: 1rem;
    background: radial-gradient(ellipse at center, rgba(20, 26, 46, 0.96) 0%, rgba(6, 8, 16, 0.98) 70%);
    color: #fff;
    text-align: center;
    cursor: pointer;
    overflow: hidden;
}

/* CRT scanline overlay, painted behind the content (default stacking order for a
   position-less child following a positioned ::before). */
.idle-timeout-banner::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: repeating-linear-gradient(
        to bottom,
        rgba(0, 0, 0, 0) 0px,
        rgba(0, 0, 0, 0) 2px,
        rgba(0, 212, 255, 0.04) 3px,
        rgba(0, 0, 0, 0) 4px
    );
    mix-blend-mode: overlay;
}

.idle-pause-icon {
    display: flex;
    gap: 0.5rem;
}

.idle-pause-icon span {
    width: 0.9rem;
    height: 3rem;
    background: var(--color-cyan);
    box-shadow: 0 0 10px rgba(0, 212, 255, 0.8), 0 0 24px rgba(0, 212, 255, 0.5);
    animation: idle-pause-flicker 2.4s ease-in-out infinite;
}

.idle-pause-icon span:last-child {
    animation-delay: 0.15s;
}

@keyframes idle-pause-flicker {
    0%, 100% { opacity: 1; }
    92%      { opacity: 1; }
    94%      { opacity: 0.4; }
    96%      { opacity: 1; }
}

.idle-pause-title {
    position: relative;
    font-family: 'Press Start 2P', 'Space Grotesk', system-ui, sans-serif;
    font-size: clamp(2.25rem, 8vw, 4.5rem);
    letter-spacing: 0.15em;
    color: #fff;
    text-shadow: 0 0 10px rgba(255, 255, 255, 0.6), 0 0 30px rgba(0, 212, 255, 0.5);
    margin: 0;
}

/* RGB-split glitch: two color copies of the same text, clipped to opposite halves and
   jittered on independent loops so they never quite line up with the white base layer. */
.idle-pause-title::before,
.idle-pause-title::after {
    content: attr(data-text);
    position: absolute;
    inset: 0;
    background: transparent;
}

.idle-pause-title::before {
    color: var(--color-cyan);
    clip-path: inset(0 0 55% 0);
    animation: idle-glitch-a 3.2s infinite linear alternate-reverse;
}

.idle-pause-title::after {
    color: var(--color-magenta);
    clip-path: inset(55% 0 0 0);
    animation: idle-glitch-b 2.6s infinite linear alternate-reverse;
}

@keyframes idle-glitch-a {
    0%   { transform: translate(0, 0); }
    20%  { transform: translate(-2px, -1px); }
    40%  { transform: translate(2px, 1px); }
    60%  { transform: translate(-1px, 1px); }
    80%  { transform: translate(1px, -1px); }
    100% { transform: translate(0, 0); }
}

@keyframes idle-glitch-b {
    0%   { transform: translate(0, 0); }
    25%  { transform: translate(2px, 1px); }
    50%  { transform: translate(-2px, -1px); }
    75%  { transform: translate(1px, -1px); }
    100% { transform: translate(0, 0); }
}

.idle-pause-subtitle {
    font-family: 'Press Start 2P', 'Space Grotesk', system-ui, sans-serif;
    font-size: clamp(0.6rem, 2vw, 0.85rem);
    letter-spacing: 0.05em;
    color: var(--color-magenta);
    text-shadow: 0 0 8px rgba(200, 80, 192, 0.6);
}

.idle-cursor {
    animation: idle-blink 1s steps(1) infinite;
}

@keyframes idle-blink {
    0%, 50%      { opacity: 1; }
    50.01%, 100% { opacity: 0; }
}

.idle-reconnect {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.idle-reconnect-text {
    font-family: 'Press Start 2P', 'Space Grotesk', system-ui, sans-serif;
    font-size: clamp(0.6rem, 2vw, 0.8rem);
    letter-spacing: 0.05em;
    color: var(--color-cyan);
    text-shadow: 0 0 8px rgba(0, 212, 255, 0.6);
}

@media (prefers-reduced-motion: reduce) {
    .idle-pause-icon span,
    .idle-pause-title::before,
    .idle-pause-title::after,
    .idle-cursor {
        animation: none;
    }
}

.body-container {
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - 4.6rem); /* 3.5rem navbar + 1.1rem content padding-top — max, not fixed, so short pages don't overflow/scroll unnecessarily */
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch; /* momentum touch-scroll on older iOS Safari (iPad target); ignored by the fridge's Chromium engine */
    padding-bottom: 2rem; /* a bit of headroom against near-boundary pages tipping into a 1-2px phantom scrollbar */
    /* Push our own scrollbar out to the true window edge (canceling article.content's
       px-4 right padding) instead of leaving it inset, then restore the same visual
       gap from our own padding so content still has breathing room before the scrollbar. */
    margin-right: -1.5rem;
    padding-right: 1.5rem;
    scrollbar-width: thin; /* Firefox */
    scrollbar-color: var(--color-border) transparent; /* Firefox */
}

.body-container::-webkit-scrollbar {
    width: 10px;
}

.body-container::-webkit-scrollbar-track {
    background: transparent;
}

.body-container::-webkit-scrollbar-thumb {
    background-color: var(--color-border);
    border-radius: 6px;
}

.body-container::-webkit-scrollbar-thumb:hover {
    background-color: var(--color-text-muted);
}

.table-responsive {
    flex: 1;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
}

.table-container {
    flex: 1;
    overflow-y: auto;
    min-height: 250px; /* Set a minimum height to prevent collapse */
}

.table thead {
    position: sticky;
    top: 0;
    background-color: var(--color-bg-subtle);
    outline: 1px solid var(--color-border);
    z-index: 1;
}

.table tr {
    height: 48px;
}

.table tbody td {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: middle;
}

.badge-expiry-expired { background-color: rgba(255, 77, 106, 0.18); color: #FF8FA3; border: 1px solid rgba(255, 77, 106, 0.3); }
.badge-expiry-soon    { background-color: rgba(245, 158, 11, 0.18); color: #FBB03B; border: 1px solid rgba(245, 158, 11, 0.3); }
.badge-expiry-good    { background-color: var(--color-bg-elevated); color: var(--color-text-secondary); border: 1px solid var(--color-border); }

.recipe-tag { background-color: rgba(0, 212, 255, 0.12); color: var(--color-cyan); border: 1px solid rgba(0, 212, 255, 0.25); font-weight: normal; }

/* Recipe badges */
.badge-draft { background-color: rgba(245, 158, 11, 0.2); color: #FBB03B; border: 1px solid rgba(245, 158, 11, 0.3); }
.badge-shared { background-color: rgba(0, 212, 255, 0.15); color: var(--color-cyan); border: 1px solid rgba(0, 212, 255, 0.3); }
.badge-recipe-meta { background-color: var(--color-bg-elevated); color: var(--color-text-secondary); border: 1px solid var(--color-border); }
.badge-recipe-total { background-color: rgba(0, 212, 255, 0.15); color: var(--color-cyan); border: 1px solid rgba(0, 212, 255, 0.3); }
.badge-recipe-category { background-color: var(--color-bg-elevated); color: var(--color-text-secondary); border: 1px solid var(--color-border); }
.badge-recipe-source { background-color: var(--color-bg-elevated); color: var(--color-text-muted); border: 1px solid var(--color-border); }
.badge-recipe-category-chip { background-color: rgba(0, 212, 255, 0.15); color: var(--color-cyan); border: 1px solid rgba(0, 212, 255, 0.3); }
.badge-share-count { background-color: var(--color-bg-elevated); color: var(--color-text-secondary); border: 1px solid var(--color-border); }
.badge-cook-history-item { background-color: var(--color-bg-elevated); color: var(--color-text-secondary); border: 1px solid var(--color-border); }
.cook-history-table { table-layout: fixed; width: 100%; }
.cook-history-recipe-group-header td { background-color: var(--color-bg-elevated); font-weight: 600; color: var(--color-text-primary); border-top: 2px solid var(--color-border); padding-top: 0.5rem; padding-bottom: 0.5rem; font-family: 'Space Grotesk', system-ui, sans-serif; }
.recycle-table { table-layout: fixed; width: 100%; }
.recycle-table .col-name { width: auto; }
.recycle-table .col-date { width: 130px; }
.recycle-table .col-actions { width: 100px; }

/* Brand / ingredient rule badges */
.badge-ai { background-color: rgba(200, 80, 192, 0.15); color: var(--color-magenta); border: 1px solid rgba(200, 80, 192, 0.3); }
.badge-manual { background-color: var(--color-bg-elevated); color: var(--color-text-secondary); border: 1px solid var(--color-border); }
.badge-needs-review { background-color: rgba(245, 158, 11, 0.18); color: #FBB03B; border: 1px solid rgba(245, 158, 11, 0.3); }

/* Household member badges */
.badge-email { background-color: var(--color-bg-elevated); color: var(--color-text-secondary); border: 1px solid var(--color-border); }

/* Grocery store editor */
.badge-store-filter { background-color: var(--color-bg-elevated); color: var(--color-text-secondary); border: 1px solid var(--color-border); }

/* Category type badges */
.badge-category-product { background-color: rgba(0, 212, 255, 0.15); color: var(--color-cyan); border: 1px solid rgba(0, 212, 255, 0.3); }
.badge-category-recipe { background-color: var(--color-bg-elevated); color: var(--color-text-secondary); border: 1px solid var(--color-border); }

/* Feedback category badges */
.badge-feedback-bug { background-color: rgba(255, 77, 106, 0.18); color: #FF8FA3; border: 1px solid rgba(255, 77, 106, 0.3); }
.badge-feedback-suggestion { background-color: rgba(0, 212, 255, 0.15); color: var(--color-cyan); border: 1px solid rgba(0, 212, 255, 0.3); }
.badge-feedback-store-request { background-color: rgba(0, 212, 255, 0.12); color: var(--color-cyan); border: 1px solid rgba(0, 212, 255, 0.25); }
.badge-feedback-other { background-color: var(--color-bg-elevated); color: var(--color-text-secondary); border: 1px solid var(--color-border); }

/* Feedback status badges */
.badge-feedback-resolved { background-color: rgba(0, 212, 255, 0.12); color: var(--color-cyan); border: 1px solid rgba(0, 212, 255, 0.25); }
.badge-feedback-open { background-color: rgba(245, 158, 11, 0.18); color: #FBB03B; border: 1px solid rgba(245, 158, 11, 0.3); }
.badge-feedback-triaged { background-color: rgba(139, 92, 246, 0.18); color: #B79CFF; border: 1px solid rgba(139, 92, 246, 0.35); }
a.badge-feedback-triaged:hover { background-color: rgba(139, 92, 246, 0.3); color: #CDBEFF; }

/* Cook history deduction status badges */
.badge-deduction-deducted { background-color: rgba(0, 212, 255, 0.12); color: var(--color-cyan); border: 1px solid rgba(0, 212, 255, 0.25); }
.badge-deduction-not-found { background-color: var(--color-bg-elevated); color: var(--color-text-secondary); border: 1px solid var(--color-border); }
.badge-deduction-insufficient { background-color: rgba(245, 158, 11, 0.18); color: #FBB03B; border: 1px solid rgba(245, 158, 11, 0.3); }
.badge-deduction-incompatible { background-color: rgba(255, 77, 106, 0.18); color: #FF8FA3; border: 1px solid rgba(255, 77, 106, 0.3); }
.badge-deduction-skipped { background-color: var(--color-bg-elevated); color: var(--color-text-muted); border: 1px solid var(--color-border); }
.badge-deduction-unknown { background-color: var(--color-bg-elevated); color: var(--color-text-secondary); border: 1px solid var(--color-border); }

/* Low-confidence ingredient match badge */
.badge-match-low-confidence { background-color: rgba(245, 158, 11, 0.18); color: #FBB03B; border: 1px solid rgba(245, 158, 11, 0.3); }

.w-10 { width: 10%; }
.w-15 { width: 15%; }
.w-35 { width: 35%; }
.w-40 { width: 40%; }
.w-45 { width: 45%; }

.table-footer {
    background-color: var(--color-bg-subtle);
    padding: 10px;
    border-top: 1px solid var(--color-border);
    color: var(--color-text-secondary);
}

.brand-logo {
    width: auto;
    height: 100%;
    max-height: 40px;
    object-fit: scale-down;
    display: block;
    margin: auto;
}

input[type=search] {
    width: 20rem;
    padding: 0.75rem 0.75rem 0.75rem 2.5rem;
    color: var(--color-text-primary);
    background-color: var(--color-bg-subtle);
    border: 1px solid var(--color-border);
    border-radius: 0.5rem;
}

.search-box {
    position: relative;
}

    .search-box:before {
        content: '';
        width: 1.25rem;
        height: 1.25rem;
        position: absolute;
        left: .75rem;
        top: calc(50% - 0.625rem);
        background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z');
        background-size: contain;
        background-repeat: no-repeat;
    }

.badge {
    display: inline-flex;
    align-items: center;
    width: fit-content;
    padding: 0.5rem 1rem;
    border-radius: 1rem;
}

    .badge .btn-close {
        padding: 0.2rem;
        margin-left: 0.5rem;
    }

/* ── Tab count badge (superscript circle) ───────────────────── */
.tab-badge {
    font-size: 0.72rem;
    font-weight: 600;
    background-color: var(--color-bg-elevated);
    color: var(--color-text-secondary);
    border-radius: 50%;
    min-width: 1.5em;
    height: 1.5em;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    vertical-align: super;
    margin-left: 4px;
    line-height: 1;
    padding: 0;
}

/* ── Build version indicator ────────────────────────────────── */

.nav-version {
    padding: 0.5rem 1rem;
    font-size: 0.7rem;
    opacity: 0.4;
    color: #fff;
}

/* ── Recipe editor: fixed dialog height ───────────────── */
/* Scoped to .recipe-editor-dialog (CssClass on ComponentAsDialogOptions)  */
/* so other ExtraLarge dialogs (e.g. ReceiptReviewDialog) size naturally.  */
.recipe-editor-dialog .blazor-dialog-content-wrapper-xlarge {
    height: 940px;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

/* Flex chain: wrapper → content → form → header/body/footer */
.recipe-editor-dialog .blazor-dialog-content-wrapper-xlarge .blazor-dialog-content,
.recipe-editor-dialog .blazor-dialog-content-wrapper-xlarge .blazor-dialog-content > form {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    margin: 0;
}

.recipe-editor-dialog .blazor-dialog-content-wrapper-xlarge .blazor-dialog-header,
.recipe-editor-dialog .blazor-dialog-content-wrapper-xlarge .blazor-dialog-footer {
    flex-shrink: 0;
}

/* Dialog body is a flex column: nav-tabs pinned at top, tab content scrolls.
   No sticky needed — avoids the peekaboo where content bleeds above sticky tabs. */
.recipe-editor-dialog .blazor-dialog-content-wrapper-xlarge .blazor-dialog-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

.recipe-editor-dialog .blazor-dialog-content-wrapper-xlarge .blazor-dialog-body > .nav-tabs {
    flex-shrink: 0;
}

.recipe-editor-dialog .blazor-dialog-content-wrapper-xlarge .recipe-tab-content {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 2px 4px 4px 4px;
}

/* ── Pantry item editor: fixed 860px dialog height ─────────── */
/* Same flex approach as recipe editor, scoped via CssClass.    */
.pantry-item-dialog .blazor-dialog-content-wrapper-large {
    height: 860px;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

.pantry-item-dialog .blazor-dialog-content-wrapper-large .blazor-dialog-content,
.pantry-item-dialog .blazor-dialog-content-wrapper-large .blazor-dialog-content > form {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    margin: 0;
}

.pantry-item-dialog .blazor-dialog-content-wrapper-large .blazor-dialog-header,
.pantry-item-dialog .blazor-dialog-content-wrapper-large .blazor-dialog-footer {
    flex-shrink: 0;
}

.pantry-item-dialog .blazor-dialog-content-wrapper-large .blazor-dialog-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

.pantry-item-dialog .blazor-dialog-content-wrapper-large .blazor-dialog-body > .nav-tabs {
    flex-shrink: 0;
}

.pantry-item-dialog .blazor-dialog-content-wrapper-large .pantry-tab-content {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 2px 4px 0 4px;
}

/* ── Soft-keyboard dialog fix ───────────────────────────────── */
/* Samsung Internet keyboard is a true overlay — JS can't detect */
/* its height. Solution: on mobile, anchor the dialog to the top */
/* of the screen with a large bottom padding so the container is */
/* scrollable. The user can drag the whole dialog up above the   */
/* keyboard, and the body scrolls for long content within it.    */

@media (max-width: 800px) {
    .blazor-dialog-container {
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none; /* hide scrollbar so it doesn't shift content */
    }

    .blazor-dialog-container::-webkit-scrollbar {
        display: none;
    }

    /* Switch from flex-centered to block so dialog sits at top */
    .blazor-dialog-centered {
        display: block !important;
        padding: 1rem 0 50vh;
    }

    .blazor-dialog-content-wrapper {
        margin: 0 auto;
        max-height: 70vh;
        display: flex;
        flex-direction: column;
    }

    .blazor-dialog-content {
        display: flex;
        flex-direction: column;
        min-height: 0;
        max-height: 100%;
    }

    .blazor-dialog-body {
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        flex: 1 1 auto;
        min-height: 0;
    }
}


/* Nutrition Facts Label */
.nutrition-label {
    border: 2px solid #000;
    padding: 4px 8px;
    max-width: 380px;
    margin: 0 auto;
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-size: 0.85rem;
    color: #000;
}

.nutrition-label .nf-title {
    font-size: 2rem;
    font-weight: 900;
    line-height: 1;
    margin-bottom: 2px;
}

.nutrition-label .nf-bar-thick {
    background-color: #000;
    height: 8px;
    margin: 2px -8px;
}

.nutrition-label .nf-serving-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 3px 0;
}

.nutrition-label .nf-amount-per {
    font-size: 0.8rem;
    padding: 4px 0 0;
}

.nutrition-label .nf-calories-section {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    padding: 2px 0;
}

.nutrition-label .nf-calories-label {
    font-size: 2rem;
    font-weight: 900;
}

.nutrition-label .nf-dv-header {
    text-align: right;
    font-size: 0.75rem;
    font-weight: 700;
    padding: 3px 0;
    border-bottom: 1px solid #000;
}

.nutrition-label .nf-table {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
}

.nutrition-label .nf-table tr {
    border-bottom: 1px solid #000;
}

.nutrition-label .nf-td-label {
    padding: 2px 0;
    vertical-align: middle;
    overflow: hidden;
}

.nutrition-label .nf-td-input {
    padding: 2px 0 2px 4px;
    text-align: right;
    vertical-align: middle;
    width: 62px;
}

.nutrition-label .nf-td-unit {
    padding: 2px 0 2px 3px;
    vertical-align: middle;
    width: 30px;
    font-size: 0.85rem;
}

.nutrition-label .nf-td-pct {
    padding: 2px 0 2px 4px;
    text-align: right;
    vertical-align: middle;
    width: 42px;
    font-weight: 700;
    font-size: 0.8rem;
}

.nutrition-label .nf-bold .nf-td-label {
    font-weight: 700;
}

.nutrition-label .nf-indent .nf-td-label {
    padding-left: 1rem;
}

.nutrition-label .nf-indent2 .nf-td-label {
    padding-left: 2rem;
}

.nutrition-label .nf-footnote {
    font-size: 0.7rem;
    padding: 4px 0 2px;
    line-height: 1.3;
}

.nutrition-label input.nf-input {
    width: 100% !important;
    border: none !important;
    border-bottom: 1px solid #888 !important;
    box-shadow: none !important;
    text-align: right;
    padding: 0 2px;
    font-size: 0.85rem;
    background: transparent !important;
    outline: none;
}

.nutrition-label input.nf-input:focus {
    border-bottom-color: #1b6ec2 !important;
    background: #f0f4ff !important;
}

.nutrition-label input.nf-input-lg {
    width: 90px !important;
    font-size: 2rem !important;
    font-weight: 900;
}

.nutrition-label input.nf-input-text {
    width: 180px !important;
    border: none !important;
    border-bottom: 1px solid #888 !important;
    box-shadow: none !important;
    text-align: right;
    padding: 0 2px;
    font-size: 0.85rem;
    background: transparent !important;
    outline: none;
}

.nutrition-label input.nf-input-text:focus {
    border-bottom-color: #1b6ec2 !important;
    background: #f0f4ff !important;
}

/* ── InventoryPicker ────────────────────────────────────────── */

.inventory-picker-input {
    text-align: center;
    padding-left: 0;
    padding-right: 0;
}

.inventory-picker-input::-webkit-inner-spin-button,
.inventory-picker-input::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.inventory-picker-input[type=number] {
    -moz-appearance: textfield;
    appearance: textfield;
}

/* ── Low-stock panel (Home / fridge display) ────────────────── */

.low-stock-panel {
    border: 1px solid rgba(245, 158, 11, 0.4);
    border-left: 4px solid var(--color-warning);
    border-radius: 0.5rem;
    background: rgba(245, 158, 11, 0.06);
    margin-bottom: 1.25rem;
    overflow: hidden;
}

.low-stock-header {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.5rem 0.75rem;
    background: rgba(245, 158, 11, 0.1);
    border-bottom: 1px solid rgba(245, 158, 11, 0.3);
    font-weight: 700;
    font-size: 0.85rem;
    color: #FBB03B;
}

.low-stock-count {
    margin-left: auto;
    background: var(--color-warning);
    color: #0A0E1A;
    border-radius: 999px;
    padding: 0 0.5rem;
    font-size: 0.75rem;
    font-weight: 700;
    line-height: 1.6;
}

.low-stock-list {
    list-style: none;
    margin: 0;
    padding: 0.25rem 0;
}

.low-stock-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.3rem 0.75rem;
    font-size: 0.85rem;
    border-bottom: 1px solid rgba(245, 158, 11, 0.15);
}

.low-stock-item:last-child {
    border-bottom: none;
}

.low-stock-thumb {
    width: 28px;
    height: 28px;
    object-fit: cover;
    border-radius: 4px;
    flex-shrink: 0;
}

.low-stock-thumb--placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(245, 158, 11, 0.2);
    color: #FBB03B;
    border-radius: 4px;
    font-size: 0.8rem;
}

.low-stock-name {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--color-text-primary);
}

.low-stock-qty {
    font-weight: 700;
    color: #FBB03B;
    background: rgba(245, 158, 11, 0.1);
    border: 1px solid rgba(245, 158, 11, 0.3);
    border-radius: 0.25rem;
    padding: 0.1rem 0.4rem;
    font-size: 0.78rem;
    flex-shrink: 0;
}

.low-stock-qty--out {
    color: #FF8FA3;
    background: rgba(255, 77, 106, 0.12);
    border-color: rgba(255, 77, 106, 0.3);
}

/* ── Slot color swatches (UpsertMealTimeDialog) ─────────────── */

.slot-color-swatch {
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    border: 2px solid transparent;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: transform 0.1s, box-shadow 0.1s;
    padding: 0;
    font-size: 0.85rem;
}

.slot-color-swatch:hover {
    transform: scale(1.15);
    box-shadow: 0 0 0 2px #adb5bd;
}

.slot-color-swatch--selected {
    box-shadow: 0 0 0 3px #343a40;
    transform: scale(1.1);
}

.slot-color-swatch--sm {
    width: 1.1rem;
    height: 1.1rem;
    border-radius: 50%;
    border: 2px solid transparent;
    flex-shrink: 0;
    pointer-events: none;
}


/* Onboarding preload overlay — covers the page while the circuit connects and
   the dialog is preparing. @Body is suppressed while this is visible so nothing
   renders behind it. The dialog container renders after this in the DOM and
   sits on top. */
.onboarding-preload-overlay {
    position: fixed;
    inset: 0;
    background-color: rgba(0, 0, 0, 0.6);
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
}

/* Onboarding wizard — dimmed + blurred backdrop */
.onboarding-wizard-dialog.blazor-dialog-container {
    background-color: rgba(0, 0, 0, 0.6);
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
}

/* Announcements dialog */
.announcements-dialog .blazor-dialog-content-wrapper-normal {
    max-height: 50vh;
    display: flex;
    flex-direction: column;
}

.announcements-dialog .blazor-dialog-content {
    display: flex;
    flex-direction: column;
    min-height: 0;
    flex: 1;
}

.announcements-dialog .blazor-dialog-body {
    overflow-y: auto;
    flex: 1;
    min-height: 0;
}

.announcements-content {
    line-height: 1.6;
}

.announcements-dialog-title {
    font-size: 2em;
    font-weight: 600;
    margin: 0 auto;
}

@media (max-width: 767.98px) {
    .announcements-dialog .blazor-dialog-content-wrapper-normal {
        min-height: 80vh !important;
        max-width: 88vw !important;
        margin: 10vh auto !important;
    }
}

/* Announcement items (AB#429). Each one is a summary the reader can unfold, so the row itself is the
   button: the whole line is the target, which is what makes it usable on the fridge. */
/* Cyan so the date reads as a divider between releases rather than as another headline competing with
   the summaries directly under it. */
.announcement-date {
    font-size: 1rem;
    font-weight: 600;
    color: var(--color-cyan, #00D4FF);
    margin: 1.25rem 0 0.35rem;
}

.announcement-date:first-child {
    margin-top: 0;
}

.announcement-list {
    list-style: none;
    padding: 0;
    margin: 0 0 0.5rem;
}

.announcement-item {
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.announcement-item:last-child {
    border-bottom: none;
}

.announcement-toggle {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
    min-height: 48px;
    padding: 0.5rem 0;
    background: none;
    border: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.announcement-summary {
    flex: 1;
    font-weight: 600;
}

.announcement-summary-plain {
    display: block;
    padding: 0.75rem 0;
}

.announcement-chevron {
    flex: 0 0 auto;
    opacity: 0.7;
}

.announcement-detail {
    padding: 0 0 0.85rem;
    opacity: 0.9;
}

/* Ensure toasts render above dropdowns and backdrops */
.blazored-toast-container {
    z-index: 1100 !important;
}

/* Receipt drop zone */
.receipt-drop-zone {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.5rem 0.75rem;
    border: 2px dashed var(--color-border);
    border-radius: 0.5rem;
    color: var(--color-text-muted);
    font-size: 0.875rem;
    min-height: 48px;
    cursor: default;
    transition: border-color 0.15s, background-color 0.15s;
    flex-wrap: wrap;
}

.receipt-drop-zone--active {
    border-color: var(--color-cyan);
    background-color: rgba(0, 212, 255, 0.06);
    color: var(--color-cyan);
}

/* SimpleDialog — wider than BlazorDialog's default 500px Normal to avoid wrapping on confirm messages */
@media (min-width: 576px) {
    .blazor-dialog-content-wrapper-normal {
        max-width: 550px !important;
    }
}

/* Feedback attachment thumbnail */
.feedback-attachment-thumb {
    max-width: 120px;
    max-height: 120px;
    object-fit: cover;
}

/* ── Login / signed-out page ────────────────────────────────── */

.public-screen {
    /* Fixed-height scroll container: html/body are locked to 100vh with overflow hidden, so this
       element owns the signed-out scroll. It stacks the shared public header above the page content;
       long pages (Privacy/Terms) scroll within it while the sticky header stays put. */
    height: 100vh;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    /* Arcade backdrop matching the marketing home (.landing): the neon-kitchen photo pinned behind
       everything (tint layer keeps text readable), the ambient glow blooms layered over it in ::before,
       and scanlines over the top in ::after. Fixed attachment keeps all layers pinned to the viewport
       at any scroll position - a scroll-attached background slides away below a tall card
       (AB#723/#744 legal pages exposed this). Portrait swaps to the 9x16 crop below. */
    background-color: #12161F;
    background-image: linear-gradient(rgba(10, 14, 26, 0.62), rgba(10, 14, 26, 0.62)), url('/images/bg-neon-kitchen-landscape.webp');
    background-position: center center;
    background-size: cover;
    background-repeat: no-repeat;
    background-attachment: fixed;
    position: relative;
}

@media (orientation: portrait) {
    .public-screen {
        background-image: linear-gradient(rgba(10, 14, 26, 0.62), rgba(10, 14, 26, 0.62)), url('/images/bg-neon-kitchen-portrait.webp');
    }
}

/* Ambient neon blooms over the photo, matching the marketing home's .glow-field. Fixed so they stay
   pinned as a tall page scrolls; pointer-events none keeps the page clickable. */
.public-screen::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background:
        radial-gradient(640px 480px at 85% -5%, rgba(0, 212, 255, 0.13), transparent 70%),
        radial-gradient(560px 560px at -10% 45%, rgba(200, 80, 192, 0.11), transparent 70%),
        radial-gradient(700px 500px at 50% 115%, rgba(139, 92, 246, 0.10), transparent 70%);
}

/* Faint CRT scanlines over the whole signed-out surface, matching the marketing home. Fixed so they
   cover the viewport regardless of scroll; pointer-events none keeps everything clickable. */
.public-screen::after {
    content: '';
    position: fixed;
    inset: 0;
    z-index: 30;
    pointer-events: none;
    background: repeating-linear-gradient(
        to bottom,
        rgba(255, 255, 255, 0.022) 0px,
        rgba(255, 255, 255, 0.022) 1px,
        transparent 1px,
        transparent 4px);
}

/* Shared header across every signed-out page (LoginLayout), matching the marketing home header so the
   public surfaces look consistent. Sticky so it stays visible while a long legal page scrolls. */
.public-header {
    position: sticky;
    top: 0;
    z-index: 20;
    flex-shrink: 0;
    background: rgba(18, 22, 31, 0.94);
}

/* Animated signature-gradient rule under the header, matching the marketing home. */
.public-header::after {
    content: '';
    display: block;
    height: 2px;
    background: linear-gradient(90deg, #00D4FF, #8B5CF6, #C850C0, #8B5CF6, #00D4FF);
    background-size: 200% 100%;
    animation: public-marquee 9s linear infinite;
}

@keyframes public-marquee {
    0% { background-position: 0% 0; }
    100% { background-position: 200% 0; }
}

@media (prefers-reduced-motion: reduce) {
    .public-header::after { animation: none; }
}

/* Inner column matches the marketing home header's .wrap/.topbar (max-width 1040, centred, 1.5rem
   inset) so the brand and Sign-in button sit in the same place on the home page and every public
   page - otherwise they jump horizontally when navigating between them. */
.public-header-inner {
    max-width: 1040px;
    margin: 0 auto;
    padding: 0 1.5rem;
    min-height: 64px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
}

.public-brand {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    font-family: 'Space Grotesk', system-ui, sans-serif;
    font-weight: 700;
    font-size: 1.2rem;
    letter-spacing: -0.01em;
    color: var(--color-text-primary, #fff);
    text-decoration: none;
}

.public-brand img {
    width: 32px;
    height: 32px;
    border-radius: 8px;
    box-shadow: 0 0 14px rgba(0, 212, 255, 0.35);
}

.public-signin {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 48px;
    padding: 0 1.2rem;
    font-weight: 600;
    font-size: 0.95rem;
    border: 1px solid var(--color-border-strong, #3A4266);
    border-radius: 8px;
    color: var(--color-text-secondary, #C8D0E0);
    text-decoration: none;
}

.public-signin:hover {
    border-color: var(--color-cyan, #00D4FF);
    color: var(--color-text-primary, #fff);
}

/* Public page nav (AB#743), shared by the marketing shell (.landing .topbar) and the legal-page
   header (.public-header-inner) via the PublicPageNav component. Global rather than scoped so it works
   in both variable scopes; the --l-* palette resolves inside .landing, and the hardcoded fallbacks
   cover the .public-header context. Fridge-safe (Chromium M94): flexbox + flex-wrap only. */
.public-nav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 0.25rem 0.75rem;
    flex: 1 1 auto;
}

.public-nav a {
    display: inline-flex;
    align-items: center;
    min-height: 48px;
    padding: 0 0.65rem;
    font-family: 'Space Grotesk', system-ui, sans-serif;
    font-weight: 600;
    font-size: 0.95rem;
    color: var(--l-text, #A0AABB);
    text-decoration: none;
    white-space: nowrap;
    border-bottom: 2px solid transparent;
    transition: color 0.15s, border-color 0.15s;
}

.public-nav a:hover {
    color: var(--l-white, #FFFFFF);
    border-bottom-color: var(--l-cyan, #00D4FF);
}

/* Tablet/fridge and down: brand and Sign in share the top row, the nav drops to a full-width centred
   second row so the six links never crowd the button or stack each item onto its own line. Needs
   flex-wrap on the parent header rows (set on .public-header-inner and .landing .topbar). The 900px
   cutoff covers the fridge (720) and tablet (768) portrait widths; wider viewports keep the nav inline
   between the brand and Sign in. */
@media (max-width: 900px) {
    .public-nav {
        order: 3;
        flex-basis: 100%;
        margin-top: 0.25rem;
    }
}

/* The page content area below the header. Grows to fill the remaining viewport so a short card
   (login) centres, but takes its natural height when the card is taller (Privacy/Terms) so the page
   scrolls instead of clipping. */
.public-content {
    flex: 1 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
    padding: 2.5rem 1.5rem;
}

/* Auto vertical margins center a short card but collapse to 0 when the card is taller than the space,
   so the card top is never clipped in the scroll container. flex-shrink: 0 stops the column flex from
   shrinking a too-tall card (whose overflow: hidden would then silently clip it instead of scrolling). */
.public-content > * {
    margin: auto 0;
    flex-shrink: 0;
}

/* Footer strip on the signed-out layout, carrying the cookie-preferences affordance (AB#776). Sits
   after .public-content, which grows to fill the viewport, so on a short page (login) it rides at the
   bottom and on a long one (Terms) it follows the content. z-index 1 clears the ::before glow layer;
   the ::after scanlines sit at 30 and are pointer-events: none, so they pass clicks through. */
.public-footer {
    position: relative;
    z-index: 1;
    flex: 0 0 auto;
    width: 100%;
    /* Deliberately tight. .public-content already carries 2.5rem of bottom padding and grows to fill
       the viewport, so anything more here pushes a short page (login) into a few pixels of scroll it
       previously did not have. The button's own 48px min-height supplies the visual weight. */
    padding: 0 1.5rem 0.25rem;
    text-align: center;
}

.public-footer-link {
    display: inline-flex;
    align-items: center;
    /* 48px is the fridge touch-target floor. */
    min-height: 48px;
    padding: 0 0.5rem;
    background: none;
    border: 0;
    color: var(--color-text-secondary, #A0AABB);
    font-size: 0.9rem;
    cursor: pointer;
}

.public-footer-link:hover,
.public-footer-link:focus-visible {
    color: var(--color-cyan, #00D4FF);
}

.public-card {
    z-index: 1;
}

.public-card {
    background: rgba(30, 36, 56, 0.92);
    border: 1px solid rgba(255, 255, 255, 0.10);
    border-radius: 1.25rem;
    padding: 3rem 2.75rem;
    text-align: center;
    width: 100%;
    max-width: 460px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 80px rgba(200, 80, 192, 0.08);
    position: relative;
    overflow: hidden;
}

.public-card::before {
    content: '';
    position: absolute;
    top: -60px;
    left: -60px;
    width: 240px;
    height: 240px;
    background: var(--gradient-glow-magenta);
    pointer-events: none;
}

.public-logo {
    width: 96px;
    height: 96px;
    object-fit: contain;
    margin-bottom: 1.25rem;
}

.public-app-name {
    font-size: 2.75rem;
    font-weight: 800;
    font-family: 'Space Grotesk', system-ui, sans-serif;
    color: var(--color-text-primary);
    margin-bottom: 0.35rem;
    line-height: 1.1;
    letter-spacing: -0.02em;
}

.public-tagline {
    font-size: 1rem;
    color: var(--color-text-secondary);
    margin-bottom: 2.25rem;
}

.btn-google {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    width: 100%;
    background: #fff;
    border: 1px solid #dadce0;
    border-radius: 4px;
    padding: 0.875rem 1.75rem;
    min-height: 52px;
    min-width: 240px;
    font-size: 1rem;
    font-weight: 500;
    color: #3c4043;
    text-decoration: none;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
    cursor: pointer;
}

.btn-google:hover {
    background-color: #f8f9fa;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.16);
    color: #3c4043;
    text-decoration: none;
}

.btn-google:active {
    background-color: #f1f3f4;
}

.btn-google-icon {
    width: 20px;
    height: 20px;
    flex-shrink: 0;
}

/* Additional OAuth provider buttons (AB#969) — same footprint as the Google button */
.btn-microsoft {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    width: 100%;
    background: #fff;
    border: 1px solid #dadce0;
    border-radius: 4px;
    padding: 0.875rem 1.75rem;
    min-height: 52px;
    min-width: 240px;
    font-size: 1rem;
    font-weight: 500;
    color: #3c4043;
    text-decoration: none;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
    cursor: pointer;
}

.btn-microsoft:hover {
    background-color: #f8f9fa;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.16);
    color: #3c4043;
    text-decoration: none;
}

.btn-microsoft:active {
    background-color: #f1f3f4;
}

.btn-microsoft-icon {
    width: 20px;
    height: 20px;
    flex-shrink: 0;
}

/* Passkey controls (AB#773).

   Hidden by default and revealed only under html.passkey-supported, which js/passkey.js adds when the
   browser actually has WebAuthn. Doing the gate in CSS rather than by toggling elements means it needs
   no re-running after Blazor swaps the DOM on an enhanced navigation, and it degrades the right way:
   a browser with JS off or WebAuthn missing never shows a control it cannot honour. The Samsung Family
   Hub fridge (Samsung Internet 10 / Chromium ~M94) is the case this exists for — it simply keeps the
   password and provider buttons it already had.

   Written as "hide when unsupported" rather than a hide/show pair on purpose. The pair would have to
   name a display value to restore, and there is no single right one: these containers are a plain div on
   the login page but a Bootstrap .card (display: flex) in Settings, so restoring `block` silently flattened
   the card's flex layout. Negating the class instead means the supported case adds no display rule at all
   and every container keeps whatever display it would otherwise have. */
html:not(.passkey-supported) [data-passkey-ui] {
    display: none;
}

/* Matches .btn-google / .btn-microsoft so the three sign-in choices read as one set, but in the app's
   own colours rather than a vendor's — a passkey belongs to Ate-bit, not to a provider. */
.btn-passkey {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    width: 100%;
    background: var(--color-bg-elevated);
    border: 1px solid var(--color-border);
    border-radius: 4px;
    padding: 0.875rem 1.75rem;
    min-height: 52px;
    min-width: 240px;
    font-size: 1rem;
    font-weight: 500;
    color: var(--color-text-primary);
    text-decoration: none;
    cursor: pointer;
}

/* The elevated background is already the lightest surface in the palette, so hover reads on the border
   rather than going lighter still. */
.btn-passkey:hover {
    border-color: var(--color-border-focus);
    color: var(--color-text-primary);
}

.btn-passkey[aria-busy="true"] {
    opacity: 0.65;
    cursor: default;
}

.btn-passkey-icon {
    font-size: 1.15rem;
    line-height: 1;
    flex-shrink: 0;
}

/* One row per registered passkey in Settings. */
.passkey-item-meta {
    font-size: 0.8125rem;
    color: var(--color-text-secondary);
}

/* Email/password auth forms on the login card (AB#966) */
.auth-form {
    text-align: left;
    margin-bottom: 1.25rem;
}

.auth-form .form-label {
    color: var(--color-text-secondary);
    font-size: 0.875rem;
    margin-bottom: 0.25rem;
}

.auth-form .form-control {
    min-height: 48px;
}

.auth-submit {
    min-height: 52px;
}

/* Primary submit matches the marketing home's signature-gradient CTA. Scoped to .btn-primary so the
   outline-secondary submit variants keep their Bootstrap look. */
.btn-primary.auth-submit {
    background: linear-gradient(90deg, #00D4FF 0%, #8B5CF6 50%, #C850C0 100%);
    border: 0;
    color: #0A0E1A;
    font-family: 'Space Grotesk', system-ui, sans-serif;
    font-weight: 700;
    box-shadow: 0 6px 26px rgba(0, 212, 255, 0.22), 0 6px 26px rgba(200, 80, 192, 0.14);
}

.btn-primary.auth-submit:hover,
.btn-primary.auth-submit:focus {
    background: linear-gradient(90deg, #00D4FF 0%, #8B5CF6 50%, #C850C0 100%);
    color: #0A0E1A;
    box-shadow: 0 10px 34px rgba(0, 212, 255, 0.34), 0 10px 34px rgba(200, 80, 192, 0.22);
}

.btn-primary.auth-submit:disabled {
    background: linear-gradient(90deg, #00D4FF 0%, #8B5CF6 50%, #C850C0 100%);
    color: #0A0E1A;
    opacity: 0.55;
}

.auth-divider {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    color: var(--color-text-secondary);
    font-size: 0.85rem;
    margin: 1.25rem 0;
}

.auth-divider::before,
.auth-divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background: rgba(255, 255, 255, 0.12);
}

.auth-alt {
    color: var(--color-text-secondary);
    font-size: 0.9rem;
    margin-top: 0.5rem;
}

/* Live password requirements checklist (AB#1071) */
.password-requirements {
    list-style: none;
    margin: 0.5rem 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.password-requirement {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

.password-requirement i {
    font-size: 0.9rem;
}

.password-requirement.is-met {
    color: var(--color-success);
}

.border-dashed {
    border: 2px dashed var(--color-border) !important;
}

/* Broken / missing photo fallback — CSS-only trick.
   Pseudo-elements on <img> are hidden when the image loads successfully;
   they become visible when the src fails, covering the browser's broken-image icon. */
img {
    position: relative;
}

img::before {
    content: "";
    display: block;
    position: absolute;
    inset: 0;
    background-color: var(--color-bg-elevated);
    z-index: 1;
}

img::after {
    content: "📷  " attr(alt);
    display: flex;
    align-items: center;
    justify-content: center;
    position: absolute;
    inset: 0;
    background-color: var(--color-bg-elevated);
    border: 2px dashed var(--color-border);
    border-radius: 6px;
    color: var(--color-text-muted);
    font-size: 0.75rem;
    font-family: 'Inter', sans-serif;
    text-align: center;
    padding: 0.5rem;
    box-sizing: border-box;
    z-index: 2;
}

/* Inline SVG country flags (RegionFlag component). Emoji flags don't render on
   Windows / Samsung Internet, so flags are drawn as SVG and sized here. */
.region-flag {
    display: inline-flex;
    vertical-align: middle;
    line-height: 0;
    margin-right: 0.35rem;
}

.region-flag svg {
    height: 0.9em;
    width: auto;
    border-radius: 1px;
    box-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.25);
}

/* Centered flag when used as a KPI card icon — drop the inline right margin. */
.kpi-icon .region-flag {
    margin-right: 0;
}

/* ── Public marketing landing ("/", signed-out) ─────────────────
   Ported from the former static wwwroot/home.html into a Razor page so the copy is localizable
   (AB#784). Every rule is scoped under .landing so the marketing chrome (its own .btn, .hero, .panel,
   .feature, etc.) stays isolated from Bootstrap and the app styles that share those class names.
   Fridge-safe CSS only (Samsung Internet / Chromium M94): no :has(), @container, CSS nesting, @layer,
   subgrid, or text-wrap:balance. Flexbox + grid + transforms + keyframes + custom properties only.
   Press Start 2P is decoration-tier: tiny arcade micro-labels only, never headlines or body copy. */
.landing {
    --l-bg: #12161F;
    --l-card: #1E2438;
    --l-card-2: #242B44;
    --l-border: #2E3550;
    --l-border-strong: #3A4266;
    --l-text: #A0AABB;
    --l-text-strong: #C8D0E0;
    --l-white: #FFFFFF;
    --l-muted: #5A6480;
    --l-cyan: #00D4FF;
    --l-cyan-dark: #00BBDD;
    --l-magenta: #C850C0;
    --l-purple: #8B5CF6;
    --l-grad: linear-gradient(90deg, #00D4FF 0%, #8B5CF6 50%, #C850C0 100%);
    --l-maxw: 1040px;
    font-family: 'Inter', system-ui, sans-serif;
    /* Neon-kitchen photo pinned behind everything (a tint layer keeps text readable). The glow field
       and content sit above it; scanlines layer over the top of all of it. */
    background-color: var(--l-bg);
    background-image: linear-gradient(rgba(10, 14, 26, 0.62), rgba(10, 14, 26, 0.62)), url('/images/bg-neon-kitchen-landscape.webp');
    background-position: center center;
    background-size: cover;
    background-repeat: no-repeat;
    background-attachment: fixed;
    color: var(--l-text);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    /* html/body are locked to overflow:hidden, so the landing owns its own scroll (same pattern as
       .public-screen). The fixed glow/scanline layers stay pinned to the viewport while this scrolls. */
    height: 100vh;
    overflow-x: hidden;
    overflow-y: auto;
}
.landing *, .landing *::before, .landing *::after { box-sizing: border-box; }
.landing h1, .landing h2, .landing h3, .landing p, .landing ul, .landing li { margin: 0; padding: 0; }

@media (orientation: portrait) {
    .landing {
        background-image: linear-gradient(rgba(10, 14, 26, 0.62), rgba(10, 14, 26, 0.62)), url('/images/bg-neon-kitchen-portrait.webp');
    }
}

/* Ambient cabinet glow: one cyan bloom top-right, one magenta bloom left, fixed so the room feels lit
   while content scrolls through it. */
.landing .glow-field {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background:
        radial-gradient(640px 480px at 85% -5%, rgba(0, 212, 255, 0.13), transparent 70%),
        radial-gradient(560px 560px at -10% 45%, rgba(200, 80, 192, 0.11), transparent 70%),
        radial-gradient(700px 500px at 50% 115%, rgba(139, 92, 246, 0.10), transparent 70%);
}
/* CRT scanlines over everything, faint enough to read as texture, not noise. */
.landing .scanlines {
    position: fixed;
    inset: 0;
    z-index: 30;
    pointer-events: none;
    background: repeating-linear-gradient(
        to bottom,
        rgba(255, 255, 255, 0.022) 0px,
        rgba(255, 255, 255, 0.022) 1px,
        transparent 1px,
        transparent 4px);
}
.landing main, .landing .site-header, .landing footer { position: relative; z-index: 1; }
.landing a { color: var(--l-cyan); text-decoration: none; }
.landing a:hover { color: var(--l-cyan-dark); }
.landing .wrap { width: 100%; max-width: var(--l-maxw); margin: 0 auto; padding: 0 1.5rem; }

.landing .px {
    font-family: 'Press Start 2P', monospace;
    font-size: 0.6rem;
    letter-spacing: 0.08em;
}

/* --- Header: solid bar with an animated signature-gradient marquee rule underneath --- */
.landing .site-header {
    position: sticky;
    top: 0;
    z-index: 20;
    background: rgba(18, 22, 31, 0.94);
}
.landing .site-header::after {
    content: '';
    display: block;
    height: 2px;
    background: linear-gradient(90deg, #00D4FF, #8B5CF6, #C850C0, #8B5CF6, #00D4FF);
    background-size: 200% 100%;
    animation: landing-marquee 9s linear infinite;
}
@keyframes landing-marquee {
    0% { background-position: 0% 0; }
    100% { background-position: 200% 0; }
}
.landing .topbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    min-height: 64px;
}
.landing .brand {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    font-family: 'Space Grotesk', system-ui, sans-serif;
    font-weight: 700;
    font-size: 1.2rem;
    color: var(--l-white);
    letter-spacing: -0.01em;
}
.landing .brand img {
    width: 32px;
    height: 32px;
    border-radius: 8px;
    box-shadow: 0 0 14px rgba(0, 212, 255, 0.35);
}
.landing .nav-signin {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 48px;
    padding: 0 1.2rem;
    font-weight: 600;
    font-size: 0.95rem;
    border: 1px solid var(--l-border-strong);
    border-radius: 8px;
    color: var(--l-text-strong);
    transition: border-color 0.15s, color 0.15s, box-shadow 0.15s;
}
.landing .nav-signin:hover {
    border-color: var(--l-cyan);
    color: var(--l-white);
    box-shadow: 0 0 16px rgba(0, 212, 255, 0.25);
}

/* --- Buttons --- */
.landing .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 52px;
    padding: 0 1.9rem;
    border-radius: 10px;
    font-family: 'Space Grotesk', system-ui, sans-serif;
    font-weight: 700;
    font-size: 1rem;
    letter-spacing: 0.01em;
    border: 0;
    cursor: pointer;
    transition: box-shadow 0.15s, border-color 0.15s, color 0.15s, transform 0.15s;
}
.landing .btn-primary {
    background: var(--l-grad);
    color: #0A0E1A;
    box-shadow: 0 6px 26px rgba(0, 212, 255, 0.28), 0 6px 26px rgba(200, 80, 192, 0.18);
}
.landing .btn-primary:hover {
    color: #0A0E1A;
    transform: translateY(-2px);
    box-shadow: 0 10px 34px rgba(0, 212, 255, 0.4), 0 10px 34px rgba(200, 80, 192, 0.28);
}
.landing .cta-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.85rem;
    justify-content: center;
}

/* --- Hero: attract screen. Gradient headline, floating pixel-art food sprites. --- */
.landing .hero {
    position: relative;
    overflow: hidden;
    text-align: center;
    padding: clamp(4rem, 9vw, 6.5rem) 0 clamp(6.5rem, 12vw, 9rem);
}
.landing .hero-inner { position: relative; z-index: 2; }
.landing .eyebrow {
    display: inline-block;
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--l-cyan);
    margin-bottom: 1.25rem;
}
/* Pixel-art food sprites: the 8-bit nod IS the food. Drawn as inline SVG rect grids so they stay crisp
   at any size. Gentle alternating float, glow matched to each sprite's colour. */
.landing .sprite-row {
    display: flex;
    justify-content: center;
    gap: clamp(1.4rem, 5vw, 2.75rem);
    margin: 0 0 1.75rem;
}
.landing .sprite {
    width: clamp(44px, 7vw, 60px);
    height: clamp(44px, 7vw, 60px);
    animation: landing-bob 3.4s ease-in-out infinite;
}
.landing .sprite svg { width: 100%; height: 100%; shape-rendering: crispEdges; }
.landing .sprite:nth-child(2) { animation-delay: -0.9s; }
.landing .sprite:nth-child(3) { animation-delay: -1.8s; }
.landing .sprite:nth-child(4) { animation-delay: -2.6s; }
.landing .sprite--cyan { filter: drop-shadow(0 0 10px rgba(0, 212, 255, 0.35)); }
.landing .sprite--magenta { filter: drop-shadow(0 0 10px rgba(200, 80, 192, 0.35)); }
@keyframes landing-bob {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-7px); }
}
.landing h1 {
    font-family: 'Space Grotesk', system-ui, sans-serif;
    font-weight: 700;
    font-size: clamp(2.4rem, 6.5vw, 4rem);
    line-height: 1.06;
    letter-spacing: -0.025em;
    color: var(--l-white);
    margin: 0 auto 1.25rem;
}
.landing h1 .accent {
    display: block;
    background: var(--l-grad);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}
.landing .lede {
    font-size: clamp(1.05rem, 2.4vw, 1.25rem);
    line-height: 1.65;
    max-width: 600px;
    margin: 0 auto 2.25rem;
    color: var(--l-text-strong);
}
/* --- Section rhythm: target section.wrap so vertical padding beats .wrap's zero block padding --- */
.landing section.wrap {
    padding-top: clamp(2.75rem, 6vw, 4.25rem);
    padding-bottom: clamp(2.75rem, 6vw, 4.25rem);
}
.landing .section-head { text-align: center; max-width: 620px; margin: 0 auto 2.5rem; }
.landing h2 {
    font-family: 'Space Grotesk', system-ui, sans-serif;
    font-weight: 700;
    font-size: clamp(1.6rem, 4vw, 2.15rem);
    line-height: 1.2;
    letter-spacing: -0.02em;
    color: var(--l-white);
    margin-bottom: 0.85rem;
}
.landing .section-head p { font-size: 1.05rem; }

/* --- Hi-score bar: three stats on a thin neon shelf --- */
.landing .hiscore {
    position: relative;
    z-index: 2;
    margin-top: -3.5rem;
}
.landing .hiscore-bar {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-around;
    gap: 1.25rem;
    background: rgba(30, 36, 56, 0.92);
    border: 1px solid var(--l-border-strong);
    border-radius: 16px;
    padding: 1.4rem 1.5rem;
    box-shadow: 0 0 30px rgba(0, 212, 255, 0.08), 0 14px 34px rgba(0, 0, 0, 0.35);
}
.landing .score { text-align: center; min-width: 150px; }
.landing .score-num {
    font-family: 'Press Start 2P', monospace;
    font-size: 1.15rem;
    line-height: 1.4;
    color: var(--l-white);
}
.landing .score-num .u { color: var(--l-cyan); }
.landing .score-label {
    font-family: 'Press Start 2P', monospace;
    font-size: 0.6rem;
    letter-spacing: 0.08em;
    color: var(--l-muted);
    text-transform: uppercase;
    margin-top: 0.5rem;
}

/* --- Panels --- */
.landing .panel {
    background: var(--l-card);
    border: 1px solid var(--l-border);
    border-radius: 20px;
    padding: clamp(2rem, 4vw, 2.75rem);
    text-align: center;
}
.landing .panel h2 { text-align: center; }
.landing .panel p {
    font-size: 1.05rem;
    max-width: 660px;
    margin: 0 auto 1rem;
}
.landing .panel p:last-child { margin-bottom: 0; }
.landing .panel strong { color: var(--l-text-strong); font-weight: 600; }
/* Final CTA: gradient hairline frame via padding trick (border-image is fussy with radius). */
.landing .panel-frame {
    background: var(--l-grad);
    border-radius: 21px;
    padding: 1px;
    box-shadow: 0 0 44px rgba(139, 92, 246, 0.22);
}
.landing .panel--final {
    border: 0;
    border-radius: 20px;
    background: linear-gradient(160deg, #232a44 0%, var(--l-bg) 100%);
}
.landing .panel--final p { max-width: 520px; margin-bottom: 1.9rem; }

/* --- Level select: feature cards with alternating neon accents --- */
.landing .features {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1.1rem;
}
.landing .feature {
    position: relative;
    background: var(--l-card);
    border: 1px solid var(--l-border);
    border-radius: 16px;
    padding: 1.75rem 1.6rem;
    overflow: hidden;
    transition: border-color 0.15s, transform 0.15s, box-shadow 0.15s;
}
.landing .feature::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    background: var(--l-grad);
    opacity: 0.85;
}
.landing .feature:hover { transform: translateY(-3px); }
.landing .feature--cyan:hover {
    border-color: rgba(0, 212, 255, 0.55);
    box-shadow: 0 0 26px rgba(0, 212, 255, 0.16), 0 12px 28px rgba(0, 0, 0, 0.28);
}
.landing .feature--magenta:hover {
    border-color: rgba(200, 80, 192, 0.55);
    box-shadow: 0 0 26px rgba(200, 80, 192, 0.16), 0 12px 28px rgba(0, 0, 0, 0.28);
}
.landing .feature-top { margin-bottom: 1.15rem; }
.landing .feature-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    border-radius: 12px;
    background: var(--l-card-2);
    border: 1px solid var(--l-border-strong);
    color: var(--l-cyan);
}
.landing .feature--magenta .feature-icon { color: var(--l-magenta); }
.landing .feature-icon svg { width: 24px; height: 24px; }
.landing .feature h3 {
    font-family: 'Space Grotesk', system-ui, sans-serif;
    font-weight: 600;
    font-size: 1.2rem;
    color: var(--l-white);
    margin-bottom: 0.5rem;
}
.landing .feature p { font-size: 0.98rem; }

/* --- Footer --- */
.landing footer {
    border-top: 1px solid var(--l-border);
    padding: 2.25rem 0 2.75rem;
    text-align: center;
    font-size: 0.9rem;
    color: var(--l-muted);
}
.landing footer .links { margin-bottom: 0.65rem; }
.landing footer .links a { margin: 0 0.65rem; color: var(--l-text); }
.landing footer .links a:hover { color: var(--l-cyan); }
/* Cookie preferences (AB#776) reopens the consent banner in place rather than navigating, so it has
   to be a button — styled to sit in the footer link row as an equal. Padding keeps it a comfortable
   touch target on the fridge without changing the row's visual rhythm. */
.landing footer .links .footer-link-btn {
    display: inline-flex;
    align-items: center;
    /* 48px is the fridge touch-target floor. Applied to the button rather than the whole row so the
       neighbouring anchors keep the footer's existing rhythm. */
    min-height: 48px;
    padding: 0 0.25rem;
    margin: 0 0.65rem;
    background: none;
    border: 0;
    color: var(--l-text);
    font: inherit;
    cursor: pointer;
}
.landing footer .links .footer-link-btn:hover { color: var(--l-cyan); }
.landing .footer-tag {
    display: block;
    margin-top: 0.9rem;
    color: var(--l-muted);
    opacity: 0.75;
}

/* Two-column feature grid from tablet up; the fridge (720px portrait) gets two columns too. */
@media (min-width: 640px) {
    .landing .features { grid-template-columns: 1fr 1fr; gap: 1.25rem; }
}
/* Respect reduced motion: freeze the attract-screen animations. */
@media (prefers-reduced-motion: reduce) {
    .landing .site-header::after, .landing .sprite { animation: none; }
}

/* ======================================================================
   Arcade theme — shared chrome for every admin page (AB#959, AB#795)
   ----------------------------------------------------------------------
   Global rather than scoped on purpose. These started life in
   AdminDashboard.razor.css, but Blazor CSS isolation binds a scoped sheet
   to a single component, so /admin/ai-pricing, /admin/ai-cost and
   /admin/jobs rendered the same markup with none of the styling. Anything
   only one page uses (KPI cards, the dashboard's bar charts) stays in that
   page's own .razor.css.
   ====================================================================== */

.arcade-page {
    --arcade-font: 'Press Start 2P', 'Space Grotesk', system-ui, sans-serif;
    position: relative;
}

/* ── CRT scanline overlay ──────────────────────────────────────────── */
.arcade-page::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background: repeating-linear-gradient(
        to bottom,
        rgba(0, 0, 0, 0) 0px,
        rgba(0, 0, 0, 0) 2px,
        rgba(0, 212, 255, 0.025) 3px,
        rgba(0, 0, 0, 0) 4px
    );
    mix-blend-mode: overlay;
}

.arcade-page > * {
    position: relative;
    z-index: 1;
}

/* ── Title screen header ───────────────────────────────────────────── */
.arcade-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 2rem;
}

.arcade-title {
    font-family: var(--arcade-font);
    font-size: 1.5rem;
    color: var(--color-cyan);
    text-shadow: 0 0 6px rgba(0, 212, 255, 0.8), 0 0 18px rgba(0, 212, 255, 0.5);
    margin: 0;
    line-height: 1.4;
}

.arcade-subtitle {
    font-family: var(--arcade-font);
    font-size: 0.65rem;
    color: var(--color-magenta);
    text-shadow: 0 0 8px rgba(200, 80, 192, 0.6);
    margin-top: 0.5rem;
}

.arcade-subtitle .arcade-cursor {
    animation: arcade-blink 1s steps(1) infinite;
}

@keyframes arcade-blink {
    0%, 50% { opacity: 1; }
    50.01%, 100% { opacity: 0; }
}

.arcade-status {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.5rem;
}

.arcade-clock {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.8rem;
    color: var(--color-text-secondary);
    letter-spacing: 0.05em;
}

.arcade-btn {
    font-family: var(--arcade-font);
    font-size: 0.65rem;
    color: #0A0E1A;
    background: var(--color-cyan);
    border: none;
    border-radius: 4px;
    padding: 0.6rem 1rem;
    box-shadow: 0 4px 0 #009AB8, 0 0 14px rgba(0, 212, 255, 0.4);
    transition: transform 80ms ease, box-shadow 80ms ease;
    cursor: pointer;
}

.arcade-btn:hover {
    box-shadow: 0 4px 0 #009AB8, 0 0 20px rgba(0, 212, 255, 0.7);
}

.arcade-btn:active {
    transform: translateY(4px);
    box-shadow: 0 0 0 #009AB8, 0 0 10px rgba(0, 212, 255, 0.4);
}

.arcade-btn:disabled {
    opacity: 0.6;
    cursor: default;
    transform: none;
}

/* A back/secondary action in the header: same shape as .arcade-btn, muted so
   the primary action on the page still reads as the loud one. */
.arcade-btn-ghost {
    color: var(--color-cyan);
    background: transparent;
    border: 1px solid rgba(0, 212, 255, 0.5);
    box-shadow: none;
    text-decoration: none;
    display: inline-block;
}

.arcade-btn-ghost:hover {
    color: #0A0E1A;
    background: var(--color-cyan);
    box-shadow: 0 0 14px rgba(0, 212, 255, 0.45);
}

.arcade-btn-ghost:active {
    transform: none;
}

/* ── Top-level section headings (Metrics / AI Usage / Platform / Feedback) ── */
.arcade-section-heading {
    font-family: var(--arcade-font);
    font-size: 1.1rem;
    color: var(--color-magenta);
    text-shadow: 0 0 8px rgba(200, 80, 192, 0.55);
    letter-spacing: 0.04em;
}

/* ── RPG-style section dividers ────────────────────────────────────── */
.arcade-divider {
    font-family: var(--arcade-font);
    font-size: 0.7rem;
    color: var(--color-purple);
    text-shadow: 0 0 8px rgba(139, 92, 246, 0.6);
    text-align: center;
    margin: 1.5rem 0 1rem;
    letter-spacing: 0.1em;
}

/* ── Generic arcade card treatment (AI Usage / Platform / Feedback / Jobs) ── */
.arcade-card {
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    box-shadow: 0 0 16px rgba(0, 212, 255, 0.08);
}

.arcade-card-header {
    font-family: var(--arcade-font);
    font-size: 0.7rem;
    color: var(--color-cyan);
    text-shadow: 0 0 8px rgba(0, 212, 255, 0.5);
    letter-spacing: 0.05em;
}

/* ── Coin glyph for cost figures ───────────────────────────────────── */
.arcade-coin {
    color: var(--color-warning);
    text-shadow: 0 0 6px rgba(245, 158, 11, 0.6);
}

/* ── Segmented control (AI usage date range) ──────────────────────── */
.arcade-segmented {
    display: inline-flex;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    overflow: hidden;
}

.arcade-segment-btn {
    font-family: var(--arcade-font);
    font-size: 0.6rem;
    color: var(--color-text-secondary);
    background: var(--color-bg-subtle);
    border: none;
    padding: 0.5rem 0.75rem;
    cursor: pointer;
    transition: background 120ms ease, color 120ms ease;
}

.arcade-segment-btn + .arcade-segment-btn {
    border-left: 1px solid var(--color-border);
}

.arcade-segment-btn.active {
    background: var(--color-cyan);
    color: #0A0E1A;
    text-shadow: none;
}

.arcade-segment-btn:hover:not(.active) {
    color: var(--color-text-primary);
    background: var(--color-bg-elevated);
}

/* The arcade title is the loudest thing on the page; on a narrow viewport
   (the fridge at 720px, a phone) it plus its subtitle plus a header action
   crowd everything below, so tighten the type and let the header breathe. */
@media (max-width: 575.98px) {
    .arcade-title { font-size: 1.1rem; }
    .arcade-subtitle { font-size: 0.55rem; }
    .arcade-section-heading { font-size: 0.85rem; }
    .arcade-header { margin-bottom: 1.5rem; row-gap: 0.75rem; }
    .arcade-status { align-items: flex-start; }
}
