:root {
    --bg: #0d0d0d;
    --surface: #1c1c1e;
    --surface2: #2c2c2e;
    --accent: #0a84ff;
    --accent2: #30d158;
    --danger: #ff453a;
    /* Amber on the dark surface scores 8.28:1 — excellent. It is overridden in .light-theme below,
       where the same amber scores only 1.84:1 and is unreadable in bright sun. */
    --warning: #ff9f0a;
    --text: #ffffff;
    --text2: #ffffff;
    --text3: #ffffff;
    --border: #38383a;
    --tab-h: 56px;
    --safe-bottom: env(safe-area-inset-bottom, 0px);
    color-scheme: dark;
}

html.light-theme {
    --bg: #ffffff;
    --surface: #f2f2f7;
    --surface2: #e5e5ea;
    --text: #000000;
    --text2: #000000;
    --text3: #000000;
    --border: #c6c6c8;
    /* Accent colours are DEEPER in the light theme. The dark-theme values are tuned for a near-black
       surface and are far too pale on white — checked with Core/deploy/check_contrast.py (a deploy
       gate). Ratios below are against the light card (#f2f2f7), the worst case. Staff use these apps
       outdoors in bright sun, so anything marginal is unreadable in practice.
         dark #30d158 -> 1.81:1 (fail)  |  light #0F7B3C -> 4.80:1
         dark #0a84ff -> 3.27:1 (weak)  |  light #0B63CE -> 5.10:1
         dark #ff453a -> 3.05:1 (weak)  |  light #C81E1E -> 5.14:1
         dark #ff9f0a -> 1.84:1 (fail)  |  light #C2410C -> 4.64:1
       These are also the button faces (btn-success/btn-primary/btn-danger), so this fixes the white
       button text in the light theme at the same time. */
    --accent: #0B63CE;
    --accent2: #0F7B3C;
    --danger: #C81E1E;
    --warning: #C2410C;
    color-scheme: light;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    -webkit-font-smoothing: antialiased;
    background: var(--bg);
    color: var(--text);
}

#app {
    display: flex;
    flex-direction: column;
    height: 100dvh;
}

/* Header */
#header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 16px;
    border-bottom: 1px solid var(--border);
    background: var(--bg);
}

#header h1 {
    font-size: 1.25rem;
    font-weight: 700;
    letter-spacing: -0.3px;
}

/* Content */
#content {
    flex: 1;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 16px;
}

/* Bottom Tab Nav */
#tabs {
    display: flex;
    background: var(--surface);
    border-top: 1px solid var(--border);
    height: calc(var(--tab-h) + var(--safe-bottom));
    padding-bottom: var(--safe-bottom);
}

.tab {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    text-decoration: none;
    color: var(--text3);
    font-size: 0.65rem;
    font-weight: 600;
    padding: 6px 0;
    transition: color 0.2s;
}

.tab.active { color: var(--accent); }
.tab:hover { color: var(--text2); }

/* Flash messages — bottom toast */
.flash {
    padding: 14px 16px;
    border-radius: 12px;
    font-size: 0.9rem;
    font-weight: 500;
    display: flex;
    align-items: center;
    gap: 12px;
    box-shadow: 0 4px 24px rgba(0,0,0,0.35);
    animation: flash-slidein 0.3s ease;
    transition: opacity 0.3s, transform 0.3s;
}

@keyframes flash-slidein {
    from { transform: translateY(40px); opacity: 0; }
    to   { transform: translateY(0);    opacity: 1; }
}

.flash-close {
    background: none;
    border: none;
    color: inherit;
    opacity: 0.75;
    cursor: pointer;
    font-size: 1rem;
    padding: 0;
    line-height: 1;
    flex-shrink: 0;
}
.flash-close:hover { opacity: 1; }

.flash-success { background: #248a3d; color: #ffffff; }
.flash-error   { background: #c0392b; color: #ffffff; }
.flash-warning { background: #c47a00; color: #ffffff; }

/* Cards */
.card {
    background: var(--surface);
    border-radius: 12px;
    margin-bottom: 2px;
    overflow: hidden;
}

.card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 14px;
    cursor: pointer;
}

.card-title {
    font-size: 0.95rem;
    font-weight: 600;
    flex: 1;
}

.card-meta {
    font-size: 0.85rem;
    color: var(--text2);
    margin-left: 12px;
    white-space: nowrap;
}

/* A bare row count shown as "(N)" in accent, matching the .collapse-section-count on section headers.
   It must sit immediately AFTER the label, not float to the right edge, so the row reads like
   "Costa Hospitality Group (2)" the same way the section header reads "ORGANISATIONS (3)". In a
   .card-header with a count, the title sizes to its content (not flex:1) and the count carries the
   flex slack (margin-right:auto), which pushes the chevron alone to the far right. Scoped with :has()
   so only count rows change — cards whose meta is a date/role badge/app name keep their right-aligned
   layout. */
.card-count {
    color: var(--accent);
    font-size: 0.95rem;
    margin-left: 6px;
    margin-right: auto;
}
.card-count::before { content: "("; }
.card-count::after { content: ")"; }
.card-header:has(.card-count) .card-title { flex: 0 1 auto; }

.card-chevron {
    color: var(--text3);
    margin-left: 8px;
    transition: transform 0.2s;
    font-size: 1.5rem;      /* enlarged to match .collapse-section-chevron; line-height:1 keeps row height */
    font-weight: 700;
    line-height: 1;
}

.card.expanded .card-chevron { transform: rotate(90deg); }
.card.expanded { border: 1px solid var(--border); }

.card-body {
    display: none;
    padding: 0 14px 14px;
}

.card.expanded .card-body { display: block; }

/* Nested cards (an app pane whose body holds its guide cards): always bordered so each inner row is
   visually separate, since inner and outer share the surface colour. */
.card .card { border: 1px solid var(--border); }
.card .card:last-child { margin-bottom: 0; }

/* Public theme toggle (sun/moon). Anonymous screens have no hamburger, so this is the ONLY way a guest
   can switch to light mode — and a guest in bright sunlight is exactly who needs it. */
.theme-toggle {
    background: none;
    border: none;
    padding: 4px;
    font-size: 1.25rem;
    line-height: 1;
    cursor: pointer;
}

/* Collapsible sections — the platform default for ANY grouped list (a heading with repeated rows
   under it). Collapsed on load: a long list arrives as a short stack of headings the user opens.
   Same idiom as .card/.expanded, so there is ONE collapse mechanism on the platform.
   Body is display:none when collapsed — form controls inside a collapsed section STILL SUBMIT, so a
   user may open a section, choose, collapse it, open another, and post them all in one form. */
.collapse-section { margin: 16px 0 6px; }

/* The header is a SHELF, not a button. It carries out no action; it reveals what is already there,
   so it must look pressable without borrowing the button face (saturated fill + white bold text).
   A muted surface with a leading disclosure chevron is the distinction: shape says "one object you
   can press", the absence of an accent fill says "this is not a Save".
   Before this it had no background at all, so the title, count and chevron read as three unrelated
   fragments a full screen-width apart, indistinguishable from the static headings beside them.
   Horizontal padding is 14px to match .field-row/.field-group-label EXACTLY: with #content's 16px,
   every label on the screen starts on the same 30px grid line. Do not change one without the other. */
.collapse-section-header {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 14px;
    background: var(--surface);
    border-radius: 12px;
    cursor: pointer;
    user-select: none;
    transition: background 0.15s;
}

/* A RESTRAINED lift, not --surface2. The title/chevron are --accent, and --surface2 is close enough
   to the accent in the dark theme to drop the title from 4.66:1 to 3.82:1 — still past the 3:1 gate
   for bold text, but these headings are read on a phone in bright sun, where marginal is unreadable.
   #232325 keeps 4.30:1 and is still a visible change. Measured, not eyeballed; see the note below. */
.collapse-section-header:hover { background: #232325; }

/* Touch has no hover, so the press itself has to answer back. */
.collapse-section-header:active { background: #232325; }

html.light-theme .collapse-section-header:hover,
html.light-theme .collapse-section-header:active { background: #e9e9ee; }

/* 0.95rem, not the 0.7rem this started at: these headings are the primary navigation on a phone held
   in bright sun, and at 11px they were a strain to read.
   Contrast is measured against --surface, NOT --bg: the header sits on a shelf now. --accent scores
   4.66:1 on the dark surface (#1c1c1e) and 5.10:1 on the light one (#f2f2f7, accent #0B63CE), both
   past AA for text this size. Restyling the shelf changes these numbers — re-measure if you do. */
.collapse-section-title {
    order: -2;
    /* NOT flex:1. The title takes only its own width so the count can sit right next to it as
       "MENUS (1)"; the chevron is pushed to the far right instead (see .collapse-section-chevron). */
    font-size: 0.95rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--accent);
}

/* The count belongs TO the label, so it sits beside it: "MENUS (1)", one phrase the eye reads in one
   go. Right-justified at the far edge it was a stray grey mark a whole screen-width from the word it
   counted, and at 0.7rem/60% opacity it was effectively invisible on a phone.
   Brackets come from CSS, not from 30 templates -- the markup stays `<span>{{ x | length }}</span>`
   in Core and all six apps, so there is nothing to keep in step and nothing to forget on a new screen.
   ORDER MAP for the header, and it must stay explicit: chevron -3, title -2, count -1, spacer 0,
   then anything else (bills' money, orders' sunbed/customer spans) falls to the default 0 and lands
   AFTER the spacer, i.e. pinned right where it was before. Leave a gap in the numbering at your peril:
   an unclassed span defaulting to 0 is what would otherwise wedge itself between title and count. */
.collapse-section-count {
    order: -1;
    font-size: 0.95rem;
    font-weight: 400;
    color: var(--accent);
    white-space: nowrap;
    margin-left: -2px;
}

.collapse-section-count::before { content: "("; }
.collapse-section-count::after { content: ")"; }

/* Opt-out for headers whose "count" slot is not a count. Sunbed's bills screen puts the booking DATE
   there, next to the outstanding money -- "Tomas Berg (Sat 26 Jul 2026)" would be nonsense, and both
   values have to stay right-aligned to scan down the column. Push it back to the far edge, no brackets. */
.collapse-section-count.is-meta {
    order: 2;
    margin-left: auto;
    font-size: 0.7rem;
    color: var(--text2);
    opacity: 0.6;
}

.collapse-section-count.is-meta::before,
.collapse-section-count.is-meta::after { content: none; }

/* Lowest order puts the chevron BEFORE the title without touching a single template in Core or the
   six apps. Leading the row it reads as a disclosure triangle ("this opens"); parked at the far right
   edge it read as a next-page arrow, which promises navigation this row does not do.
   Accent-coloured so it is plainly the control and not stray punctuation. */
.collapse-section-chevron {
    order: -3;
    color: var(--accent);
    font-size: 1.5rem;      /* as large as fits the header line; line-height:1 stops it growing header height */
    font-weight: 700;       /* more ink so the thin glyph reads on a phone in bright sun (TODO 45) */
    line-height: 1;
    transition: transform 0.2s;
    flex-shrink: 0;
}

/* Nothing else claims the leftover width now the title is content-sized, so a spacer after the count
   keeps the shelf full-width and holds any trailing element (bills' money column) at the far edge. */
.collapse-section-header::after {
    content: "";
    order: 0;
    flex: 1;
}

.collapse-section.expanded .collapse-section-chevron { transform: rotate(90deg); }

.collapse-section-body { display: none; }

.collapse-section.expanded .collapse-section-body { display: block; }

/* Buttons */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 12px;
    padding: 8px 14px;
    font-size: 1rem;
    font-weight: 600;
    cursor: pointer;
    transition: opacity 0.2s;
    text-decoration: none;
    /* White text REQUIRES a solid background: a variant-less .btn used to have none, so it rendered
       white-on-white and vanished in the light theme. This default keeps every button legible in
       BOTH themes even when a screen forgets its variant. */
    background: #48484a;
    color: #ffffff;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    text-align: center;
}

.btn:hover { opacity: 0.85; }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }

.btn-primary { background: var(--accent); width: 100%; }
.btn-success { background: var(--accent2); width: 100%; }
.btn-danger { background: var(--danger); }
.btn-warning { background: var(--warning); color: #1c1c1e; width: 100%; }
html.light-theme .btn-warning { color: #ffffff; }
.btn-surface { background: #48484a; }
.btn-back { background: #6E4AC7; white-space: nowrap; margin-bottom: 16px; }

.btn-sm {
    border-radius: 8px;
    padding: 7px 14px;
    font-size: 0.8rem;
    font-weight: 600;
}

/* ── My Apps launcher: the app rows INSIDE an expanded business card ───────────
   The ONLY bespoke rule this screen needs — `.card` has no row idiom for its own body. The business is
   the card title; its apps are plain rows within. Until 16 Jul 2026 this ran the other way round: bold
   app names under a lighter business name, with a rule drawn between every row, so the visual weight
   fought the hierarchy and the screen read as a wall of shouting. No dividers between rows — they are one
   short group inside their card, and a rule between each fights the grouping the card already gives.

   The whole row is the link (it is an <a>), so there is no LAUNCH button: the app name is what the user
   scans for, the chevron says the row is tappable, and a full-width tap target beats a 90px button on a
   phone. `.btn-launch` is gone with it — nothing else on the platform used it. */
.launch-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 0;
    text-decoration: none;
    color: inherit;
}
.launch-row .launch-app { font-size: 0.95rem; font-weight: 400; }
.launch-role { display: block; font-size: 0.7rem; font-weight: 400; color: var(--text3); margin-top: 2px; }

/* The business rows themselves are plain `.card`s — the same idiom as Organisations, Businesses and
   Users. `.card` already gives the 2px stack, the expand/collapse, the chevron rotation and the
   border-when-open, so there is nothing to add here and nothing to override. An earlier version of this
   screen used `.collapse-section` and then needed a pile of bespoke margins to undo its heading spacing;
   that CSS is gone. If a screen needs custom spacing to look right, the component is probably wrong. */

.btn-row {
    display: flex;
    gap: 10px;
    margin-top: 12px;
}
/* Direct children, and buttons inside an action <form style="display:contents"> wrapper (the standard
   pattern), are sized the same — the child combinator alone misses form-wrapped buttons. */
.btn-row > *,
.btn-row > form > * { flex: 1; }
.btn-row > .btn-back,
.btn-row > form > .btn-back { flex: 0 0 auto; min-width: 80px; margin-bottom: 0; }

/* A long toolbar (back + print + several filters) squashes to unreadable on a phone in one line, so it
   wraps and its buttons take their natural width instead of an equal share. */
.btn-row.wrap { flex-wrap: wrap; }
.btn-row.wrap > *,
.btn-row.wrap > form > * { flex: 0 1 auto; }

/* Buttons stacked vertically, each full width. */
.btn-row.stack { flex-direction: column; }
.btn-row.stack > *,
.btn-row.stack > form > * { flex: 0 0 auto; width: 100%; }

/* The TOP action bar (Back + Save/etc.) stays visible while a long form scrolls beneath it, so the
   green Save button is never lost off-screen. Applied by app.js to the FIRST .btn-row inside #content
   only -- mid-form and footer button rows are never made sticky. It pins to the top of the scroll
   container (#content). #content has 16px padding all round, so the bar's opaque background is extended
   OUTWARD on all four exposed sides (negative margin) with matching padding to keep the buttons in
   place: this covers the 16px strip ABOVE the bar (where content would otherwise peek through between
   the header and the bar) and the strips left/right, giving a clean full-width band. */
.btn-row.is-sticky-top {
    position: sticky;
    /* #content is the scroll container and has 16px padding, so `sticky` pins at its PADDING edge --
       `top: 0` would leave a 16px strip above the bar where content scrolls through. `top: -16px` pins
       flush to the content's top border edge (against the fixed header). The matching -16px top margin
       + 16px top padding keep the buttons in their normal place while the opaque background fills that
       strip; -16px side margins + 16px side padding make the band full-width. Verified live 21 Jul. */
    top: -16px;
    z-index: 20;
    background: var(--bg);
    margin: -16px -16px 16px;
    padding: 16px 16px 12px;
}

/* Forms */
.field-group {
    background: var(--surface);
    border-radius: 14px;
    margin-bottom: 16px;
    overflow: hidden;
}

.field-group-label {
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--text);
    letter-spacing: 0.8px;
    padding: 16px 14px 8px;
}

/* Collapsible form panes */
.collapsible-pane {
    margin-bottom: 16px;
}
.collapsible-pane > summary {
    background: var(--surface);
    border-radius: 14px;
    padding: 10px 14px;
    cursor: pointer;
    list-style: none;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--text);
    letter-spacing: 0.8px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    user-select: none;
}
.collapsible-pane > summary::-webkit-details-marker { display: none; }
.collapsible-pane > summary::after {
    content: '›';
    font-size: 1.1rem;
    color: var(--text3);
    display: inline-block;
    transform: rotate(90deg);
    transition: transform 0.2s;
}
details[open].collapsible-pane > summary {
    border-radius: 14px 14px 0 0;
}
details[open].collapsible-pane > summary::after {
    transform: rotate(270deg);
}
.collapsible-pane > .field-group {
    border-radius: 0 0 14px 14px;
    margin-bottom: 0;
}

/* "+ Add …" expander — a full-width button (a styled <summary>) that reveals its form when opened.
   Reusable for EVERY "Add" control (services, seasons, and any future add forms). Give the summary
   the .btn .btn-primary classes; the form sits in a .field-group below. */
.add-expander { margin-bottom: 16px; }
.add-expander > summary { list-style: none; }
.add-expander > summary::-webkit-details-marker { display: none; }
.add-expander > summary::after { content: none; }
.add-expander > .field-group { margin-top: 8px; }

.field-row {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    padding: 10px 14px;
    border-bottom: 1px solid var(--border);
}

.field-row:last-child { border-bottom: none; }

.field-row label {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--text);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.field-row input,
.field-row select,
.field-row textarea {
    flex: 1;
    background: transparent;
    border: none;
    color: var(--text);
    font-size: 0.95rem;
    font-family: inherit;
    outline: none;
    padding: 4px 0;
}

.field-row input::placeholder,
.field-row textarea::placeholder {
    color: var(--text3);
    font-style: italic;
}

/* Helper prompt text under a field — italic so it reads as guidance, not input. */
.field-hint {
    font-style: italic;
}

/* A <select> still showing its empty prompt option ("Choose…") reads as guidance — italic + muted,
   matching input placeholders. Reverts to normal once a real option is chosen. */
select:has(option[value=""]:checked) {
    font-style: italic;
    color: var(--text2);
}

.field-row select {
    appearance: auto;
    -webkit-appearance: menulist;
}

.field-row select option {
    background: var(--surface);
    color: var(--text);
}

.field-row select optgroup {
    background: var(--surface);
    color: var(--text);
    font-weight: 600;
}

.field-row textarea {
    min-height: 96px;
    resize: vertical;
}

.field-row input[type="date"],
.field-row input[type="time"] { width: auto; flex: 0; }

/* Make the native date/time picker icon visible on the dark theme (dark glyph → invert to light). */
.field-row input[type="date"]::-webkit-calendar-picker-indicator,
.field-row input[type="time"]::-webkit-calendar-picker-indicator {
    filter: invert(1);
    opacity: 0.65;
    cursor: pointer;
}
html.light-theme .field-row input[type="date"]::-webkit-calendar-picker-indicator,
html.light-theme .field-row input[type="time"]::-webkit-calendar-picker-indicator {
    filter: none;
    opacity: 0.55;
}

.field-row input[type="checkbox"] { flex: 0; width: 18px; height: 18px; accent-color: var(--accent); cursor: pointer; }
.field-row .badge { align-self: flex-start; }

/* Checkbox rows */
.check-row {
    display: flex;
    align-items: center;
    padding: 10px 14px;
    border-bottom: 1px solid var(--border);
    gap: 12px;
}

.check-row:last-child { border-bottom: none; }

.check-row input[type="checkbox"] {
    width: 18px;
    height: 18px;
    accent-color: var(--accent);
    cursor: pointer;
    flex-shrink: 0;
}

.check-row label {
    font-size: 0.9rem;
    cursor: pointer;
    flex: 1;
}

.check-row .check-meta {
    font-size: 0.75rem;
    color: var(--text3);
}

/* Status badges */
.badge {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 20px;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
}

.badge-active { background: var(--accent2); color: #ffffff; }
.badge-inactive { background: var(--danger); color: #ffffff; }
.badge-role { background: var(--accent); color: #ffffff; }
/* Amber pill needs theme-aware TEXT: white-on-amber fails contrast on the dark surface (the known
   --warning issue), so dark text on the bright dark-mode amber, white text on the darker light-mode
   burnt-orange. */
.badge-warning { background: var(--warning); color: #1c1c1e; }
html.light-theme .badge-warning { color: #ffffff; }
/* Space consecutive chips so a row of them never runs together. */
.badge + .badge { margin-left: 6px; }

/* Stat cards */
.stat-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
    margin-bottom: 16px;
}

.stat-card {
    background: var(--surface);
    border-radius: 12px;
    padding: 16px;
    text-align: center;
}

/* A stat card MAY be a link (users press them anyway — a number is only useful if you can reach the
   thing it counts). As an <a> it must look identical to the inert version, so the two can sit in the
   same grid, with a press state so the tap is acknowledged. */
a.stat-card {
    display: block;
    color: inherit;
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
    transition: transform 0.08s ease, background 0.15s ease;
}
a.stat-card:active { transform: scale(0.97); background: var(--surface2, #2c2c2e); }

.stat-value {
    font-size: 1.8rem;
    font-weight: 700;
    color: var(--warning);
}

.stat-label {
    font-size: 0.7rem;
    color: var(--text3);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-top: 4px;
}

/* Section header */
.section-title {
    font-size: 1rem;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--text);
    letter-spacing: 0.8px;
    margin: 20px 0 10px;
    padding-left: 14px;
}

/* Login page */
.login-container {
    max-width: 360px;
    margin: 60px auto;
}

.login-title {
    font-size: 1.5rem;
    font-weight: 700;
    text-align: center;
    margin-bottom: 24px;
}

/* Login form fields — stacked label-above-input layout */
.login-fields {
    background: var(--surface);
    border-radius: 14px;
    overflow: hidden;
    margin-bottom: 16px;
}

.login-field {
    padding: 10px 14px;
    border-bottom: 1px solid var(--border);
}

.login-field:last-child { border-bottom: none; }

.login-field label {
    display: block;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 4px;
}

.login-field input {
    display: block;
    width: 100%;
    background: transparent;
    border: none;
    outline: none;
    color: var(--text);
    font-size: 1rem;
    padding: 2px 0;
}

/* App toggle cards */
.app-card {
    background: var(--surface);
    border-radius: 12px;
    padding: 16px;
    margin-bottom: 8px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.app-card-info { flex: 1; }
.app-card-name { font-size: 0.95rem; font-weight: 600; }
.app-card-desc { font-size: 0.8rem; color: var(--text3); margin-top: 2px; }

/* Tab bar — retired, never shown */
#tabs { display: none; }

/* Theme toggle icon button */
#themeToggleBtn {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 1.25rem;
    line-height: 1;
    padding: 2px;
    user-select: none;
}

/* Hamburger — always visible */
#app { position: relative; }

.nav-hamburger {
    display: flex;
    flex-direction: column;
    gap: 5px;
    background: none;
    border: none;
    cursor: pointer;
    padding: 4px;
}

.nav-hamburger span {
    display: block;
    width: 24px;
    height: 2px;
    background: var(--text);
    border-radius: 2px;
}

/* Password show/hide toggle */
.password-field { position: relative; }
.password-field input { padding-right: 44px; }
.password-toggle {
    position: absolute;
    right: 12px;
    top: 50%;
    transform: translateY(-50%);
    background: none;
    border: none;
    cursor: pointer;
    color: var(--text3);
    padding: 0;
    display: flex;
    align-items: center;
}

.nav-links {
    display: none;
    flex-direction: column;
    position: absolute;
    top: 56px;
    right: 0;
    width: max-content;
    min-width: 160px;
    background: var(--surface);
    padding: 0.25rem 0 0.75rem;
    z-index: 1000;
    gap: 0;
    box-shadow: 0 4px 12px rgba(0,0,0,0.5);
    list-style: none;
    border-radius: 0 0 0 10px;
}

.nav-links.open { display: flex; }

.nav-links li {
    border-top: 1px solid var(--border);
}

.nav-links a {
    display: block;
    padding: 0.75rem 1.75rem;
    font-size: 0.9rem;
    color: var(--text);
    text-decoration: none;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    font-weight: 600;
    white-space: nowrap;
}

.nav-links a:hover { color: var(--accent); }

/* Admin table */
.admin-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.85rem;
}

.admin-table th {
    text-align: left;
    padding: 10px 8px;
    color: var(--text);
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    border-bottom: 1px solid var(--border);
}

.admin-table td {
    padding: 10px 8px;
    border-bottom: 1px solid var(--border);
    color: var(--text2);
}

.admin-table tr:last-child td { border-bottom: none; }

/* Spinner */
.spinner {
    width: 16px;
    height: 16px;
    border: 2px solid rgba(255,255,255,.3);
    border-top-color: #fff;
    border-radius: 50%;
    animation: spin .6s linear infinite;
    display: inline-block;
}

@keyframes spin { to { transform: rotate(360deg); } }

@media (max-width: 768px) {
    #content {
        height: auto;
        padding-bottom: 16px;
    }
}

/* Guide screenshots (inserted via the guide editor's Insert image button). */
.help-img {
    display: block;
    max-width: 100%;
    height: auto;
    margin: 12px 0;
    border: 1px solid var(--border);
    border-radius: 10px;
}

/* Guide/help body lists — indent so the bullet or number sits in line with the body text instead of
   hanging out into the left margin. Covers the in-app Help page (.help) and the guide-editor preview
   pane (.help-body). Scoped by class, so it beats any bare ul/ol reset by specificity. */
.help ul, .help ol,
.help-body ul, .help-body ol {
    padding-left: 1.5em;
    margin: 8px 0;
}
.help li, .help-body li { margin: 2px 0; }
