/* ── Self-hosted webfonts ──────────────────────────────────────────────────
   Manrope + DM Sans were loaded from fonts.googleapis.com until now, and the
   app's own CSP (style-src 'self'; font-src 'self' data:) blocked both the
   stylesheet and the font files -- so every public page silently rendered in
   the generic sans-serif fallback. Self-hosting fixes that without widening
   the CSP, and stops a visitor's IP being handed to a third party on a site
   that sells EU compliance. latin + latin-ext subsets only. */
/* latin-ext */
@font-face {
  font-family: 'DM Sans';
  font-style: italic;
  font-weight: 300;
  font-display: swap;
  src: url('../fonts/dm-sans-300-italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'DM Sans';
  font-style: italic;
  font-weight: 300;
  font-display: swap;
  src: url('../fonts/dm-sans-300-italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('../fonts/dm-sans-300-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('../fonts/dm-sans-300-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/dm-sans-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/dm-sans-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/dm-sans-500-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/dm-sans-500-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('../fonts/manrope-300-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('../fonts/manrope-300-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/manrope-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/manrope-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/manrope-600-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/manrope-600-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/manrope-700-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
  }
/* latin */
@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/manrope-700-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }
/* latin-ext */
@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url('../fonts/manrope-800-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
  }
/* latin */
@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url('../fonts/manrope-800-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }
/* ========================================
   QR SYSTEM - UNIFIED RESPONSIVE CSS
   ======================================== */

/* === CSS DESIGN TOKENS === */
:root {
    /* Brand */
    --color-primary:        #667eea;
    --color-primary-dark:   #5568d3;
    /* Status */
    --color-success:        #48bb78;
    --color-success-dark:   #38a169;
    --color-danger:         #e53e3e;
    --color-danger-dark:    #c53030;
    --color-warning:        #ecc94b;
    --color-warning-dark:   #d69e2e;
    --color-warning-text:   #744210;
    /* Neutral */
    --color-secondary:      #e2e8f0;
    --color-secondary-dark: #cbd5e0;
    --color-text:           #2c3e50;
    --color-text-muted:     #718096;
    --color-border:         #e2e8f0;
    --color-bg:             #f5f5f5;
    --color-bg-card:        #ffffff;
    /* Radius */
    --radius-sm:            6px;
    --radius-md:            12px;
    --radius-lg:            16px;
    /* Shadows */
    --shadow-sm:            0 2px 8px rgba(0,0,0,0.1);
    --shadow-md:            0 4px 20px rgba(0,0,0,0.15);
    /* Transitions */
    --transition:           0.2s ease;
}

/* Screen-reader-only utility */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0,0,0,0);
    white-space: nowrap;
    border: 0;
}

/* === RESET & BASE === */
/* Prevent full-page horizontal scrollbar on normal pages.
   wide-page bodies need horizontal scroll for tables/canvas. */
body:not(.wide-page) { overflow-x: clip; }
/* Backdrop hidden by default — only shown in media query when mobile menu opens */
#mob-backdrop { display: none; }

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
    background: var(--color-bg);
    color: var(--color-text);
    line-height: 1.6;
}

/* Pages with wide tables or complex layouts.
   On desktop the body holds at 1024px so the table never squishes.
   On mobile: the CONTAINER and all non-table content fits the viewport normally.
   Only the TABLE itself (inside .table-wrapper) gets a min-width so columns
   don't collapse — the wrapper provides the horizontal scroll. */
body.wide-page { min-width: 1024px; }
@media (max-width: 1080px) {
    /* Body and container reflow to viewport width */
    body.wide-page { min-width: 0; }
    body.wide-page .container,
    body.wide-page .container-medium { min-width: 0; }
    /* Canvas/designer pages keep a hard body min-width — the whole page scrolls */
    body.wide-page.canvas-page { min-width: 1024px; }
    /* The table (not the container) keeps its minimum so columns are usable.
       The .table-wrapper provides the horizontal scroll. */
    body.wide-page .table-wrapper {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        overscroll-behavior-x: contain;
        width: 100%;
    }
    body.wide-page .table-wrapper table {
        min-width: 700px;
    }
}

/* === NAVIGATION === */
.nav { 
    background: #3b5bdb;
    color: white;
    padding: 0 24px;
    height: 44px;
    display: flex;
    justify-content: space-between;
    align-items: stretch;
    gap: 0;
    flex-wrap: nowrap;
}

/* Mobile menu — hidden everywhere by default */
.nav-mobile-menu { display: none !important; }
.nav-mobile-menu.open { display: flex !important; flex-direction: column; }
.nav-burger { display: none; }

/* Admin variant - dark gray nav */
.nav-admin {
    background: #2d3748;
}

/* Alternative: Add class to body */
body.admin-page .nav {
    background: #2d3748;
}

body.client-page .nav {
    background: #3b5bdb;
}

.nav-left { 
    display: flex;
    gap: 0;
    align-items: stretch;
    flex-wrap: nowrap;
    flex: 1;
}

.nav-brand { 
    font-size: 15px;
    font-weight: 700;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 160px;
    height: 44px;               /* never push nav taller */
    display: flex;
    align-items: center;
    padding: 0 16px 0 0;
    margin-right: 8px;
    border-right: 1px solid rgba(255,255,255,0.15);
    color: white;
    text-decoration: none;
    flex-shrink: 0;
}
.nav-brand:hover { opacity: 0.85; color: white; background: none !important; }

.nav-links { 
    display: flex;
    align-items: stretch;
    gap: 0;
    flex-wrap: nowrap;
}

.nav a, .nav-links a, .nav-links span { 
    color: rgba(255,255,255,0.78);
    text-decoration: none;
    padding: 0 14px;
    border-radius: 0;
    transition: color 0.15s, background 0.15s;
    white-space: nowrap;
    font-size: 14px;
    display: flex;
    align-items: center;
    border-bottom: 2px solid transparent;
}

.nav-links a:hover {
    background: rgba(255,255,255,0.1);
    color: white;
}

/* Nav cart. The count sits ON the icon rather than after it, so the item never
   changes width as the count changes and the rest of the bar cannot shift.
   The [hidden] rule is not redundant: `.nav-links a` above sets display:flex,
   which outranks the HTML hidden attribute and would render the icon anyway. */
.nav-links a.nav-cart {
    position: relative;
    /* Full bar height and square, matching the text menu items rather than
       floating as a shorter chip. Width follows height via aspect-ratio, so the
       square holds if the bar height ever changes. */
    align-self: stretch;
    box-sizing: border-box;
    height: auto;
    aspect-ratio: 1;
    padding: 0;
    margin: 0 0 0 6px;
    border-radius: 0;
    border-bottom: none;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Transparent at rest like the other menu items, since it is now flush with
       them; the chip background is what made it read as a separate control. */
    background: transparent;
    /* Full white rather than the 0.78 the text links carry: now that the glyph
       follows currentColor, inheriting that alpha would have dimmed the icon
       against the labels it sits beside. */
    color: #fff;
}
.nav-links a.nav-cart:hover { background: rgba(255,255,255,0.1); }
/* On its own page the cart is the current menu item and says so the same way
   every other one does. It was the only item in the bar that stayed
   unchanged when you were standing on it — the comment below always claimed
   currentColor, but the stroke was hard-coded #fff, so no colour rule could
   ever reach the icon. */
.nav-links a.nav-cart.active {
    background: rgba(255,224,102,0.18);
    color: #ffe066;
}
.nav-links a.nav-cart svg {
    /* An SVG, not the emoji: a colour-glyph cart could never match the nav's
       white text and read as pasted on. currentColor keeps it in the palette. */
    width: 18px;
    height: 18px;
    display: block;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.nav-links a.nav-cart svg circle { fill: currentColor; stroke: none; }
.nav-links a.nav-cart[hidden] { display: none; }
/* The icon is always shown — it is the way into the cart, so hiding it when
   empty removed the entrance at the moment a customer had nothing in there
   yet. The BADGE is what disappears: it is absolutely positioned with a red
   fill and a 16px min-width, so an empty one is a meaningless red dot. */
.nav-links a.nav-cart .nav-cart-n:empty { display: none; }
/* Selector must stay at least as specific as `.nav-links span` above (0,2,0),
   which otherwise wins on specificity regardless of order and flattens the pill:
   it forces border-radius:0 and padding:0 14px, turning a 16px round badge into
   a 38px square block. */
.nav-links a.nav-cart .nav-cart-n {
    position: absolute;
    /* Inside the square, not overhanging it. The button is now full bar height,
       so a negative offset would clip against the bar edge again — the bug that
       turned the pill into a bare rectangle the first time. */
    top: 4px;
    right: 4px;
    left: auto;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    box-sizing: border-box;
    background: #e53e3e;
    color: #fff;
    /* Ring in the nav's own colour (#3b5bdb) so the pill reads as sitting on
       the bar rather than punched through it. */
    border: 1.5px solid #3b5bdb;
    border-radius: 999px;
    font-size: 10px;
    font-weight: 700;
    line-height: 13px;
    text-align: center;
    font-variant-numeric: tabular-nums;
    pointer-events: none;
}

.nav-links a.active { 
    background: transparent;
    color: #ffe066;
    font-weight: 600;
    border-bottom: 2px solid transparent;
}

/* === CONTAINERS === */
.container { 
    padding: 30px;
    max-width: 1400px;
    margin: 0 auto;
}

.container-small {
    padding: 30px;
    max-width: 600px;
    margin: 0 auto;  /* Container itself is centered */
}

/* Center all block elements within container-small */
.container-small > * {
    margin-left: auto;
    margin-right: auto;
}

/* Explicit centering for common block elements */
.container-small .card,
.container-small .section,
.container-small form,
.container-small .btn-block {
    margin-left: auto;
    margin-right: auto;
}

.container-medium {
    padding: 30px;
    max-width: 900px;
    margin: 0 auto;
}

/* === CARDS === */
.card { 
    background: white;
    padding: 30px;
    border-radius: 12px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    margin-bottom: 20px;
}

.section { 
    background: white;
    padding: 30px;
    border-radius: 12px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    margin-bottom: 30px;
}

.section h2 { 
    color: #2c3e50;
    margin-bottom: 20px;
    padding-bottom: 10px;
    border-bottom: 2px solid #ecf0f1;
    font-size: 20px;
}

/* === STATS CARDS === */
.stats { 
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 20px;
    margin-bottom: 30px;
}

.stat-card { 
    background: white;
    padding: 25px;
    border-radius: 12px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    border-left: 4px solid #667eea;
}

.stat-card h3 { 
    color: #7f8c8d;
    font-size: 14px;
    margin-bottom: 10px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.stat-card .value { 
    font-size: 36px;
    font-weight: bold;
    color: #2c3e50;
}

/* Progress bars */
.progress-bar { 
    background: #e0e0e0;
    height: 10px;
    border-radius: 5px;
    overflow: hidden;
    margin-top: 10px;
}

.progress-fill { 
    background: #667eea;
    height: 100%;
    transition: width 0.3s;
}

/* === FORMS === */
.form-group { 
    margin-bottom: 20px;
}

label { 
    display: block;
    margin-bottom: 8px;
    font-weight: 600;
    font-size: 14px;
    color: #2c3e50;
}

input, select, textarea { 
    width: 100%;
    padding: 12px;
    border: 2px solid #e2e8f0;
    border-radius: 6px;
    font-size: 14px;
    transition: border-color 0.3s, box-shadow 0.3s;
}
input[type="checkbox"],
input[type="radio"]
{
    width: auto;
}

input:focus, select:focus, textarea:focus { 
    outline: none;
    border-color: #667eea;
    box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}

/* ...but a field reached by keyboard gets the same ring as everything else.
   The rule above sets outline:none at a higher specificity than :focus-visible,
   so without this a tab into a form was the one place the cursor vanished. */
input:focus-visible, select:focus-visible, textarea:focus-visible {
    outline: 3px solid #1a202c;
    outline-offset: 2px;
}

.checkbox-group { 
    display: flex;
    align-items: center;
    gap: 10px;
}

.checkbox-group input[type="checkbox"] { 
    width: auto;
}

.input-group { 
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}

.help, .help-text { 
    font-size: 13px;
    color: #7f8c8d;
    margin-top: 5px;
    line-height: 1.4;
}

/* === BUTTONS === */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: auto;
    min-width: fit-content;
    padding: 10px 20px;
    background: var(--color-primary);
    color: white;
    text-decoration: none;
    border-radius: var(--radius-sm);
    border: none;
    cursor: pointer;
    font-size: 14px;
    font-weight: 500;
    line-height: 1.4;
    transition: background var(--transition), transform var(--transition), box-shadow var(--transition);
    text-align: center;
    white-space: nowrap;
    box-sizing: border-box;
    -webkit-appearance: none;
    appearance: none;
    vertical-align: middle;
}

button.btn { padding: 10px 20px; }

/* Globally prevent buttons from stretching to parent width */
button { width: fit-content; min-width: fit-content; }
input[type="submit"], input[type="button"], input[type="reset"] { width: fit-content; min-width: fit-content; }

.btn:hover {
    background: var(--color-primary-dark);
    transform: translateY(-1px);
    box-shadow: var(--shadow-sm);
}

/* ── Keyboard focus ─────────────────────────────────────────────────────────
   The ring was the same indigo as the primary buttons, so on the button you
   are most likely to be focusing it was indigo on indigo. And it applied to
   .btn alone: the quantity steppers, the ✕ removes, the sortable headers, the
   nav's dropdown buttons and every plain <a> had no focus style at all, so
   tabbing through a page lost the cursor entirely.

   A dark ring with a white gap, so it reads on white cards, on the indigo
   primary, on the red danger and on the blue navbar alike — one treatment
   rather than a colour per background.

   :focus-visible, not :focus — the browser shows this for keyboard and
   assistive navigation and withholds it from a mouse click, which is what
   makes a strong ring tolerable. */
:focus-visible,
.btn:focus-visible {
    outline: 3px solid #1a202c;
    outline-offset: 2px;
    box-shadow: 0 0 0 2px #fff;
}
/* On the navbar the page behind is dark, so invert: white ring, dark gap. */
.nav :focus-visible {
    outline-color: #fff;
    box-shadow: 0 0 0 2px rgba(26, 32, 44, .55);
}
/* An outline is drawn outside the element, so an ancestor that clips its
   overflow erases it. These three group their children deliberately and would
   have swallowed the ring on every control inside them. */
.row-pill:focus-within, .qty-step:focus-within,
.nav-dropdown-menu:focus-within { overflow: visible; }

.btn:active {
    transform: translateY(0);
}

/* Square icon-only button. Table action cells were mixing buttons whose height
   came from whatever glyph they held -- a ★ and a 🗑️ have different metrics, so
   two buttons with identical padding still came out different heights. Fixing
   the box instead of the padding makes a row of them line up regardless of what
   is inside. */
.icon-btn {
    width: 34px;
    height: 34px;
    padding: 0 !important;
    flex: 0 0 34px;
    font-size: 15px;
    line-height: 1;
}

/* "In use, but you may still proceed." Distinct from :disabled on purpose —
   a disabled control says the action is unavailable, and for a label picture it
   is not: the server names the designs that would lose their backdrop and lets
   the person decide. Amber rather than a pale red, because a washed-out red is
   exactly what :disabled looks like -- the one signal this state must not send.
   Solid fill, so it reads as a live button that wants a second thought. */
.btn.is-inuse {
    background: #dd6b20 !important;
    color: #fff !important;
    border: 1px solid #c05621 !important;
}
.btn.is-inuse:hover {
    background: #c05621 !important;
    color: #fff !important;
}

/* Disabled used to be opacity .45 on whatever colour the button already had,
   which turned a red Delete into a washed-out pink ghost -- it read as a
   rendering fault rather than as "you cannot do this yet". A disabled control
   states its own colour instead: flat, neutral, legible, obviously inert. */
.btn:disabled,
.btn[disabled],
button:disabled,
button[disabled] {
    background: #dfe3e8 !important;
    color: #7c8595 !important;
    border-color: #cfd6de !important;
    box-shadow: none !important;
    /* grayscale() rather than opacity: these buttons carry emoji, and an emoji
       keeps its own colours however pale you make the box behind it -- which is
       why a "disabled" 🗑️ still showed a bright red bin on a ghost background
       and read as a rendering fault. Desaturating the whole control greys the
       glyph too, so the button looks switched off instead of half-painted. */
    filter: grayscale(1);
    opacity: 0.95;
    cursor: not-allowed;
    transform: none !important;
    box-shadow: none !important;
    pointer-events: none;
}

/* Button sizes */
.btn-sm,
button.btn-sm,
a.btn-sm { 
    padding: 6px 12px !important;
    font-size: 13px !important;
    line-height: 1.4 !important;
    height: auto !important;
    min-height: unset !important;
    -webkit-appearance: none !important;
    appearance: none !important;
    box-sizing: border-box !important;
    vertical-align: middle !important;
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
}

.btn-lg {
    padding: 14px 28px;
    font-size: 16px;
}

/* Inline forms used alongside buttons — reset browser defaults */
form.inline-form,
form[style*="display:inline"],
form[style*="display: inline"] {
    display: inline !important;
    margin: 0;
    padding: 0;
    vertical-align: middle;
}

/* Reset type=submit button to look identical to type=button */
button[type="submit"].btn {
    margin: 0;
    vertical-align: middle;
    line-height: normal;
    -webkit-appearance: none;
    appearance: none;
}

.btn-block {
    width: 100%;
    display: block;
}

/* CONTENT-FIT BUTTONS ARE CENTRED IN THEIR IMMEDIATE PARENT.
   Buttons are content-width, so a lone one left-aligned in a full-width container
   reads as stranded rather than as that container's action.

   :only-child is what keeps this safe. A button that shares its parent belongs to
   a group — a toolbar, a form row, a pair of confirm/cancel — and those carry
   their own alignment, which an action bar may deliberately set to right. Only a
   button that IS the whole content of its parent gets centred, so this cannot
   reorder anything that was arranged on purpose.

   Auto margins on the inline-flex button, not display:block, which would drop the
   flex centring .btn uses for its own label and icon.

   .btn-center is the opt-in for a lone button that sits beside text and so is not
   technically an only-child; .btn-left opts back out. */
/* :only-of-type, not :only-child — a lone button usually sits BELOW text (a card
   with a title, a price and one action), so :only-child almost never matched the
   real cases. :only-of-type still means "the only button here", which keeps
   toolbars and confirm/cancel pairs out of scope. */
.card > .btn:only-of-type,
.panel > .btn:only-of-type,
.pack-card > .btn:only-of-type,
.stat-card > .btn:only-of-type,
.empty > .btn:only-of-type,
.empty-state > .btn:only-of-type,
form > .btn:only-of-type,
fieldset > .btn:only-of-type,
.btn-center {
    display: flex;
    width: fit-content;
    margin-left: auto;
    margin-right: auto;
}

.btn-left {
    margin-left: 0;
    margin-right: auto;
}

/* Button variants */
.btn-primary { background: var(--color-primary); }
.btn-primary:hover { background: var(--color-primary-dark); }

.btn-success { background: var(--color-success); }
.btn-success:hover { background: var(--color-success-dark); }

.btn-danger { background: var(--color-danger); }
.btn-danger:hover { background: var(--color-danger-dark); }

/* .btn-red is used by the Brand Assets delete buttons and had no rule at all,
   so a destructive action wore the same colour as every other button. Same red
   as .btn-danger, and the bin glyph is brightened out of the emoji font's
   muted grey — a delete control should be legible at a glance. */
.btn-red { background: var(--color-danger); color: #fff; }
.btn-red:hover { background: var(--color-danger-dark); }
.btn-red { font-size: 15px; line-height: 1; }
.btn-red, .btn-danger {
    /* The emoji renders in its own colours; this lifts it to full white so it
       reads against the red rather than sitting grey on it. */
    text-shadow: 0 0 1px rgba(255,255,255,.9);
    filter: saturate(1.35) brightness(1.15);
}

.btn-warning { background: var(--color-warning); color: var(--color-warning-text); }
.btn-warning:hover { background: var(--color-warning-dark); }

.btn-secondary { background: var(--color-secondary); color: #4a5568; }
.btn-secondary:hover { background: var(--color-secondary-dark); }

.btn-purple { 
    background: #805ad5;
}

.btn-purple:hover { 
    background: #6b46c1;
}

.btn-teal { 
    background: #38b2ac;
}

.btn-teal:hover { 
    background: #319795;
}

.btn-download {
    background: #48bb78;
}

.btn-download:hover {
    background: #38a169;
}

.btn-delete {
    background: #f56565;
}

.btn-delete:hover {
    background: #e53e3e;
}

/* === TABLES === */
table { 
    width: 100%;
    border-collapse: collapse;
    margin-top: 15px;
}

th { 
    background: #f7fafc;
    padding: 15px;
    text-align: left;
    font-weight: 600;
    color: #4a5568;
    font-size: 13px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    border-bottom: 2px solid #e2e8f0;
}

td { 
    padding: 15px;
    border-bottom: 1px solid #edf2f7;
    font-size: 14px;
    vertical-align: middle;
}

tr:hover { 
    background: #f8fafc;
}

/* Table responsive wrapper */
.table-wrapper {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
}
/* Table inside wrapper: natural width so it can overflow the wrapper.
   min-width:100% ensures it fills the wrapper when content is narrow. */
.table-wrapper table,
.at-wrap table,
.file-pane table,
.dash-panel table {
    width: max-content;
    min-width: 100%;
}

/* Any table with explicit width:100% inside a scrolling container
   must be able to grow beyond it. Override with min-width approach. */
@media (max-width: 900px) {
    .table-wrapper table,
    .at-wrap table,
    .file-pane table,
    .dash-panel table,
    .section table,
    .card table {
        width: max-content;
        min-width: 100%;
    }
}

/* === BADGES === */
.badge { 
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 11px;
    font-weight: bold;
    display: inline-block;
}

.badge-admin { 
    background: #922;
    color: white;
}

.badge-client { 
    background: #286;
    color: white;
}

.b-green { 
    background: #c6f6d5;
    color: #22543d;
}

.b-red { 
    background: #fed7d7;
    color: #742a2a;
}

.b-yellow {
    background: #fef3c7;
    color: #92400e;
}

.b-blue {
    background: #dbeafe;
    color: #1e40af;
}

/* === TABS === */
.tabs { 
    display: flex;
    border-bottom: 2px solid #e2e8f0;
    margin-bottom: 30px;
    gap: 10px;
    overflow-x: auto;
    overflow-y: visible;
    -webkit-overflow-scrolling: touch;
}

.tab-btn { 
    padding: 15px 25px;
    cursor: pointer;
    border: none;
    background: none;
    font-size: 16px;
    color: #718096;
    font-weight: 600;
    white-space: nowrap;
    transition: color 0.3s;
}

.tab-btn.active { 
    color: #667eea;
    border-bottom: 2px solid #667eea;
    margin-bottom: -2px;
}

.tab-btn:hover {
    color: #667eea;
}

.tab-btn:focus {
    outline: none;
    color: #667eea;
    box-shadow: inset 0 -2px 0 #667eea;
}

.tab-content { 
    display: none;
    animation: fadeIn 0.3s;
}

.tab-content.active { 
    display: block;
}

@keyframes fadeIn { 
    from { 
        opacity: 0;
        transform: translateY(5px);
    }
    to { 
        opacity: 1;
        transform: translateY(0);
    }
}

/* === ACTION BAR === */
.actions, .action-bar { 
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 20px;
}

.action-bar {
    justify-content: flex-end;
}

.action-btn {
    padding: 10px 20px;
    border-radius: 6px;
    border: none;
    cursor: pointer;
    color: #fff;
    font-weight: 500;
    font-size: 14px;
    transition: all 0.2s;
}

/* === ALERTS & MESSAGES === */
.error {
    background: #fee;
    border: 1px solid #fcc;
    padding: 12px;
    border-radius: var(--radius-sm);
    margin-bottom: 20px;
    color: #c33;
}

.success {
    background: #d1fae5;
    border: 1px solid #6ee7b7;
    padding: 12px;
    border-radius: var(--radius-sm);
    margin-bottom: 20px;
    color: #065f46;
}

.warning {
    background: #fef3c7;
    border: 1px solid #fde047;
    padding: 12px;
    border-radius: var(--radius-sm);
    margin-bottom: 20px;
    color: #92400e;
}

.info {
    background: #e0f2fe;
    border: 1px solid #7dd3fc;
    padding: 12px;
    border-radius: var(--radius-sm);
    margin-bottom: 20px;
    color: #075985;
}

/* Live-region status messages */
[role="status"], [aria-live] {
    min-height: 1.4em;
}

/* === USER INFO === */
.user-info {
    background: #f8f9fa;
    padding: 15px;
    border-radius: 8px;
    margin-bottom: 30px;
}

.user-info strong { 
    color: #2c3e50;
}

/* === TYPOGRAPHY === */
h1 { 
    color: #2c3e50;
    margin-bottom: 10px;
    font-size: 28px;
}

h2 {
    color: #2c3e50;
    font-size: 20px;
    margin-bottom: 15px;
}

h3 {
    color: #4a5568;
    font-size: 16px;
    margin-bottom: 10px;
}

.subtitle { 
    color: #7f8c8d;
    margin-bottom: 30px;
    font-size: 16px;
}

small {
    display: block;
    margin-top: 6px;
    color: #718096;
    font-size: 13px;
    line-height: 1.4;
}

/* === PAGINATION === */
.pagination {
    display: flex;
    gap: 5px;
    justify-content: center;
    margin-top: 20px;
    flex-wrap: wrap;
}

.pagination a, .pagination span {
    padding: 8px 12px;
    border: 1px solid #e2e8f0;
    border-radius: 4px;
    text-decoration: none;
    color: #4a5568;
}

.pagination a:hover {
    background: #f7fafc;
}

.pagination .active {
    background: #3b5bdb;
    color: white;
    border-color: #667eea;
}

/* === UTILITY CLASSES === */
.text-center { text-align: center; }
.text-right { text-align: right; }
.text-left { text-align: left; }

.mt-10 { margin-top: 10px; }
.mt-20 { margin-top: 20px; }
.mt-30 { margin-top: 30px; }

.mb-10 { margin-bottom: 10px; }
.mb-20 { margin-bottom: 20px; }
.mb-30 { margin-bottom: 30px; }

.p-10 { padding: 10px; }
.p-20 { padding: 20px; }
.p-30 { padding: 30px; }

.flex { display: flex; }
.flex-wrap { flex-wrap: wrap; }
.flex-center { justify-content: center; align-items: center; }
.gap-10 { gap: 10px; }
.gap-20 { gap: 20px; }

.hidden { display: none; }

/* === Extra (ranjan) === */

.alert { padding: 12px; border-radius: 6px; margin-bottom: 15px; }
.alert-error { background: #fed7d7; color: #742a2a; }
.alert-success { background: #c6f6d5; color: #22543d; }

.batch-logo { width: 40px; height: 40px; object-fit: contain; border: 1px solid #e2e8f0; border-radius: 4px; padding: 2px; background: white; }
.batch-info { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin-top: 15px; }
.batch-logo-placeholder { font-size: 24px; color: #cbd5e0; display: inline-block; width: 40px; text-align: center; }

/* Logo Grid */
.logo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); gap: 15px; }
.logo-option { border: 2px solid #ecf0f1; border-radius: 8px; padding: 10px; text-align: center; cursor: pointer; position: relative; transition: border 0.2s; }
.logo-option:hover { border-color: #bdc3c7; }
.logo-option.selected { border-color: #667eea; background: #f0f4ff; }
.logo-option img { width: 50px; height: 50px; object-fit: contain; }
.logo-option input { position: absolute; opacity: 0; cursor: pointer; height: 0; width: 0; }


/* === RESPONSIVE DESIGN === */

/* Tablets and below (max-width: 1080px) */
@media (max-width: 1080px) {
    .container { padding: 20px; }
    .stats { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; }
    .stat-card .value { font-size: 28px; }
    .section { padding: 20px; }
}

/* The bar itself holds on longer than the rest of the tablet layout: it now
   compresses down to 950px (see "Keep the nav inside the window" below), so the
   burger only takes over below that. Page padding still relaxes at 1080. */
@media (max-width: 949px) {
    /* Tablet nav — burger menu */
    .nav {
        padding: 0 12px;
        flex-wrap: wrap;
        align-items: flex-start;  /* top-align: keeps brand row 44px, menu below */
        min-height: 44px;
        overflow: visible;
        height: auto;
        /* Pin nav to viewport so it doesn't stretch with the 1024px body on narrow screens */
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        width: 100%;
        box-sizing: border-box;
        z-index: 500;
    }
    /* Compensate for fixed nav height so content isn't hidden underneath */
    body { padding-top: 44px; }
    /* Brand row height — nav-left and burger both 44px, flex-aligned */
    .nav-left { flex: 1; height: 44px; display: flex; align-items: center; }
    .nav-burger { height: 44px; align-items: center; justify-content: center; }
    .nav-left .nav-links,
    .nav-right,
    .nav-dropdown { display: none !important; }
    .nav-burger {
        display: flex !important;
        position: fixed;
        top: 0;
        left: 0;
        z-index: 501;
        height: 44px;
        width: 44px;
        padding: 0;
        flex-direction: column;
        gap: 5px;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        background: none;
        border: none;
    }
    /* Push brand right so it doesn't sit under the burger */
    .nav-left .nav-brand { margin-left: 48px; }
    .nav-burger span {
        display: block;
        width: 22px;
        height: 2px;
        background: white;
        border-radius: 2px;
    }
    .nav-mobile-menu {
        position: fixed;
        top: 0;
        left: 0;
        height: 100vh;
        height: 100dvh;       /* dynamic vh — excludes mobile browser chrome */
        width: 280px;
        max-width: calc(100vw - 40px);
        flex-direction: column;
        background: rgba(20,20,60,0.98);
        padding: 0;
        overflow: hidden;            /* drawer itself does NOT scroll */
        transform: translateX(-100%);
        transition: transform 0.28s ease;
        z-index: 600;
        box-shadow: 4px 0 24px rgba(0,0,0,0.3);
        display: flex !important;
    }
    /* Inner scroll container — this is what actually scrolls on Android */
    .mob-scroll-body {
        flex: 1 1 auto;
        min-height: 0;        /* CRITICAL: lets a flex child shrink so overflow works */
        height: 0;            /* forces the child to take remaining space, not content height */
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        overscroll-behavior: contain;
        padding-bottom: 24px;
    }
    .nav-mobile-menu.open { transform: translateX(0); }
    /* Overlay backdrop */
    #mob-backdrop {
        display: none;
        position: fixed; inset: 0;
        background: rgba(0,0,0,0.08);
        z-index: 599;
    }
    #mob-backdrop.open { display: block; }
    /* Close button inside drawer */
    .mob-menu-close {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0 14px;
        height: 44px;
        flex-shrink: 0;
        border-bottom: 1px solid rgba(255,255,255,0.12);
        font-size: 13px;
        font-weight: 600;
        color: rgba(255,255,255,0.7);
    }
    .mob-menu-close button {
        background: none; border: none; color: rgba(255,255,255,0.7);
        font-size: 20px; cursor: pointer; padding: 4px 6px;
        line-height: 1; width: fit-content;
    }
    .mob-menu-close button:hover { color: white; }
    /* Section heading labels */
    .mob-section-label {
        font-size: 10px;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: 1.2px;
        color: rgba(255,255,255,0.45);
        padding: 12px 16px 4px;
        margin-top: 4px;
    }
    .mob-section-label:first-child { margin-top: 0; padding-top: 8px; }
    .mob-subsection-label {
        font-size: 10px;
        font-weight: 600;
        letter-spacing: 0.6px;
        color: rgba(255,255,255,0.6);
        padding: 6px 16px 2px 28px;
    }
    /* Menu items — consistent left indent under section label */
    .mob-item {
        color: white !important;
        text-decoration: none;
        padding: 9px 16px 9px 28px;
        font-size: 14px;
        display: block;
        border-radius: 6px;
        margin: 0 8px;
    }
    .mob-item:hover { background: rgba(255,255,255,0.1); }
    .mob-item-warning {
        color: #ffcc80 !important;
        border-left: 3px solid #ed8936;
        padding-left: 25px;
        margin-bottom: 4px;
    }
    .mob-item-help {
        margin-top: 8px;
        border-top: 1px solid rgba(255,255,255,0.12);
        padding-top: 13px;
    }
    /* Top-level links — same indent as section labels, visually prominent */
    .mob-top-link {
        display: block;
        color: rgba(255,255,255,0.75) !important;
        text-decoration: none;
        padding: 10px 16px;
        font-size: 13px;
        font-weight: 600;
        letter-spacing: 0.3px;
        border-top: 1px solid rgba(255,255,255,0.1);
        margin-top: 4px;
    }
    .mob-top-link:hover { color: white !important; background: rgba(255,255,255,0.08); }
    /* Fallback for any plain <a> not classed mob-item */
    .nav-mobile-menu > a {
        color: white;
        text-decoration: none;
        padding: 9px 16px;
        font-size: 14px;
        display: block;
    }
    .nav-mobile-menu > a:hover { background: rgba(255,255,255,0.1); }
}

/* Mobile devices (max-width: 768px) */
@media (max-width: 768px) {
    /* Nav at 768px — inherits from 1024px block; just override padding */
    .nav { padding: 0 12px; }
    .nav-left .nav-links,
    .nav-right,
    .nav-dropdown { display: none !important; }
    .nav-left { flex: 1; height: 44px; overflow: hidden; }

    .nav-links {
        width: 100%;
        justify-content: flex-start;
    }
    .nav-links a {
        padding: 10px 15px;
        font-size: 14px;
    }
    
    .container, .container-small, .container-medium {
        padding: 15px;
    }
    
    .stats {
        grid-template-columns: 1fr;
        gap: 15px;
    }
    
    .stat-card {
        padding: 20px;
    }
    
    .stat-card .value {
        font-size: 32px;
    }
    
    .section {
        padding: 20px;
    }
    
    .card {
        padding: 20px;
    }
    
    h1 {
        font-size: 24px;
    }
    
    h2 {
        font-size: 18px;
    }
    
    /* Make tables scrollable on mobile — scroll attaches to the
       immediate wrapper, never to the page body.
       .table-wrapper is the explicit class; the selectors below
       catch bare tables inside cards/sections that lack a wrapper. */
    .table-wrapper {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        overscroll-behavior-x: contain;
    }

    /* Bare <table> inside common containers — make the container scroll.
       We do NOT change table display (breaks layout); instead we let the
       container scroll while the table keeps its natural min-width. */
    .card > table,
    .section > table,
    .container > table,
    .container-medium > table,
    .tab-content > table,
    .card > div > table,
    .section > div > table,
    .tab-content > div > table {
        min-width: 600px;
    }

    .card,
    .section,
    .tab-content {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        overscroll-behavior-x: contain;
    }

    table {
        min-width: 600px;
    }
    
    th, td {
        padding: 10px;
        font-size: 13px;
    }
    
    /* Stack form inputs */
    .input-group {
        grid-template-columns: 1fr;
    }
    
    /* Stack buttons */
    .actions, .action-bar {
        /* flex-direction: column; ranjan */
    }
    
    .btn {
        width: fit-content; /* ranjan */
        text-align: center;
    }
    
    /* Tabs */
    .tabs {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }
    
    .tab-btn {
        padding: 12px 20px;
        font-size: 14px;
    }
}

/* Small mobile devices (max-width: 480px) */
@media (max-width: 480px) {
    .container, .container-small {
        padding: 10px;
    }
    
    .nav {
        padding: 0 10px;  /* no vertical padding — keeps nav at 44px */
    }
    
    .nav-brand {
        font-size: 18px;
    }
    
    .nav-links a {
        padding: 8px 12px;
        font-size: 13px;
    }
    
    .stat-card {
        padding: 15px;
    }
    
    .stat-card h3 {
        font-size: 12px;
    }
    
    .stat-card .value {
        font-size: 28px;
    }
    
    .section, .card {
        padding: 15px;
    }
    
    .btn:not(.btn-sm) {
        padding: 10px 16px;
        font-size: 13px;
    }
    
    input, select, textarea {
        padding: 10px;
        font-size: 14px;
    }
}

/* Print styles */
@media print {
    .nav, .actions, .action-bar, .btn {
        display: none;
    }
    
    body {
        background: white;
    }
    
    .card, .section {
        box-shadow: none;
        border: 1px solid #ddd;
    }
}

/* nav-brand defined in base nav rules above */

/* ── Nav icon link ─────────────────────────────────────────────────────────── */
.nav-icon-link {
    color: white !important;
    padding: 0 14px !important;
    font-size: 14px !important;   /* match all other nav-links a items */
    opacity: 1;
    transition: opacity 0.2s;
}
.nav-icon-link:hover { opacity: 1; background: rgba(255,255,255,0.15) !important; }

/* ── Masquerade badge ──────────────────────────────────────────────────────── */
.masquerade-badge {
    background: rgba(237,137,54,0.18);
    color: #fbd38d;
    padding: 4px 6px 4px 10px;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: 6px;
    border: 1px solid rgba(237,137,54,0.4);
}
/* ✕ Stop — stands out as a distinct button */
.masquerade-badge a {
    color: white !important;
    background: #ed8936 !important;
    padding: 3px 8px !important;
    border-radius: 4px;
    font-size: 11px;
    font-weight: 700;
    text-decoration: none;
    white-space: nowrap;
    transition: background 0.15s;
}
.masquerade-badge a:hover { background: #c05621 !important; }

/* ── Dropdown nav ──────────────────────────────────────────────────────────── */
.nav-dropdown {
    position: relative;
    display: inline-block;
}

/* One-click sign out at the far right of the nav. Muted until hovered so it
   does not compete with the working links, then red — it ends the session, and
   a control with consequences should say so before it is clicked. Sized to a
   comfortable tap target rather than to the glyph. */
.nav .nav-signout,
a.nav-signout {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Full bar height and square, so it sits flush with the text menu items
       instead of floating as a shorter chip. Width follows height via aspect-ratio
       rather than a hardcoded px, so it stays square if the bar height changes. */
    align-self: stretch;
    height: auto;
    aspect-ratio: 1;
    /* padding must be zeroed for aspect-ratio to produce a square: the inherited
       `.nav a` rule adds 0 14px, and a 24px glyph plus 28px of padding measured
       47px wide against a 44px bar. */
    padding: 0;
    min-width: 44px;
    box-sizing: border-box;
    margin: 0 0 0 6px;
    border-radius: 0;
    /* Red at rest, not only on hover: on a blue nav the icon has to read as
       "this signs you out" before it is touched, and a muted glyph did not. */
    color: #fff;
    background: #e53e3e;
    /* Bigger and brighter: the glyph is the whole label, so at 16px it read as a
       decoration on a red square rather than as the control itself. Pure white on
       a slightly lifted red, with a faint glow so the stroke stays crisp against
       the fill instead of muddying into it. */
    font-size: 24px;
    line-height: 1;
    font-weight: 700;
    text-shadow: 0 0 10px rgba(255,255,255,0.55);
    text-decoration: none;
    transition: background 0.18s, color 0.18s, text-shadow 0.18s;
}
.nav .nav-signout:hover,
.nav .nav-signout:focus-visible {
    background: #f04747;
    color: #fff;
    text-shadow: 0 0 14px rgba(255,255,255,0.85);
}
.nav .nav-signout:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 1px;
}

.nav-dropdown-btn {
    /* Same size, weight, colour and box as a plain `.nav-links a`: these sit
       side by side in one bar and are the same kind of thing, but one was a
       500-weight 0.9-alpha button with 12px of padding on the left and none on
       the right, and the other a normal-weight 0.78-alpha link padded evenly.
       Dashboard read as dimmer and slightly adrift from Manage QR beside it. */
    color: rgba(255,255,255,0.78);
    background: transparent;
    border: none;
    border-radius: 0px;
    margin: 0;
    align-self: stretch;
    padding: 0 14px;
    cursor: pointer;
    font-size: 14px;
    font-weight: 400;
    font-family: inherit;
    line-height: 1;
    transition: background 0.2s, color 0.15s;
    white-space: nowrap;
    display: flex;
    align-items: center;
    gap: 5px;
    height: 44px;
    border-bottom: 2px solid transparent;
}
.nav-dropdown-btn:hover {
    /* 0.25 was twice as strong as the 0.1 a link hover uses, so moving along
       the bar made the buttons flash and the links barely respond. */
    background: rgba(255,255,255,0.1);
    color: white;
}
.nav-dropdown-btn.active {
    background: rgba(255,224,102,0.18);
    color: #ffe066;
    font-weight: 600;
}
.nav-dropdown-arrow { font-size: 10px; opacity: 0.8; }

.nav-dropdown-menu {
    display: none;
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    background: white;
    border-radius: 8px;
    box-shadow: 0 8px 30px rgba(0,0,0,0.15);
    min-width: 180px;
    z-index: 1000;
    overflow: hidden;
    padding: 4px 0;
}
.nav-dropdown-menu.open { display: block; }

.nav-dropdown-menu a {
    display: block;
    padding: 9px 16px;
    color: #2d3748 !important;
    font-size: 13px;
    text-decoration: none;
    transition: background 0.15s;
    white-space: nowrap;
    border-radius: 0;
}
.nav-dropdown-menu a:hover {
    background: #f7fafc !important;
    color: #667eea !important;
}
.nav-dropdown-menu a.active {
    background: rgba(255,224,102,0.2) !important;
    color: #3b5bdb !important;
    font-weight: 600;
}
.nav-dropdown-divider {
    height: 1px;
    background: #e2e8f0;
    margin: 4px 0;
}

/* === NESTED SUBMENU (Generate → QR Groups ▸ / Tools ▸) === */
/* The parent menu must let the flyout escape its box. */
.nav-dropdown-menu:has(.nav-submenu) { overflow: visible; }
.nav-submenu { position: relative; }
.nav-submenu-label {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    padding: 9px 16px; color: #2d3748; font-size: 13px; font-weight: 600;
    cursor: default; white-space: nowrap;
}
.nav-submenu-label:hover { background: #f7fafc; color: #667eea; }
.nav-submenu-label.active { color: #3b5bdb; }
/* Font-independent right-caret (CSS triangle) so it always renders. */
.nav-submenu-arrow {
    margin-left: auto;
    width: 0; height: 0;
    border-top: 5px solid transparent;
    border-bottom: 5px solid transparent;
    border-left: 6px solid #667eea;
    flex: none;
}
.nav-submenu:hover > .nav-submenu-label .nav-submenu-arrow { border-left-color: #3b5bdb; }
.nav-submenu-menu {
    display: none;
    position: absolute; top: -4px; left: 100%;
    background: white; border-radius: 8px;
    box-shadow: 0 8px 30px rgba(0,0,0,0.15);
    min-width: 180px; padding: 4px 0; z-index: 1100;
}
/* Open the flyout on hover (desktop) or when JS marks it open (keyboard/touch). */
.nav-submenu:hover > .nav-submenu-menu,
.nav-submenu.open > .nav-submenu-menu { display: block; }
.nav-submenu-menu a {
    display: block; padding: 9px 16px; color: #2d3748 !important;
    font-size: 13px; text-decoration: none; white-space: nowrap; transition: background 0.15s;
}
.nav-submenu-menu a:hover { background: #f7fafc !important; color: #667eea !important; }
.nav-submenu-menu a.active {
    background: rgba(255,224,102,0.2) !important; color: #3b5bdb !important; font-weight: 600;
}

/* === COLLAPSIBLE DISCLOSURE ARROW === */
.disclosure-arrow {
    display: inline-block;
    transition: transform .2s ease;
    flex-shrink: 0;
    line-height: 1;
}
details[open] > summary .disclosure-arrow { transform: rotate(90deg); }

/* === AUTH / LOGIN PAGE === */
body.auth-page {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
}

.login-container {
    background: white;
    padding: 40px;
    border-radius: 16px;
    box-shadow: 0 20px 60px rgba(0,0,0,0.3);
    width: 100%;
    max-width: 400px;
    margin: 20px; /* Safe padding for mobile */
}

.auth-page h1 {
    color: #333;
    margin-bottom: 30px;
    text-align: center;
    font-size: 24px;
}

.link {
    text-align: center;
    margin-top: 16px;
    font-size: 14px;
}

.link a {
    color: #667eea;
    text-decoration: none;
}

.link a:hover {
    text-decoration: underline;
}

.divider {
    border: none;
    border-top: 1px solid #e2e8f0;
    margin: 20px 0;
}

/* Base.html missing alert type */
.alert-warning {
    background: #fff3cd;
    border: 1px solid #ffeaa7;
    color: #856404;
}

/* Nav group separator */
.nav-group-sep {
    width:0; align-self:stretch; margin:0 10px;
    border-left:1px solid rgba(255,255,255,0.22);
    flex-shrink:0; pointer-events:none;
}
@media (max-width:1080px) { .nav-group-sep { display:none !important; } }



/* ── Help + "What next": one stack ───────────────────────────────────────────
   The container is the only thing pinned to the viewport. The buttons inside
   are in normal flow, so their spacing is a gap rather than a pair of top
   coordinates in two different files that had to be kept 46px apart by hand. */
#fab-stack {
    position: fixed; right: 14px; top: 52px;
    z-index: 9100;
    /* One row, and row-REVERSE: the DOM order is help then "What next" (the
       nav macro's button is appended into this container), while on screen the
       round help button stays hard against the right edge where it has always
       lived, with the wider pill to its left. */
    display: flex; flex-direction: row-reverse; align-items: center; gap: 8px;
    transition: top .15s;
}
#fab-stack.scrolled-down { top: 8px; }

/* Help button — top of the stack */
#help-fab {
    position:static;
    width:38px; height:38px; border-radius:50%;
    background:#38b2ac; color:#fff;
    display:flex; align-items:center; justify-content:center;
    font-size:18px; font-weight:700; text-decoration:none;
    box-shadow:0 3px 12px rgba(56,178,172,0.45); z-index:9100;
    transition:background 0.15s, box-shadow 0.15s;
}
#help-fab:hover { background:#2c9491; box-shadow:0 4px 16px rgba(56,178,172,0.6); }

/* Scroll FAB */
#scroll-fab {
    position:fixed; right:14px; top:50%; transform:translateY(-50%);
    width:42px; height:42px; border-radius:50%;
    /* Solid rather than 92% opaque: the arrow was competing with whatever
       happened to be behind it. */
    background:#ed8936; color:#fff;
    display:flex; align-items:center; justify-content:center;
    cursor:pointer; border:none;
    box-shadow:0 3px 10px rgba(0,0,0,0.22); z-index:8900;
    opacity:0; transition:opacity 0.2s, box-shadow 0.15s; pointer-events:none; padding:0; line-height:1;
}
/* The arrowhead is drawn, not typed. As a ▲/▼ glyph it sat visibly low in the
   circle: a triangle's ink fills only part of its em box, and flex centres the
   box, not the ink -- so the optical centre ended up below the geometric one
   and no amount of line-height fixed it across fonts. A border triangle is a
   real box exactly the size of the shape, so centring it centres what you see.
   One element, rotated for the other direction. */
#scroll-fab .sf-arrow {
    width:0; height:0;
    border-left:9px solid transparent;
    border-right:9px solid transparent;
    border-bottom:12px solid #fff;
    filter:drop-shadow(0 1px 1px rgba(0,0,0,.25));
    /* A triangle looks bottom-heavy when its bounding box is centred, because
       the visual mass sits low. One pixel up puts the apparent centre right. */
    margin-top:-1px;
}
#scroll-fab.is-down .sf-arrow { transform:rotate(180deg); margin-top:1px; }
#scroll-fab.visible { opacity:1; pointer-events:auto; }
#scroll-fab:hover { background:#dd6b20; box-shadow:0 4px 16px rgba(0,0,0,0.3); }
@media (max-width:1080px) { #scroll-fab { right:6px; } #fab-stack { right:10px; } }


/* === HELP FAB HEARTBEAT (new accounts) === */
@keyframes gs-heartbeat {
    0%, 100% { box-shadow: 0 0 0 0 rgba(255,215,0,0); opacity:1; }
    40%       { box-shadow: 0 0 0 6px rgba(255,215,0,0.35); opacity:1; }
    50%       { box-shadow: 0 0 0 10px rgba(255,215,0,0); opacity:0.75; }
}
#help-fab.heartbeat {
    animation: gs-heartbeat 4s ease-in-out infinite;
    background: #2c9491;
    border: 2px solid rgba(255,215,0,0.6);
}


/* === GLOBAL MODAL OVERLAY ===
   Light veil — no blur — consistent across all pages.
   Individual modals use .modal-overlay or .help-modal-overlay.
   Any element with role="dialog" or .modal-overlay gets this treatment. */
.modal-overlay,
.help-modal-overlay {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
}
/* The background veil colour — extremely light, no blur */
.modal-overlay { background: rgba(0,0,0,0.08) !important; }
.help-modal-overlay { background: rgba(0,0,0,0.08) !important; }

/* Hide FABs on help page (FABs are redundant when help is already open) */
body[data-page="help"] #fab-stack,
body[data-page="help"] #scroll-fab { display: none !important; }

/* Hide FABs behind the open mobile drawer */
body.mob-menu-open #fab-stack,
body.mob-menu-open #scroll-fab { display: none !important; }

/* Consistent page-title spacing across all pages */
.container > h1,
.container-medium > h1,
.container-small > h1,
.content > h1,
div > h1:first-of-type {
    margin: 20px 0 16px;
    font-size: 22px;
    font-weight: 700;
    color: var(--color-text);
    display: flex;
    align-items: center;
    gap: 8px;
}


/* ========================================
   MOBILE RESPONSIVE ENHANCEMENTS
   Patch: 2026-06 — systematic mobile pass
   ======================================== */

/* ── Responsive grid utilities ──────────────────────────────────────────────
   Use these classes instead of inline grid-template-columns where possible.
   .grid-2col : 2 columns on desktop → 1 column below 600px
   .grid-auto : auto-fill with 260px min (already used in many places inline)
   ─────────────────────────────────────────────────────────────────────────── */
.grid-2col {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 16px;
}
.grid-3col {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 16px;
}

/* ── Responsive inline grids — override hard columns below 600px ────────── */
@media (max-width: 600px) {
    /* Any inline grid that forces 2 equal columns */
    [style*="grid-template-columns:1fr 1fr"],
    [style*="grid-template-columns: 1fr 1fr"],
    [style*="grid-template-columns:repeat(2"],
    [style*="grid-template-columns: repeat(2"] {
        grid-template-columns: 1fr !important;
    }
    /* 3-col and 4-col inline grids collapse to single column on mobile */
    [style*="grid-template-columns:1fr 1fr 1fr"],
    [style*="grid-template-columns: 1fr 1fr 1fr"],
    [style*="grid-template-columns:repeat(3"],
    [style*="grid-template-columns: repeat(3"],
    [style*="grid-template-columns:1fr 1fr 1fr 1fr"],
    [style*="grid-template-columns:repeat(4"] {
        grid-template-columns: 1fr !important;
    }
    /* Compass grid for sheet margins — always keeps 3 columns */
    .compass-grid {
        grid-template-columns: 1fr 1fr 1fr !important;
    }
}

/* ── Batch-view logo row ─────────────────────────────────────────────────── */
@media (max-width: 640px) {
    /* The logo + details flex row in batch_view */
    .bv-logo-row {
        flex-direction: column !important;
        align-items: flex-start !important;
        gap: 14px !important;
    }
}

/* ── Pagination control ──────────────────────────────────────────────────── */
/* table_controls.html — wrap neatly on narrow screens */
@media (max-width: 640px) {
    /* Pagination container: stack show-rows + page buttons */
    .pagination-bar,
    /* target the inline-styled wrapper directly */
    [style*="justify-content: space-between"][style*="border-top: 1px solid"] {
        flex-wrap: wrap !important;
        gap: 10px !important;
    }
    /* Shrink First/Last buttons on small screens */
    .pagination-bar .btn,
    [style*="justify-content: space-between"][style*="border-top: 1px solid"] .btn {
        padding: 6px 10px !important;
        font-size: 12px !important;
    }
}

/* ── Stats bar (batches_list, dashboard) ─────────────────────────────────── */
@media (max-width: 640px) {
    /* quota/stats flex row: wrap and shrink the progress bar */
    .stats-bar {
        flex-wrap: wrap;
        gap: 10px;
    }
    .stats-bar .quota-progress {
        width: 80px !important;
    }
}

/* ── Action toolbar (dashboard batch selection bar) ─────────────────────── */
@media (max-width: 640px) {
    .action-toolbar {
        left: 8px !important;
        right: 8px !important;
        width: auto !important;
        font-size: 12px !important;
    }
}

/* ── Button row / form footer actions ───────────────────────────────────── */
@media (max-width: 480px) {
    /* Any flex row of buttons inside a .section or .card */
    .section > div[style*="display:flex"][style*="gap"],
    .card > div[style*="display:flex"][style*="gap"] {
        flex-wrap: wrap !important;
    }
    /* Buttons stay content-width on every screen size, mobile included. Only
       .btn-block opts into full width. A button stretched to its container reads
       as a banner and gives every action the same weight regardless of
       importance, so the stack of them loses its hierarchy. */
    .form-actions {
        flex-wrap: wrap;
    }
    .form-actions .btn:not(.btn-block) {
        width: fit-content;
        text-align: center;
    }
}

/* ── Users page role stat cards ─────────────────────────────────────────── */
@media (max-width: 640px) {
    .role-stats-grid {
        grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)) !important;
    }
}

/* ── Section headers (title + action button row) ────────────────────────── */
@media (max-width: 480px) {
    .section-header,
    .page-header {
        flex-wrap: wrap !important;
        gap: 10px !important;
    }
    .section-header h1,
    .section-header h2,
    .page-header h1,
    .page-header h2 {
        font-size: 18px !important;
    }
}

/* ── Generate page: use-case section grid ───────────────────────────────── */
@media (max-width: 600px) {
    #uc-category-row,
    .uc-row {
        grid-template-columns: 1fr !important;
    }
}

/* ── Help panel full-screen on mobile ───────────────────────────────────── */
@media (max-width: 768px) {
    #help-panel {
        width: 100% !important;
        right: 0 !important;
        border-radius: 0 !important;
    }
}

/* ── GS panel: inner padding tighter on mobile ───────────────────────────── */
@media (max-width: 640px) {
    #gs-panel-inner {
        padding: 14px 14px 18px !important;
    }
    #gs-panel.open {
        max-height: 88vh;
    }
}

/* ── Masquerade badge ────────────────────────────────────────────────────── */
@media (max-width: 949px) {
    .masquerade-badge {
        display: none; /* shown in mobile menu instead */
    }
}

/* ── body padding-top: fixed nav already adds 44px at ≤949px.
   On desktop the nav is in-flow so no body padding needed. ─────────────── */
@media (min-width: 950px) {
    body { padding-top: 0 !important; }
}



/* ── Compact batch-creation form layout ───────────────────────────────────
   .form-2col  : two equal columns, top-aligned, fields fill their column.
                 Collapses to single column below 600px.
   .col-span-2 : a field that needs full width spans both columns.
   .field-xs   : caps field width (e.g. Quantity, Delay dropdowns).
   .field-sm   : medium cap (e.g. short selects).
   .field-md   : wider cap (e.g. Batch Name).
   ─────────────────────────────────────────────────────────────────────── */

/* Two equal columns, top-aligned */
.form-2col {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0 28px;
    align-items: start;
}
.form-2col .form-group { margin-bottom: 18px; }

/* Full-width span inside the two-col grid */
.form-2col .col-span-2 { grid-column: 1 / -1; }

/* Width caps on .form-group wrapper */
.field-xs { max-width: 140px; }
.field-sm { max-width: 240px; }
.field-md { max-width: 400px; }

/* Inputs/selects always fill their (possibly capped) container */
.form-compact input,
.form-compact select,
.form-compact textarea { width: 100%; }

/* Submit button: fit-content, not full-width */
.form-compact button[type="submit"] {
    width: auto !important;
    min-width: 180px;
    padding: 12px 32px;
    font-size: 15px;
}

/* Global: all submit buttons default to fit-content */
button[type="submit"]:not(.btn-block) { width: auto; }

/* Collapse to single column on mobile */
@media (max-width: 600px) {
    .form-2col { grid-template-columns: 1fr; }
    .field-xs, .field-sm, .field-md { max-width: 100%; }
}

/* ── Global table scroll on mobile ────────────────────────────────────────
   Any table inside .section or .card gets horizontal scroll on narrow screens,
   even without an explicit .table-wrapper parent. */
@media (max-width: 768px) {
    .section, .card {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }
    .section > table,
    .card > table {
        min-width: 600px;
    }
}


/* Count on a nav item — used by Scan Follow-ups for work awaiting an answer.
   Sized to sit inside a menu label without changing the bar's height. */
.nav-badge {
    display: inline-block;
    min-width: 18px;
    padding: 1px 6px;
    margin-left: 6px;
    border-radius: 9px;
    background: #dd6b20;
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
    vertical-align: middle;
    font-variant-numeric: tabular-nums;
}
.nav-submenu-label .nav-badge { background: #e2e8f0; color: #7b341e; }


/* ── Client dashboard: compact, informative, actionable ──────────────────────
   Replaces four stacked cards that spent over a thousand pixels on nine
   numbers. Every stat is a link, because a number you cannot act on is
   decoration. */
.dash-strip {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
    gap: 10px;
    margin: 0 0 14px;
}
.dash-stat {
    /* Equal height, stated rather than inferred: the labels are of different
       lengths, so one wrapping to a second line used to leave its neighbours
       short and the strip looking ragged. A flex column with height:100% keeps
       every card the height of the tallest whatever its label does. */
    display: flex; flex-direction: column; justify-content: center;
    height: 100%; box-sizing: border-box;
    padding: 12px 14px; text-decoration: none;
    background: #fff; border: 1px solid #e2e8f0; border-radius: 10px;
    transition: border-color .15s, transform .15s;
}
.dash-strip { align-items: stretch; }
.dash-stat:hover { border-color: #667eea; transform: translateY(-1px); }
.dash-stat .n {
    display: block; font-size: 24px; font-weight: 800; color: #1a202c;
    line-height: 1.15; font-variant-numeric: tabular-nums;
}
.dash-stat .k {
    display: block; margin-top: 2px; font-size: 11px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .05em; color: #a0aec0;
}
.dash-stat.warn .n  { color: #c05621; }
.dash-stat.warn     { border-color: #fbd38d; }
.dash-stat.warn .k  { color: #b7791f; }
/* -is-alert, not -alert: `.alert` above is a notification box carrying
   padding and margin-bottom:15px, and a card wearing both would inherit that
   margin — knocking it out of a row whose whole point is equal-height cards.
   Latent rather than visible: the variant only renders when there is something
   pending. Same trap as the submissions pill, which was named `alert` too. */
.dash-stat.is-alert .n { color: #c53030; }
.dash-stat.is-alert    { border-color: #feb2b2; }
.dash-stat.is-alert .k { color: #c53030; }
.dash-stat.over .n  { color: #c53030; }

.dash-actions { display: flex; flex-wrap: wrap; gap: 9px; margin-bottom: 18px; }
.dash-actions .btn { font-size: 13.5px; padding: 9px 16px; }
.dash-pill {
    display: inline-block; margin-left: 6px; padding: 1px 7px; border-radius: 9px;
    background: #dd6b20; color: #fff; font-size: 11px; font-weight: 700;
}

.dash-cols {
    display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px;
    align-items: start;      /* cards size to content — no more 367px of nothing */
}
@media (max-width: 860px) { .dash-cols { grid-template-columns: 1fr; } }
.dash-card { background: #fff; border: 1px solid #e2e8f0; border-radius: 10px; padding: 6px 4px 4px; }
.dash-card-head {
    display: flex; justify-content: space-between; align-items: center;
    padding: 8px 14px 10px; font-size: 11px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .05em; color: #a0aec0;
}
.dash-card-head a { font-size: 11.5px; color: #667eea; text-decoration: none; text-transform: none; letter-spacing: 0; }
.dash-row {
    display: flex; align-items: center; gap: 10px; padding: 9px 14px;
    border-top: 1px solid #f1f5f9; text-decoration: none; color: inherit;
}
.dash-row:hover { background: #f8fafc; }
.dash-row-main { flex: 1; min-width: 0; }
.dash-row-main strong { display: block; font-size: 13.5px; color: #1a202c; }
/* The clickable part of a dashboard row. The row used to be the target, which
   left no room for a second link and made the date and counts beside it look
   clickable when they were not. */
.dash-code {
    display: block; font-size: 13.5px; font-weight: 600; color: #4c51bf;
    text-decoration: none; cursor: pointer;
}
.dash-code:hover { text-decoration: underline; }

/* The code, on any page that lists codes: click it for everything known about
   it. Only the code — these rows carry their own actions, and a row that
   navigates on any click cannot also hold them. */
.code-link {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    color: #4c51bf; cursor: pointer; text-decoration: none;
    border-bottom: 1px dashed rgba(76,81,191,.45);
}
.code-link:hover { border-bottom-style: solid; }
.dash-row-sub {
    display: block; font-size: 11.5px; color: #a0aec0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dash-row-when { font-size: 11.5px; color: #a0aec0; white-space: nowrap; }
.dash-row-acts { display: flex; gap: 10px; }
.dash-row-acts a { font-size: 12px; color: #667eea; text-decoration: none; }
.dash-kind {
    font-size: 10.5px; padding: 2px 8px; border-radius: 10px; white-space: nowrap;
    background: #edf2f7; color: #4a5568;
}
.dash-kind.k-ownership { background: #e9e8fd; color: #434190; }
.dash-kind.k-warranty_claim { background: #feebc8; color: #7b341e; }
.dash-kind.k-incident { background: #fed7d7; color: #822727; }
.dash-empty { padding: 18px 14px; font-size: 13px; color: #a0aec0; }

/* ── Quick links ─────────────────────────────────────────────────────────────
   The five steps of the batch-QR loop, in the order they happen: make codes,
   find them, get them out, watch the job, see them used.

   Deliberately NOT styled like .dash-library below. Those are state — a place
   with a count attached — and they sit at the foot of the page. These are
   actions and they sit at the top. All of them carry the same weight: the
   strip is one journey, and a filled first button made the remaining stops
   look optional.

   These do repeat nav items, which is why the earlier shortcut block was
   removed from this page. The difference is that the nav spreads this journey
   across four separate menus, two of them behind a hover; a tenant whose whole
   job is generating and using batches should not have to reassemble the order
   from a menu bar every visit. */
/* 10px to the library row below, 18px from the library to the stats: the two
   link rows belong together, and equal spacing would orphan them apart. */
.dash-quick { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 10px; }
.dash-quick a {
    display: inline-flex; align-items: center; gap: 7px;
    font-size: 13px; font-weight: 600; color: #4a5568; text-decoration: none;
    background: #fff; border: 1px solid #e2e8f0; border-radius: 8px;
    padding: 9px 15px; transition: border-color .15s, color .15s, box-shadow .15s;
}
.dash-quick a:hover {
    border-color: #667eea; color: #667eea;
    box-shadow: 0 1px 4px rgba(102,126,234,.16);
}
.dash-quick a .qi { font-size: 15px; line-height: 1; }
@media (max-width: 640px) {
    /* Four-plus pills wrapping into stubs is worse than a scrolling row: the
       order is the point, and wrapping hides where the journey restarts. */
    .dash-quick { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch;
                  padding-bottom: 4px; }
    .dash-quick a { white-space: nowrap; flex: 0 0 auto; }
}

/* The reusable material a batch is made from, sitting under the quick links.
   Deliberately still a pill where .dash-quick is a rounded rectangle: these
   carry counts and are things you HAVE, the strip above are things you DO, and
   the shape is what keeps two adjacent rows of links from reading as one
   undifferentiated wall of ten buttons.

   Raised from the footer treatment it had when it lived at the bottom of the
   page -- darker text, real weight, a count that stands out as a number rather
   than as punctuation, and a hover that lifts. Prominent enough to be seen
   before the work that needs it, not so loud that it competes with Generate. */
.dash-library { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 18px; }
.dash-library a {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: 13px; font-weight: 600; color: #3d4759; text-decoration: none;
    background: #fff; border: 1px solid #dbe2ec; border-radius: 999px;
    padding: 8px 16px;
    transition: border-color .15s, color .15s, box-shadow .15s, transform .15s;
}
.dash-library a:hover {
    border-color: #667eea; color: #4c51bf;
    box-shadow: 0 1px 4px rgba(102,126,234,.16);
    transform: translateY(-1px);
}
/* The count reads as a value, not as a trailing digit. */
.dash-library b {
    color: #4c51bf; background: #eef1fe; border-radius: 999px;
    padding: 1px 8px; font-size: 12px; margin-left: 1px;
}
@media (max-width: 640px) {
    .dash-library { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch;
                    padding-bottom: 4px; }
    .dash-library a { white-space: nowrap; flex: 0 0 auto; }
}


/* ── "What next" drawer ──────────────────────────────────────────────────────
   The workflow hint used to sit above the content on 21 pages, pushing the
   actual work down for guidance most people read once. It lives behind this
   button instead, directly under the help FAB. */
#what-next-fab {
    /* Positioned by #fab-stack, not by itself — see the stack rule above. */
    position: static;
    display: flex; align-items: center; gap: 6px;
    height: 38px; padding: 0 13px; border: none; border-radius: 19px;
    background: #5a67d8; color: #fff; cursor: pointer;
    font: inherit; font-size: 13px; font-weight: 600;
    box-shadow: 0 3px 12px rgba(90, 103, 216, .42);
    transition: background .15s, box-shadow .15s;
}
#what-next-fab:hover { background: #4c51bf; box-shadow: 0 4px 16px rgba(90,103,216,.6); }
/* On a narrow screen the label costs more than it explains. */
@media (max-width: 640px) {
    #what-next-fab span { display: none; }
    #what-next-fab { padding: 0; width: 38px; justify-content: center; }
}

#what-next-scrim {
    position: fixed; inset: 0; background: rgba(15, 23, 42, .35);
    z-index: 9190; animation: wnFade .15s ease-out;
}
@keyframes wnFade { from { opacity: 0; } to { opacity: 1; } }

#what-next-drawer {
    /* Parked off-screen with a transform, which still counts toward the page's
       scrollable width — it was adding 2px of horizontal scrollbar at every
       width above 1500px. Clipped at the root instead, so nothing a fixed
       overlay does can give the document a horizontal bar. */
    position: fixed; top: 0; right: 0; bottom: 0; width: 380px; max-width: 92vw;
    background: #fff; z-index: 9200;
    box-shadow: -8px 0 28px rgba(0, 0, 0, .18);
    transform: translateX(100%);
    transition: transform .22s ease-out;
    display: flex; flex-direction: column;
}
#what-next-drawer.open { transform: translateX(0); }
.wn-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 16px 18px; border-bottom: 1px solid #e2e8f0;
    font-size: 14px; font-weight: 700; color: #2d3748;
}
.wn-close {
    border: none; background: none; cursor: pointer; font-size: 16px; color: #a0aec0;
    padding: 4px 6px; line-height: 1;
}
.wn-close:hover { color: #4a5568; }
.wn-body { padding: 14px 18px 22px; overflow-y: auto; display: grid; gap: 11px; }
.wn-task { border: 1px solid #e2e8f0; border-radius: 9px; padding: 12px 14px; background: #f8fafc; }
.wn-task-title { font-size: 13.5px; font-weight: 600; color: #2d3748; margin-bottom: 4px; }
.wn-task-title a { color: #3b5bdb; text-decoration: none; }
.wn-task-desc { font-size: 12.5px; color: #718096; line-height: 1.55; }
.wn-task-prereq {
    margin-top: 7px; font-size: 11.5px; color: #d69e2e;
    background: #fffff0; border: 1px solid #f6e05e; border-radius: 5px; padding: 4px 8px;
}


/* ── Keep the nav inside the window ──────────────────────────────────────────
   The desktop bar needs about 1390px laid out at full size, but it was shown
   from 1081px up — so every window between those two sizes gave the whole PAGE
   a horizontal scrollbar, on a 1366px laptop as much as anywhere. Two changes:
   the bar compresses before it runs out of room (measured: the full-size bar
   needs ~1442px, so compression starts below 1500), and the mobile menu takes over
   while there is still room rather than 300px too late.

   Three steps now, not two. Two got the bar down to a measured 1070px, which is
   why the burger took over at 1080; the third trades the two pieces of text that
   are not menu items — the brand and the signed-in address — for the width the
   menu itself needs, and holds the full bar down to 950. */
/* Every tier below compresses the BAR only, never the dropdown panels: the
   child combinators keep these off `.nav-dropdown-menu a`, which is a plain
   `.nav-dropdown-menu a` (same specificity as `.nav a`) and so lost its
   `padding: 9px 16px` to whichever of the two came last in the file. That
   flattened every leaf item to the bar's own padding and left the panels
   uneven. A dropdown is a panel of its own; the bar running out of room is not
   a reason to shrink it. */
@media (min-width: 950px) and (max-width: 1499px) {
    .nav > a, .nav-links > a, .nav-links > span { padding: 0 9px; font-size: 13px; }
    .nav-brand { max-width: 120px; padding-right: 10px; margin-right: 4px; font-size: 14px; }
    .nav-dropdown-btn { padding: 0 9px; font-size: 13px; }
    .nav-links a.nav-cart { padding: 0 8px; }
    .nav-group-sep { display: none !important; }
}
@media (min-width: 950px) and (max-width: 1279px) {
    /* Tighter still: the arrow glyphs are decoration once things are this snug. */
    .nav > a, .nav-links > a, .nav-links > span { padding: 0 7px; font-size: 12.5px; }
    .nav-dropdown-btn { padding: 0 7px; font-size: 12.5px; }
    .nav-dropdown-arrow { display: none; }
}
@media (min-width: 950px) and (max-width: 1080px) {
    /* Last step before the burger, and the tightest it gets. A seventh top-level
       menu (Buy) pushed the bar's natural width to 1095px, so at 950 the menu
       items had begun to collide with the account controls — no horizontal
       scrollbar, because flex simply squeezed them into each other.
       The width comes from the two things in the bar that are not navigation:
       the brand, which is dropped here rather than truncated to a syllable —
       Dashboard sits immediately beside it and goes to the same place — and the
       signed-in address, cut to a stub. Both return above 1080. */
    /* .nav .nav-brand, not .nav-brand: the plain selector is the same
       specificity as the base rule and lost to it here, so the brand stayed and
       the bar stayed too wide. */
    .nav .nav-brand { display: none !important; }
    .js-current-username { max-width: 46px !important; }
    .nav { padding: 0 10px; }
    .nav > a, .nav-links > a, .nav-links > span { padding: 0 4px; font-size: 12px; }
    .nav-dropdown-btn { padding: 0 4px; font-size: 12px; }
    /* The avatar button keeps its inline padding, hence the specificity here. */
    #clientAvatar .nav-dropdown-btn, #adminAvatar .nav-dropdown-btn { padding: 4px 6px !important; }
    .js-current-username {
        display: inline-block; max-width: 96px; overflow: hidden;
        text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom;
    }
    .nav-links a.nav-cart { margin-left: 2px; }
}
/* The bar may never make the page wider than the window; a dropdown is
   positioned against its trigger, so this cannot clip an open menu. */
.navbar, .nav, .nav-left, .nav-links { min-width: 0; }


/* Nothing should ever scroll the page sideways: the layout is responsive and a
   horizontal bar here always means something escaped, not that there is more to
   see. `clip` rather than `hidden` so this does not turn <html> into a scroll
   container and break position: sticky inside it. */
html { overflow-x: clip; }
@supports not (overflow-x: clip) { html { overflow-x: hidden; } }


/* ── List filter bar ──────────────────────────────────────────────────────
   The search box, its button and the use-case select sat in one flex row but
   each worked out its own height from its own padding and font size, and the
   <label> wrapping the select also picked up the global label margin-bottom.
   Flex centres the margin box, not the border box, so that 8px bottom margin
   lifted the whole use-case group about 4px above the search group.

   One declared height for every control in the bar, and no margins on the
   groups, so alignment stops depending on three paddings agreeing. */
.list-filter-bar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 16px;
    margin-bottom: 14px;
    font-size: 13px;
}
.list-filter-bar > * { margin: 0; }

.lfb-group {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0;
}

.lfb-control {
    height: 32px;
    box-sizing: border-box;
    padding: 0 9px;
    font-size: 13px;
    line-height: normal;
    border: 1px solid #e2e8f0;
    border-radius: 6px;
    background: #fff;
    color: #2d3748;
}
/* .btn sets its own padding and an inline-flex display with !important, so the
   Search button needs the height restated to match the fields beside it. */
button.lfb-control { padding: 0 14px; }

.lfb-label {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .4px;
    color: #a0aec0;
    white-space: nowrap;
}


/* ── Buttons size to their content ────────────────────────────────────────
   A button in a column flex or a grid cell stretches to the cross-axis by
   default, so buttons ended up as wide as whatever sat beside them — a
   two-letter "PDF" spanning a whole card, and the same word a different width
   on two pages. Sized to content and centred in the space instead.

   Rows are left alone: `align-self` only affects the cross axis, so a button in
   a normal left-to-right toolbar keeps its place. */
.btn,
button.btn,
a.btn {
    width: fit-content;
    max-width: 100%;
    align-self: center;
    justify-self: center;
}
/* Nav controls are layout, not content: their width comes from the bar they
   divide up, and shrinking them to their labels leaves gaps in the menu. */
.nav .btn, .nav-dropdown-btn, .nav-links .btn { width: auto; align-self: auto; }
