/* ======================================================================
   Ate-bit — Arcode theme
   ====================================================================== */

:root {
    /* ── Arcode brand tokens ─────────────────────────────────────── */
    --color-bg-base:         #1A1F2E;
    --color-bg-surface:      #222840;
    --color-bg-elevated:     #2A3050;
    --color-bg-subtle:       #1E2338;

    --color-cyan:            #00D4FF;
    --color-magenta:         #C850C0;
    --color-purple:          #8B5CF6;

    --color-primary:         var(--color-cyan);
    --color-primary-hover:   #00BBDD;
    --color-secondary:       var(--color-magenta);
    --color-secondary-hover: #A830A0;

    --color-danger:          #FF4D6A;
    --color-danger-hover:    #E03055;
    --color-success:         var(--color-cyan);
    --color-warning:         #F59E0B;

    --color-text-primary:    #FFFFFF;
    --color-text-secondary:  #A0AABB;
    --color-text-muted:      #5A6480;

    --color-border:          #2E3550;
    --color-border-subtle:   #252B42;
    --color-border-focus:    var(--color-cyan);

    /* Ghost-control outline. Translucent, not a fixed hue: #2E3550 was tuned against the base
       background and disappears on anything lighter — group header rows, selected rows, the
       expanded detail band. A white alpha reads at the same perceived weight on every surface a
       row button lands on (design system rule 4). */
    --color-border-ghost:    rgba(255, 255, 255, 0.16);

    /* The touch floor: Ate-bit targets a 720x1080 touch fridge, so any interactive
       control clears 48px in at least one dimension (design system rule 10). */
    --touch-min:             48px;

    --gradient-brand:        linear-gradient(135deg, var(--color-magenta) 0%, var(--color-purple) 50%, var(--color-cyan) 100%);
    --gradient-glow-cyan:    radial-gradient(ellipse at center, rgba(0,212,255,0.15) 0%, transparent 70%);
    --gradient-glow-magenta: radial-gradient(ellipse at center, rgba(200,80,192,0.15) 0%, transparent 70%);

    /* ── Legacy atebit-* aliases so existing component code keeps working ── */
    --atebit-primary:          var(--color-cyan);
    --atebit-primary-hover:    var(--color-primary-hover);
    --atebit-primary-active:   #009AB8;
    --atebit-secondary:        var(--color-magenta);
    --atebit-secondary-hover:  var(--color-secondary-hover);
    --atebit-accent:           var(--color-magenta);
    --atebit-accent-hover:     var(--color-secondary-hover);
    --atebit-success:          var(--color-cyan);
    --atebit-danger:           var(--color-danger);
    --atebit-warning:          var(--color-warning);
    --atebit-info:             var(--color-cyan);

    --atebit-bg:               var(--color-bg-base);
    --atebit-surface:          var(--color-bg-surface);
    --atebit-fg:               var(--color-text-primary);
    --atebit-muted:            var(--color-text-secondary);
    --atebit-border:           var(--color-border);
    --atebit-text:             var(--color-text-primary);

    --atebit-sidebar-bg:       #161B28;
    --atebit-sidebar-active:   var(--color-cyan);
    --atebit-sidebar-active-fg:#0A0E1A;
    --atebit-thead-bg:         var(--color-bg-subtle);
    --atebit-thead-fg:         var(--color-text-muted);
    --atebit-row-hover:        var(--color-bg-elevated);
    --atebit-soft-accent:      var(--color-bg-elevated);
    --atebit-soft-accent-bd:   var(--color-border);

    /* ── Bootstrap CSS variable overrides ─────────────────────────── */
    --bs-primary:            var(--color-cyan);
    --bs-primary-rgb:        0, 212, 255;
    --bs-secondary:          var(--color-magenta);
    --bs-secondary-rgb:      200, 80, 192;
    --bs-success:            var(--color-cyan);
    --bs-success-rgb:        0, 212, 255;
    --bs-danger:             var(--color-danger);
    --bs-danger-rgb:         255, 77, 106;
    --bs-warning:            var(--color-warning);
    --bs-warning-rgb:        245, 158, 11;
    --bs-info:               var(--color-cyan);
    --bs-info-rgb:           0, 212, 255;

    /* Bootstrap 5.3's tint families (AB#880). Overriding --bs-primary alone only moves the solid colour;
       the low-contrast partners it ships alongside — used by bg-*-subtle, text-*-emphasis,
       border-*-subtle and by the meal plan's drag states — keep resolving to Bootstrap's own blue and
       grey, so a "subtle primary" surface came out navy next to a cyan border.

       Values follow Bootstrap's own dark-mode recipe against the brand colours: emphasis is the colour
       40% of the way to white, bg-subtle is 20% of it, border-subtle 60%. Written as static hex on
       purpose — color-mix() would say this in one line but landed in Chromium 111, and the fridge is on
       M94. Recompute these if a brand colour changes; nothing derives them at runtime.

       Not set: the light-* and dark-* families. Ate-bit is dark-only and overrides neither --bs-light nor
       --bs-dark, so there is no brand answer to derive and a guess would be worse than Bootstrap's. */
    --bs-primary-text-emphasis:     #66E5FF;
    --bs-primary-bg-subtle:         #002A33;
    --bs-primary-border-subtle:     #007F99;

    --bs-success-text-emphasis:     #66E5FF;
    --bs-success-bg-subtle:         #002A33;
    --bs-success-border-subtle:     #007F99;

    --bs-info-text-emphasis:        #66E5FF;
    --bs-info-bg-subtle:            #002A33;
    --bs-info-border-subtle:        #007F99;

    --bs-secondary-text-emphasis:   #DE96D9;
    --bs-secondary-bg-subtle:       #281026;
    --bs-secondary-border-subtle:   #783073;

    --bs-danger-text-emphasis:      #FF94A6;
    --bs-danger-bg-subtle:          #330F15;
    --bs-danger-border-subtle:      #992E40;

    --bs-warning-text-emphasis:     #F9C56D;
    --bs-warning-bg-subtle:         #312002;
    --bs-warning-border-subtle:     #935F07;

    --bs-body-bg:            var(--color-bg-base);
    --bs-body-color:         var(--color-text-primary);
    --bs-border-color:       var(--color-border);
    --bs-border-color-translucent: rgba(46, 53, 80, 0.5);

    /* Bootstrap 5.3's neutral surface and text scale (AB#880). data-bs-theme="dark" supplies these, but
       from Bootstrap's own warm greys — #343a40 and #2b3035 — which read as a different material next to
       Ate-bit's navy. The meal plan is where it showed: its headers and day-total row are built on these
       two variables, so a grey band sat across a navy page. Mapped onto the brand surfaces in the same
       order Bootstrap stacks them (body < tertiary < secondary), so relative depth still reads. */
    --bs-secondary-bg:       var(--color-bg-elevated);
    --bs-tertiary-bg:        var(--color-bg-surface);
    --bs-secondary-color:    var(--color-text-secondary);
    --bs-tertiary-color:     var(--color-text-muted);

    --bs-link-color:         var(--color-cyan);
    --bs-link-color-rgb:     0, 212, 255;
    --bs-link-hover-color:   var(--color-primary-hover);
    --bs-link-hover-color-rgb: 0, 187, 221;

    --bs-modal-bg:           var(--color-bg-surface);
    --bs-card-bg:            var(--color-bg-surface);
    --bs-card-border-color:  var(--color-border);

    --bs-dropdown-bg:        var(--color-bg-elevated);
    --bs-dropdown-color:     var(--color-text-primary);
    --bs-dropdown-border-color: var(--color-border);
    --bs-dropdown-link-color: var(--color-text-primary);
    --bs-dropdown-link-hover-bg: rgba(0, 212, 255, 0.08);
    --bs-dropdown-link-hover-color: var(--color-text-primary);

    --bs-table-color:        var(--color-text-secondary);
    --bs-table-bg:           transparent;
    --bs-table-hover-bg:     var(--color-bg-elevated);
    --bs-table-border-color: var(--color-border-subtle);

    --bs-nav-tabs-border-color: var(--color-border);
    --bs-nav-tabs-link-hover-border-color: var(--color-border);
    --bs-nav-tabs-link-active-bg: var(--color-bg-surface);
    --bs-nav-tabs-link-active-border-color: var(--color-border) var(--color-border) var(--color-bg-surface);
    --bs-nav-tabs-link-active-color: var(--color-cyan);

    --bs-list-group-bg: var(--color-bg-surface);
    --bs-list-group-border-color: var(--color-border);
    --bs-list-group-color: var(--color-text-primary);
    --bs-list-group-hover-bg: var(--color-bg-elevated);
    --bs-list-group-action-color: var(--color-text-primary);
    --bs-list-group-active-bg: var(--color-cyan);
    --bs-list-group-active-border-color: var(--color-cyan);
}

/* ── Body ──────────────────────────────────────────────────────────── */
body {
    background-color: var(--color-bg-base);
    color: var(--color-text-primary);
    font-family: 'Inter', system-ui, sans-serif;
}

h1, h2, h3, h4, h5, h6 {
    font-family: 'Space Grotesk', system-ui, sans-serif;
    letter-spacing: -0.02em;
}

/* ── Buttons ───────────────────────────────────────────────────────── */
.btn-primary {
    --bs-btn-bg:                  var(--color-cyan);
    --bs-btn-border-color:        var(--color-cyan);
    --bs-btn-hover-bg:            var(--color-primary-hover);
    --bs-btn-hover-border-color:  var(--color-primary-hover);
    --bs-btn-active-bg:           #009AB8;
    --bs-btn-active-border-color: #009AB8;
    --bs-btn-disabled-bg:         var(--color-cyan);
    --bs-btn-disabled-border-color: var(--color-cyan);
    --bs-btn-color:               #0A0E1A;
    --bs-btn-hover-color:         #0A0E1A;
    --bs-btn-active-color:        #0A0E1A;
    color: #0A0E1A;
    font-weight: 700;
    letter-spacing: 0.02em;
}
.btn-primary:hover,
.btn-primary:focus {
    background-color: var(--color-primary-hover);
    border-color: var(--color-primary-hover);
    color: #0A0E1A;
    box-shadow: 0 0 16px rgba(0, 212, 255, 0.35);
}

.btn-secondary {
    --bs-btn-bg:               transparent;
    --bs-btn-border-color:     var(--color-cyan);
    --bs-btn-hover-bg:         rgba(0, 212, 255, 0.08);
    --bs-btn-hover-border-color: var(--color-cyan);
    --bs-btn-color:            var(--color-cyan);
    --bs-btn-hover-color:      var(--color-cyan);
    color: var(--color-cyan);
    border-color: var(--color-cyan);
    font-weight: 600;
}

.btn-success {
    --bs-btn-bg:              var(--color-cyan);
    --bs-btn-border-color:    var(--color-cyan);
    --bs-btn-hover-bg:        var(--color-primary-hover);
    --bs-btn-hover-border-color: var(--color-primary-hover);
    --bs-btn-color:           #0A0E1A;
    --bs-btn-hover-color:     #0A0E1A;
    color: #0A0E1A;
}

.btn-danger {
    --bs-btn-bg:              var(--color-danger);
    --bs-btn-border-color:    var(--color-danger);
    --bs-btn-hover-bg:        var(--color-danger-hover);
    --bs-btn-hover-border-color: var(--color-danger-hover);
}
.btn-danger:hover,
.btn-danger:focus {
    box-shadow: 0 0 12px rgba(255, 77, 106, 0.3);
}

.btn-warning {
    --bs-btn-bg:              var(--color-warning);
    --bs-btn-border-color:    var(--color-warning);
    --bs-btn-color:           #0A0E1A;
    --bs-btn-hover-bg:        #D97706;
    --bs-btn-hover-border-color: #D97706;
    --bs-btn-hover-color:     #0A0E1A;
    color: #0A0E1A;
}

/* Filter-bar toggles (Category, Brand, source filters, Group). Bootstrap's .active state fills
   these solid grey, which reads as a second filled button next to the page's primary action;
   the design system keeps active filters as a cyan outline instead (one filled button per screen). */
.btn-outline-secondary.active {
    --bs-btn-active-bg: var(--color-bg-surface);
    --bs-btn-active-border-color: var(--color-cyan);
    --bs-btn-active-color: var(--color-cyan);
}

.btn-outline-primary {
    --bs-btn-color:            var(--color-cyan);
    --bs-btn-border-color:     var(--color-cyan);
    --bs-btn-hover-bg:         rgba(0, 212, 255, 0.08);
    --bs-btn-hover-border-color: var(--color-cyan);
    --bs-btn-hover-color:      var(--color-cyan);
    --bs-btn-active-bg:        var(--color-cyan);
    --bs-btn-active-border-color: var(--color-cyan);
    --bs-btn-active-color:     #0A0E1A;
}

/* ── Focus ring ────────────────────────────────────────────────────── */
/* Buttons ring on :focus-visible, not :focus. A mouse click leaves focus on the button, so under :focus
   the ring stayed lit after the press and a toggle button read as still on: the pantry's Staples filter
   looked identical switched off with focus as it did switched on. A ring that can mean "pressed" is
   worse than no ring for a pointer user, and keyboard users lose nothing — :focus-visible is exactly the
   "reached this without a pointer" signal, and it is Chromium M86, inside the fridge's M94.

   Fields keep plain :focus below. A text box has to show where typing will land however it was reached,
   and unlike a button it carries no pressed state the ring could be mistaken for. */
.btn:focus-visible,
.btn:active:focus-visible,
.btn-link.nav-link:focus-visible {
    box-shadow: 0 0 0 3px rgba(0, 212, 255, 0.2);
    border-color: var(--color-border-focus);
}

.form-check-input:focus,
.form-control:focus,
.form-select:focus {
    box-shadow: 0 0 0 3px rgba(0, 212, 255, 0.2);
    border-color: var(--color-border-focus);
}

/* ── Links ─────────────────────────────────────────────────────────── */
a, .btn-link {
    color: var(--color-cyan);
}
a:hover {
    color: var(--color-primary-hover);
}

/* ── Sidebar ───────────────────────────────────────────────────────── */
.sidebar {
    background-image: none !important;
    background-color: #161B28 !important;
}

.top-row.navbar.navbar-dark {
    background-color: var(--color-bg-base) !important;
    border-bottom: 1px solid var(--color-border) !important;
}

/* Active nav item — 3px cyan left accent */
.nav-item ::deep a.active,
.nav-item a.active {
    background-color: var(--color-bg-elevated) !important;
    color: var(--color-cyan) !important;
    border-radius: 0 !important;
    font-weight: 600;
}
.nav-item ::deep a.active .nav-menu-icon,
.nav-item a.active .nav-menu-icon {
    color: var(--color-cyan) !important;
}

/* ── Tables (QuickGrid) ────────────────────────────────────────────── */
.table {
    --bs-table-color:        var(--color-text-secondary);
    --bs-table-bg:           var(--color-bg-surface);
    --bs-table-hover-bg:     var(--color-bg-elevated);
    --bs-table-hover-color:  var(--color-text-primary);
    --bs-table-border-color: var(--color-border-subtle);
    color: var(--color-text-secondary);
    border-color: var(--color-border-subtle);
}

/* Bootstrap still paints cell striping/hover as an inset 9999px box-shadow in 5.3, so this kill is
   still required. What changed: the shadow now reads --bs-table-bg-state then --bs-table-bg-type
   before falling back to the old --bs-table-accent-bg, which is why that variable is no longer set
   above — overriding one name in a three-deep fallback chain would not have covered the other two.
   Killing the shadow outright does. */
.table > :not(caption) > * > * {
    background-color: var(--color-bg-surface) !important;
    box-shadow: none !important;
    border-bottom-color: var(--color-border-subtle) !important;
    color: var(--color-text-secondary);
}

/* Main thead: darkest stripe */
.table > thead > tr > * {
    background-color: var(--color-bg-base) !important;
    color: var(--color-text-muted) !important;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    border-bottom-color: var(--color-border) !important;
}

/* Item group header rows (tr.table-secondary): elevated, clearly distinct */
.table > tbody > tr.table-secondary > * {
    background-color: var(--color-bg-elevated) !important;
    color: var(--color-text-primary) !important;
    border-top: 2px solid var(--color-border) !important;
    border-bottom-color: var(--color-border) !important;
}

/* Sub-column header rows (tr.table-light within tbody): subtle, muted */
.table > tbody > tr.table-light > * {
    background-color: var(--color-bg-subtle) !important;
    color: var(--color-text-muted) !important;
    font-size: 0.8rem;
    border-bottom-color: var(--color-border) !important;
}

/* Category separator rows (tr.table-primary): cyan-tinted accent */
.table > tbody > tr.table-primary > * {
    background-color: rgba(0, 212, 255, 0.07) !important;
    color: var(--color-text-primary) !important;
    border-top: 1px solid rgba(0, 212, 255, 0.2) !important;
    border-bottom-color: rgba(0, 212, 255, 0.2) !important;
    font-weight: 600;
}

/* Row hover — skip on special row types that already have meaningful colors */
.table > tbody > tr:not(.table-secondary):not(.table-light):not(.table-primary):hover > * {
    background-color: var(--color-bg-elevated) !important;
    color: var(--color-text-primary) !important;
}

.table thead {
    background-color: var(--color-bg-base) !important;
    color: var(--color-text-muted);
    outline-color: var(--color-border) !important;
}

/* QuickGrid renders sortable column titles as a native <button> — browsers paint
   native widget chrome (e.g. ButtonFace) over background-color unless appearance is reset. */
.table > thead button.col-title {
    appearance: none;
    background: transparent;
    color: inherit;
    font: inherit;
}

.table-footer {
    background-color: var(--color-bg-subtle);
    border-top-color: var(--color-border);
    color: var(--color-text-secondary);
}

/* The column-options popover (the search/filter panel behind a column's hamburger). QuickGrid styles
   it for a light theme from its own scoped stylesheet — `background: white; border: 1px solid silver`,
   then `box-shadow: 0 3px 8px 1px #aaa; border-color: #ddd` from its default theme — which reads as a
   bright card floating over the dark grid.

   Themed here rather than on a page: every list grid with a ColumnOptions filter renders the same
   popover, so Pantry, Recipes, Brands, Ingredient Rules and Categories were all showing it. The
   !important is not decoration — the scoped bundle loads after this file, so plain rules of equal
   specificity would lose on order. */
/* QuickGrid's scoped bundle sets 0.1rem vertical cell padding, which makes grid rows visibly
   tighter than the hand-rolled list tables (Bootstrap's 0.5rem). Same !important-vs-load-order
   story as the .col-options override below: the scoped bundle loads after this file. Vertical
   only — the horizontal padding stays QuickGrid's, which carries its column-gap machinery. */
.quickgrid > tbody > tr > td {
    padding-top: 0.5rem !important;
    padding-bottom: 0.5rem !important;
}

.col-options,
.quickgrid[theme=default] .col-options {
    background: var(--color-bg-elevated) !important;
    border: 1px solid var(--color-border) !important;
    border-radius: 8px !important;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45) !important;
    color: var(--color-text-primary);
}

/* ── Form controls ─────────────────────────────────────────────────── */
.form-control,
.form-select {
    background-color: var(--color-bg-subtle);
    border-color: var(--color-border);
    color: var(--color-text-primary);
}
.form-control::placeholder {
    color: var(--color-text-muted);
}
.form-control:focus,
.form-select:focus {
    background-color: var(--color-bg-subtle);
    border-color: var(--color-border-focus);
    color: var(--color-text-primary);
    box-shadow: 0 0 0 3px rgba(0, 212, 255, 0.12);
}
/* Bootstrap 5.3 dropped its .form-control[readonly] rule entirely, so the override that used to
   undo its light #e9ecef background is gone with it (AB#882): readonly fields now inherit the dark
   background from the .form-control rule above, which is the same value the override was setting. */
.form-control:disabled,
.form-select:disabled {
    background-color: var(--color-bg-base);
    color: var(--color-text-muted);
    border-color: var(--color-border);
}
.form-label {
    color: var(--color-text-secondary);
}
.input-group-text {
    background-color: var(--color-bg-elevated);
    border-color: var(--color-border);
    color: var(--color-text-secondary);
}
/* ── Checkboxes, switches, and their touch targets ─────────────────── */
/* One convention, defined once (AB#931). The app used to draw checkboxes at five different sizes —
   13px bare native, 16px Bootstrap, 18px and 20px from inline styles, 24px from four separate scoped
   stylesheets — six of them never carried .form-check-input at all, so they missed the theme and
   rendered as browser-default controls on a dark surface, and the thing a finger actually had to hit
   ranged from 13px to 48px depending on the page.

   The box and the target are deliberately two different sizes. A 1.5rem tick is what the control
   should look like; a 48px slab beside a one-line row is not. So the box stays 1.5rem everywhere and
   the target is grown around it, either by the .form-check row below or by a wrapping label. */
.form-check-input {
    background-color: var(--color-bg-subtle);
    border-color: var(--color-border);
}
.form-check-input:checked {
    background-color: var(--color-cyan);
    border-color: var(--color-cyan);
}
.form-check-input[type=checkbox],
.form-check-input[type=radio] {
    width: 1.5rem;
    height: 1.5rem;
    flex: 0 0 auto;
}
/* A switch has to stay wider than it is tall or it stops reading as a switch, so it keeps its own
   proportions — but off the same 1.5rem height as the tick, so the two look like one family. */
.form-switch .form-check-input {
    width: 2.75rem;
    border-radius: 2em;
}

/* Bootstrap lays .form-check out with a float and a left padding, which leaves the box a 16px target
   and the label a ~24px strip. Flex at the touch floor instead, and stretch the label across the whole
   row — including the band above and below the box, which is dead space in Bootstrap's version. */
.form-check {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.625rem;
    min-height: var(--touch-min);
    padding-left: 0;
}
/* Above the label's overlay, so a tap on the box is handled by the box itself rather than forwarded. */
.form-check .form-check-input {
    position: relative;
    z-index: 1;
    float: none;
    margin-top: 0;
    margin-left: 0;
}
.form-check .form-check-label {
    flex: 1 1 auto;
    margin-bottom: 0;
    cursor: pointer;
}
/* A <label for> forwards its own clicks to the control it names, so stretching one over the row is
   what makes the row the target — no handler, no JS. Only a real <label> gets the overlay:
   MergeRecipeDialog renders a <span class="form-check-label"> inside a card that is itself one big
   label, and an overlay there would blanket the card with something that eats taps and toggles
   nothing. */
label.form-check-label::before {
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
}

/* The two wrapped shapes, for rows that are not .form-check. .check-target is a square column beside
   content the row needs for its own controls; .check-row is the full row, for rows where ticking is
   the only thing on offer. Both are <label>s wrapping the input, so clicks forward the same way. */
.check-target {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    min-width: var(--touch-min);
    min-height: var(--touch-min);
    margin-bottom: 0;
    cursor: pointer;
}
.check-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    min-height: var(--touch-min);
    min-width: 0;
    margin-bottom: 0;
    cursor: pointer;
}
/* Bootstrap's .form-check-input carries a 0.25em top margin for its float layout. Both wrappers
   centre the box themselves, so the margin only pushes it off-centre. */
.check-target .form-check-input,
.check-row .form-check-input {
    margin: 0;
}

input[type=search] {
    background-color: var(--color-bg-subtle);
    border-color: var(--color-border);
    color: var(--color-text-primary);
}
input[type=search]:focus {
    border-color: var(--color-border-focus);
    outline: none;
    box-shadow: 0 0 0 3px rgba(0, 212, 255, 0.12);
}

/* ── Modal / BlazorDialog ──────────────────────────────────────────── */
.modal-content {
    background-color: var(--color-bg-surface);
    border-color: var(--color-border);
    color: var(--color-text-primary);
}
.modal-header, .modal-footer {
    border-color: var(--color-border);
}

.blazor-dialog-content-wrapper {
    background-color: var(--color-bg-surface) !important;
    border: 1px solid var(--color-border) !important;
    color: var(--color-text-primary) !important;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5) !important;
}
/* One header chrome for every dialog (AB#926): a bordered bar with the title on the left and the
   close X on the right, whatever the dialog puts between them.

   BlazorDialog wraps everything a header is given in `.blazor-dialog-title`, so that inner div is
   the row, not `.blazor-dialog-header` itself. `margin-right: auto` on the heading is what pushes
   the optional aside (the wizards' step counter) and the X out to the far edge, which is why no
   dialog needs its own width or alignment styles on a header any more. */
.blazor-dialog-header {
    border-bottom-color: var(--color-border) !important;
    color: var(--color-text-primary);
    background-color: var(--color-bg-surface);
    align-items: center;
    /* Tighter than BlazorDialog's 1rem, because the close X is now a 48px square rather than a
       glyph: without this the chrome eats height the fixed-height editors need for their fields.
       !important for the same reason the border-colour above needs it — BlazorDialog's own
       stylesheet loads after this file, so an equal-specificity rule there would win. */
    padding: 0.6rem 1rem !important;
}
.blazor-dialog-header .blazor-dialog-title {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
}
.blazor-dialog-header .dialog-title {
    margin: 0 auto 0 0;
    font-size: 1.125rem;
    font-weight: 600;
}

/* The close X is a touch target first and a glyph second: BlazorDialog sizes its own button from a
   font-size, which lands well under the 48px floor on the fridge. Ours is a square that clears it. */
.blazor-dialog-header .blazor-dialog-close {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: var(--touch-min);
    height: var(--touch-min);
    margin: -0.5rem -0.5rem -0.5rem 0;
    padding: 0;
    float: none;
    font-size: 1rem;
    color: var(--color-text-muted);
    text-shadow: none;
    opacity: 1;
    border-radius: 0.375rem;
}
.blazor-dialog-header .blazor-dialog-close:hover,
.blazor-dialog-header .blazor-dialog-close:focus {
    color: var(--color-text-primary);
    background-color: var(--color-bg-elevated);
    opacity: 1;
}
.blazor-dialog-header .blazor-dialog-close:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(0, 212, 255, 0.2);
}

.blazor-dialog-body {
    color: var(--color-text-primary);
}

/* One height for every control in a dialog, the `-sm` variants included. The first pass exempted
   them on the theory that a full-cell-width field clears 48px across, but that left the recipe
   editor's ingredient rows visibly ragged: 31px inputs, a 35px stepper and a 48px delete in the
   same row. The stepper was always meant to match the row's delete button — its own comment in
   app.css says so — so the row lines up at the floor rather than below it. */
.blazor-dialog-body .form-control,
.blazor-dialog-body .form-select,
.blazor-dialog-body .input-group-text {
    min-height: var(--touch-min);
}

/* The native file picker. Bootstrap floats a short button inside the control with negative margins,
   which reads as a grey slab adrift in a taller box once the control is on the touch floor. This
   fills the height, squares off the seam, and puts it in the app's own colours. */
.blazor-dialog-body .form-control[type=file] {
    padding: 0;
    overflow: hidden;
}
.blazor-dialog-body .form-control[type=file]::file-selector-button {
    height: var(--touch-min);
    margin: 0 0.75rem 0 0;
    padding: 0 1rem;
    background-color: var(--color-bg-elevated);
    color: var(--color-text-primary);
    border: 0;
    border-right: 1px solid var(--color-border);
    border-radius: 0;
    cursor: pointer;
}
.blazor-dialog-body .form-control[type=file]::file-selector-button:hover {
    background-color: var(--color-border);
    color: var(--color-text-primary);
}

/* Dialogs that scroll get the app's own scrollbar, not the browser's default light one. Same
   treatment as `.body-container`; without it the What's New list painted a bright bar down the
   side of a dark dialog. */
.blazor-dialog-body,
.recipe-tab-content,
.pantry-tab-content {
    scrollbar-width: thin; /* Firefox */
    scrollbar-color: var(--color-border) transparent; /* Firefox */
}
.blazor-dialog-body::-webkit-scrollbar,
.recipe-tab-content::-webkit-scrollbar,
.pantry-tab-content::-webkit-scrollbar {
    width: 10px;
}
.blazor-dialog-body::-webkit-scrollbar-track,
.recipe-tab-content::-webkit-scrollbar-track,
.pantry-tab-content::-webkit-scrollbar-track {
    background: transparent;
}
.blazor-dialog-body::-webkit-scrollbar-thumb,
.recipe-tab-content::-webkit-scrollbar-thumb,
.pantry-tab-content::-webkit-scrollbar-thumb {
    background-color: var(--color-border);
    border-radius: 6px;
}
.blazor-dialog-body::-webkit-scrollbar-thumb:hover,
.recipe-tab-content::-webkit-scrollbar-thumb:hover,
.pantry-tab-content::-webkit-scrollbar-thumb:hover {
    background-color: var(--color-text-muted);
}

/* The footer sits on the subtle background so the commit row reads as a separate band from the body,
   and every control in a dialog clears the touch floor — the fridge is the reason, and a dialog is
   the one surface where a mis-tap costs the most. */
.blazor-dialog-footer {
    border-top-color: var(--color-border) !important;
    background-color: var(--color-bg-subtle);
    gap: 0.5rem;
    padding: 0.75rem 1rem !important;
}
.blazor-dialog-footer > :not(:last-child),
.blazor-dialog-footer > :not(:first-child) {
    margin-left: 0;
    margin-right: 0;
}
.blazor-dialog-footer .btn {
    min-height: var(--touch-min);
}
.blazor-dialog-container {
    background-color: rgba(0, 0, 0, 0.65);
}

/* ── Badges ────────────────────────────────────────────────────────── */
.badge {
    background-color: var(--color-bg-elevated);
    color: var(--color-text-primary);
    border: 1px solid var(--color-border);
}
.badge.bg-primary   { background-color: var(--color-cyan)    !important; color: #0A0E1A !important; border: none !important; }
.badge.bg-secondary { background-color: var(--color-magenta) !important; color: #fff !important; border: none !important; }
.badge.bg-success   { background-color: var(--color-cyan)    !important; color: #0A0E1A !important; border: none !important; }
.badge.bg-danger    { background-color: var(--color-danger)  !important; color: #fff !important; border: none !important; }
.badge.bg-warning   { background-color: var(--color-warning) !important; color: #0A0E1A !important; border: none !important; }
.badge.bg-info      { background-color: var(--color-cyan)    !important; color: #0A0E1A !important; border: none !important; }

/* ── Nav tabs ──────────────────────────────────────────────────────── */
.nav-tabs {
    border-bottom-color: var(--color-border);
}
.nav-tabs .nav-link {
    color: var(--color-text-secondary);
    border-color: transparent transparent var(--color-border);
}
.nav-tabs .nav-link:hover {
    color: var(--color-text-primary);
    border-color: var(--color-border) var(--color-border) var(--color-bg-surface);
}
.nav-tabs .nav-link.active {
    background-color: var(--color-bg-surface);
    border-color: var(--color-border) var(--color-border) var(--color-bg-surface);
    color: var(--color-cyan);
}

/* ── Cards ─────────────────────────────────────────────────────────── */
.card {
    background-color: var(--color-bg-surface);
    border-color: var(--color-border);
    color: var(--color-text-primary);
}
.card-header, .card-footer {
    background-color: var(--color-bg-subtle);
    border-color: var(--color-border);
}

/* ── List group ────────────────────────────────────────────────────── */
.list-group-item {
    background-color: var(--color-bg-surface);
    border-color: var(--color-border);
    color: var(--color-text-primary);
}
.list-group-item:hover {
    background-color: var(--color-bg-elevated);
}

/* ── Dropdowns ─────────────────────────────────────────────────────── */
.dropdown-menu {
    background-color: var(--color-bg-elevated);
    border-color: var(--color-border);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
}
.dropdown-item {
    color: var(--color-text-primary);
}
.dropdown-item:hover, .dropdown-item:focus {
    background-color: rgba(0, 212, 255, 0.08);
    color: var(--color-text-primary);
}
.dropdown-divider {
    border-color: var(--color-border);
}

/* ── Validation states ─────────────────────────────────────────────── */
.valid.modified:not([type=checkbox]) { outline: 1px solid var(--color-cyan); }
.invalid                              { outline: 1px solid var(--color-danger); }
.validation-message                   { color: var(--color-danger); }

/* ── Feedback admin table ──────────────────────────────────────────── */
/* Widths go on the header cells, NOT on `col` elements (AB#977). QuickGrid renders table/thead/tbody
   and no colgroup at all — verified against the shipped assembly, which contains no "colgroup" or
   "<col" string anywhere — so a `col.col-actions` selector matches nothing and never has. The first
   attempt at this bug rebalanced those percentages and changed nothing, because the browser had been
   ignoring every one of them: the table fell back to fixed layout's equal-share default, six columns
   at an identical width with Actions crushed to the 1% below.
   Under table-layout: fixed the widths are taken from the first row, so the thead cells are what set
   the columns.
   `.table.feedback-table` and not `.feedback-table` on purpose: app.css loads AFTER this file and
   sets `.table th.col-actions { width: 1% }` for shrink-to-content Actions columns everywhere else.
   That is the same specificity as `.feedback-table th.col-actions`, so on source order it would win
   and re-crush the column. The extra `.table` outranks it. Do not "simplify" it away.
   The min-width keeps Actions reachable: two 48px icon buttons plus the gap and cell padding need
   ~116px, and 13% clears that once the table is at least 64rem wide. Narrower than that the
   .overflow-x-auto wrapper scrolls, the way .waitlist-table below does. It was 18% when this column
   also held a View button; the date opens the message now, so the freed width went to Message. */
.feedback-table { table-layout: fixed; min-width: 64rem; }
.table.feedback-table th.col-date         { width: 12%; }
.table.feedback-table th.col-category     { width: 10%; }
.table.feedback-table th.col-submitted-by { width: 13%; }
.table.feedback-table th.col-page         { width: 14%; }
.table.feedback-table th.col-message      { width: 26%; }
.table.feedback-table th.col-status       { width: 12%; }
.table.feedback-table th.col-actions      { width: 13%; }

/* ── Waitlist admin table ──────────────────────────────────────────── */
/* Six columns of email addresses and UTM values do not fit 720px portrait, and squeezing them
   there wraps every cell to three lines. A min-width instead lets the .overflow-x-auto wrapper
   scroll on the fridge while the table still fills a desktop viewport.
   This table had `col.col-date` and `col.col-actions` width rules too, removed rather than ported
   to `th` (AB#977). They were dead for the same reason the feedback ones were, and the grid has
   always rendered correctly without them: it uses auto layout, so the columns size to content, and
   app.css's `.table th/td.col-actions` already gives the Actions column its shrink-to-content width.
   Reviving them as `th` rules would have changed a working table on the strength of intent nobody
   had verified. */
.waitlist-table { min-width: 46rem; }
