@font-face { font-family: 'DM Sans'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/dm-sans-latin-400-normal.woff2') format('woff2'); }
@font-face { font-family: 'DM Sans'; font-style: normal; font-weight: 500; font-display: swap; src: url('/fonts/dm-sans-latin-500-normal.woff2') format('woff2'); }
@font-face { font-family: 'DM Sans'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/dm-sans-latin-700-normal.woff2') format('woff2'); }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/poppins-latin-400-normal.woff2') format('woff2'); }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/poppins-latin-700-normal.woff2') format('woff2'); }

/* Suppress the WebView's own pull-to-refresh on native — avoids an OS-level
   refresh gesture interfering with position:sticky on Android browser. */
html.native-app, html.native-app body { overscroll-behavior-y: contain; }
body { background-color: #fbf7f0; }

/* Event card sent to you / to a group you're in (ui.js eventCardTone), and
   its "sent to you" / "sent to group" pill on the Social feed. Warm gold, so
   it's distinct from interested's sky and sits on the warm dark theme
   (dark overrides with the other html.dark remaps below). */
.ev-tone-sent-you { border-color: #e0a93b; background-color: #fcefd2; }
.ev-tone-sent-group { border-color: #efd5a2; background-color: #fcf6ea; }
.ev-sent-label { color: #9a5b06; background-color: #fae3b0; }

/* Add/Edit event dialog: brief shake to signal a blocked backdrop-click close
   when the form has unsaved changes. */
@keyframes le-dialog-shake {
    10%, 90% { transform: translateX(-2px); }
    20%, 80% { transform: translateX(4px); }
    30%, 50%, 70% { transform: translateX(-6px); }
    40%, 60% { transform: translateX(6px); }
}
.le-dialog-shake { animation: le-dialog-shake 0.4s; }

@keyframes user-menu-refresh-spin {
    to { transform: rotate(360deg); }
}

body {
    font-family: 'Poppins', sans-serif;
    background-color: #fbf7f0; /* Sepia background */
    color: #4f463c; /* Darker sepia text */
}
h1, h2, h3, h4, h5 {
     color: #3e352e; /* Even darker for headers */
}
.details-transition {
    transition: max-height 0.05s ease-out, padding 0.05s ease-out, border 0.05s ease-out;
}
.group-venues-container {
    transition: max-height 0.12s ease-in-out;
}
.group-chevron-icon {
    transition: transform 0.12s ease-in-out;
}
.panel-transition {
    transition: transform 0.1s ease-out;
}
.overlay-transition {
    transition: opacity 0.1s ease-out;
}
.icon {
    width: 14px;
    height: 14px;
    stroke-width: 2.5px;
}

/* Narrow layout: Tickets / Share / Tag collapse to icon-only buttons (min
   44x44 touch target), and Add-to-cal + Edit move out of the row into the
   overflow (kebab) menu — leaving the row short enough to fit on one line.
   Wide view (default, no .is-narrow) is untouched.
   .is-narrow is added/removed by ui.js (updateActionsRowLayout), which
   measures whether the wide layout actually fits, rather than switching at
   a fixed viewport-width breakpoint — a fixed breakpoint left a gap where
   Edit disappeared into the (not-yet-relevant) overflow menu before the
   wide buttons had actually run out of room. Deliberately no overflow-x
   scroll fallback: the share/tag/overflow dropdowns are
   absolutely-positioned descendants of this row, and an overflow:auto here
   would clip them. */
.event-actions .narrow-only-action { display: none; }
.event-actions.is-narrow {
    gap: 0.375rem;
    flex-wrap: nowrap !important;
}
.event-actions.is-narrow .action-label,
.event-actions.is-narrow .action-chevron {
    display: none;
}
.event-actions.is-narrow .event-icon-btn {
    min-width: 44px;
    min-height: 44px;
    padding: 0;
    justify-content: center;
}
/* Descendant selector (not a direct-child one) so this also reaches the
   icons inside the share/overflow dropdown menu items, not just the row's
   own icon-only buttons — keeps them visually matched. */
.event-actions.is-narrow .icon {
    width: 18px;
    height: 18px;
}
.event-actions.is-narrow .wide-only-action { display: none; }
.event-actions.is-narrow .narrow-only-action { display: flex; }

.chevron-icon svg,
.group-chevron-icon svg {
    width: 20px;
    height: 20px;
    min-width: 20px;
    min-height: 20px;
    flex-shrink: 0;
}

/* Hide entire header initially - shown all together when ready */
/* Show title and tagline images immediately, hide everything else until ready */
html:not([data-header-ready]) #logo-img,
html:not([data-header-ready]) #tagline-img {
    display: block;
}

html:not([data-header-ready]) #search-container {
    display: none;
}

/* When header is ready, show everything */
html[data-header-ready] #sticky-header {
    display: block;
}

html[data-header-ready] #search-container {
    display: flex;
}


#sticky-header {
    position: sticky;
    top: 0;
    z-index: 30;
    background-color: #fbf7f0;
    padding-top: var(--safe-area-inset-top, env(safe-area-inset-top, 0px));
    padding-bottom: 0.5rem;
    box-shadow: 0 2px 10px rgba(0,0,0,0.05);
}

#main-header {
    max-height: 200px;
    overflow: hidden;
    transition: max-height 0.25s ease, opacity 0.2s ease, padding 0.25s ease;
}

/* Tagline: shrink then collapse when scrolled; wrapper animates max-height */
.tagline-wrapper {
    max-height: 1.5rem;
    opacity: 1;
}
#tagline-img {
    filter: grayscale(1) opacity(0.55);
}

/* Filter chips: 3 groups with gap-2 within group, gap-4 between groups.
   Not meant to scroll — html.chip-overflow (see app.js updateToolbarOverflow)
   switches to the mobile bottom bar before the row would ever need to; this
   overflow-x stays only as a defensive fallback, with no visual scroll hint. */
.chips-scroll-row {
    -webkit-overflow-scrolling: touch;
    touch-action: pan-x;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
}
.chips-scroll-row::-webkit-scrollbar {
    display: none;
}
.chips-groups-row {
    width: 100%;
    min-width: max-content;
}
/* Wide-view button bar (filter chips, sort/alerts, My Gigs action bar) —
   black to match the narrow-view mobile bottom bar's .mob-icon-btn color. */
.chip-btn-mono {
    border-color: #000;
    color: #000;
}
html.dark .chip-btn-mono {
    border-color: #fff;
    color: #fff;
}
/* Custom scrollbar for settings panel */
#settings-panel-body::-webkit-scrollbar {
    width: 6px;
}
#settings-panel-body::-webkit-scrollbar-track {
    background: #f1e9db;
}
#settings-panel-body::-webkit-scrollbar-thumb {
    background: #c7bca1;
    border-radius: 3px;
}
#settings-panel-body::-webkit-scrollbar-thumb:hover {
    background: #b4a78c;
}

/* Highlighting and Pulsing Animation */
@keyframes highlight-pulse {
    0% { background-color: #ffd6de; border-color: #e6005c; box-shadow: 0 0 0 8px #ff336688, 0 0 16px 4px #e6005c44; }
    20% { background-color: #fff; border-color: #e6005c; box-shadow: 0 0 0 16px #fff17688, 0 0 32px 8px #e6005c88; }
    50% { background-color: #ff3366; border-color: #e6005c; box-shadow: 0 0 0 24px #ff3366cc, 0 0 48px 12px #e6005c; }
    80% { background-color: #fff; border-color: #e6005c; box-shadow: 0 0 0 16px #fff17688, 0 0 32px 8px #e6005c88; }
    100% { background-color: #ffd6de; border-color: #e6005c; box-shadow: 0 0 0 8px #ff336688, 0 0 16px 4px #e6005c44; }
}
.highlight {
    border: 1.5px solid #e6005c !important;
    background-color: #ffd6de !important;
    box-shadow: none !important;
    z-index: 20;
    animation: none !important;
}
[data-event-id] {
    position: relative;
    z-index: 1;
}
.bg-white\/50.rounded-lg.shadow-sm.border.border-stone-200\/80.overflow-hidden {
    border: none !important;
}


/* Settings Panel Tabs */
/* Settings panel accent — change this one value to re-theme */
#settings-panel { --fnn-accent: #D4537E; padding: 0; overflow: hidden; }

.tab-btn {
    font-family: inherit;
    border: none;
    border-radius: 0;
    background-color: transparent;
    color: #999;
    padding: 0.5rem 0.25rem;
    /* Count titles ("197 Venues") must stay on one line in the narrow panel */
    white-space: nowrap;
    cursor: pointer;
    position: relative;
    transition: color 0.15s;
}

.tab-btn.active {
    background-color: transparent !important;
    color: var(--fnn-accent) !important;
    font-weight: 600;
    z-index: 2;
}

.tab-btn:not(:last-child) {
    border-right: none;
}

/* Tab container bottom border */
#settings-panel .flex.border-b.border-stone-300 {
    border-bottom: 1px solid #e5e7eb !important;
}

/* Active tab: 2px accent underline, covers the container border */
.tab-btn.active::after {
    content: '';
    position: absolute;
    bottom: -1px;
    left: 0;
    right: 0;
    height: 2px;
    background-color: var(--fnn-accent);
    z-index: 3;
}

#settings-panel-body .tab-content {
    display: none !important;
}

#settings-panel-body {
    padding-bottom: var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px));
}

#settings-panel-body .tab-content.active {
    display: block !important;
}

/* Prevent text selection and cursor in settings panel */
#settings-panel,
#settings-panel * {
    user-select: none !important;
    -webkit-user-select: none !important;
    -moz-user-select: none !important;
    -ms-user-select: none !important;
    caret-color: transparent !important;
}

/* Custom clear ("x") button replaces the native search cancel button so it
   stays visible when the input loses focus (native cancel buttons only show
   while focused in Chrome/Safari). */
#search-input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }

/* Allow text selection only for input fields if needed */
#settings-panel input[type="text"],
#settings-panel input[type="search"],
#settings-panel textarea {
    user-select: text !important;
    -webkit-user-select: text !important;
    caret-color: auto !important;
}

/* Prevent cursor on all text elements in settings */
#settings-panel label,
#settings-panel span,
#settings-panel div,
#settings-panel p,
#settings-panel button {
    caret-color: transparent !important;
}

#settings-panel label:focus,
#settings-panel span:focus,
#settings-panel div:focus {
    outline: none !important;
    caret-color: transparent !important;
}

/* Prevent blinking cursors in selection tree */
#display-venue-filter-container {
    user-select: none;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
}

#display-venue-filter-container * {
    user-select: none !important;
    -webkit-user-select: none !important;
    -moz-user-select: none !important;
    -ms-user-select: none !important;
    caret-color: transparent !important;
    outline: none !important;
}

/* Prevent focus from showing cursor */
#display-venue-filter-container *:focus {
    outline: none !important;
    caret-color: transparent !important;
}

/* Allow text selection only for labels (but no cursor) */
#display-venue-filter-container label {
    cursor: pointer;
    caret-color: transparent !important;
    user-select: none !important;
    -webkit-user-select: none !important;
}

#display-venue-filter-container input[type="checkbox"] {
    cursor: pointer;
    caret-color: transparent !important;
    outline: none !important;
    -webkit-tap-highlight-color: transparent;
}

/* Prevent text selection on labels */
#display-venue-filter-container label,
#display-venue-filter-container label span {
    user-select: none !important;
    -webkit-user-select: none !important;
    -moz-user-select: none !important;
    -ms-user-select: none !important;
    pointer-events: auto;
}

/* Completely prevent focus on checkboxes */
#display-venue-filter-container input[type="checkbox"]:focus {
    outline: none !important;
    caret-color: transparent !important;
    box-shadow: none !important;
}

/* Prevent cursor on label when clicking checkbox */
#display-venue-filter-container label:active,
#display-venue-filter-container label:focus {
    caret-color: transparent !important;
    outline: none !important;
}

/* Prevent text selection and cursor on all interactive elements */
#display-venue-filter-container .node-header-toggle,
#display-venue-filter-container .node-toggle-btn {
    caret-color: transparent !important;
    user-select: none !important;
    -webkit-user-select: none !important;
}

/* Prevent text cursor in spans and all text elements */
#display-venue-filter-container span,
#display-venue-filter-container div,
#display-venue-filter-container button {
    caret-color: transparent !important;
}

/* Specifically target any focusable elements */
#display-venue-filter-container [tabindex] {
    caret-color: transparent !important;
    outline: none !important;
}

/* --- Prevent text selection & caret in the settings tree --- */

/* Apply to the specific containers */
#display-venue-filter-container {
  -webkit-user-select: none !important;
  -moz-user-select: none !important;
  -ms-user-select: none !important;
  user-select: none !important;
}

/* Disable selection and caret on labels/spans/divs inside those containers */
#display-venue-filter-container label,
#display-venue-filter-container label * {
  -webkit-user-select: none !important;
  -moz-user-select: none !important;
  -ms-user-select: none !important;
  user-select: none !important;
  caret-color: transparent !important;     /* hide caret */
  outline: none !important;                /* avoid focus ring if undesired */
}

/* Allow inputs to behave normally (focusable / clickable) */
#display-venue-filter-container input[type="checkbox"] {
  user-select: auto !important;
  -webkit-user-select: auto !important;
  caret-color: auto !important;
  outline: none; /* style focus separately if you want an accessible focus */
}

/* Optional: remove ::selection highlight if any */
#display-venue-filter-container ::selection {
  background: transparent;
  color: inherit;
}


@media (min-width: 400px) {
    #sticky-header > header {
        padding-right: 0 !important;
    }
}

/* For screens < 400px: center to width between settings button and left edge, with smaller gap */
@media (max-width: 400px) {
    /* 1. Reset Header Padding */
    /* We remove the right-padding from the header so it doesn't squeeze the tagline. */
    #sticky-header > header {
        padding-right: 0 !important;
        padding-left: 0 !important;
        width: 100%;
    }

    /* 2. Shrink Tagline to Fit — scale it down proportionally instead of
       stretching edge-to-edge, which clipped the text on narrow screens
       (the wrapper has no definite width for that % to resolve against). */
    .tagline-wrapper {
        width: 100% !important;
        display: flex !important;
        justify-content: center !important;
    }
    #tagline-img {
        width: auto !important;
        height: auto !important;
        max-width: 100% !important;
        margin-left: 0 !important;
        margin-right: 0 !important;
        display: block;
    }

    /* 3. Protect the Logo */
    /* Since we removed the header padding, we add margin to the logo specifically 
       so it doesn't overlap with the Settings button in the top right. */
    #logo-img {
        margin-right: 6rem !important; /* Leaves space for the help + account buttons */
        max-width: calc(100% - 6rem); object-fit: contain; /* Shrinks rather than running under the buttons on small screens */
    }
}

/* Remove blue highlight/ring from select elements */
.no-focus-ring:focus {
    outline: none !important;
    box-shadow: none !important;
    border-color: #d1d5db !important;
}

/* Collapsible Sections */
.collapsible-section {
    border-bottom: 1px solid #e5e7eb;
}

.collapsible-header {
    padding: 0.5rem 0;
    cursor: pointer;
    background: none;
    border: none;
    transition: opacity 0.2s;
}

.collapsible-header:hover {
    opacity: 0.8;
}

.collapsible-title {
    flex: 1;
}

.collapsible-indicator {
    font-size: 1rem;
    transition: transform 0.2s ease-in-out;
    display: inline-block;
    margin-left: 0.5rem;
}

.collapsible-header.expanded .collapsible-indicator {
    transform: rotate(90deg);
}

.collapsible-content {
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.3s ease-in-out;
}

.collapsible-content:not(.collapsed) {
    max-height: 2000px; /* Large enough to accommodate content */
}

.collapsible-content.collapsed {
    max-height: 0;
}

/* Segmented Control */
.segmented-control {
    display: flex;
    border: 1px solid #3e352e;
    border-radius: 9999px;
    overflow: hidden;
    background-color: white;
    white-space: nowrap;
}

.segmented-control-fixed {
    width: 140px;
    flex-shrink: 0;
}

.segmented-control-fixed .segmented-btn {
    padding: 0.35rem 0.5rem;
    min-height: 2.5rem;
}

.segmented-btn {
    flex: 1;
    padding: 0.25rem 0.75rem;
    border: none;
    background-color: white;
    color: #3e352e;
    font-size: 0.875rem;
    cursor: pointer;
    transition: background-color 0.2s ease;
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0;
    white-space: normal;
    line-height: 1.2;
}

.segmented-btn span {
    display: block;
    line-height: 1.2;
}

.segmented-btn:not(:last-child) {
    border-right: 1px solid #3e352e;
}

.segmented-btn.active {
    background-color: #ffd6e0;
    color: #3e352e;
}

.segmented-btn.active::after {
    content: '✓';
    font-size: 0.875rem;
    font-weight: bold;
    position: absolute;
    right: 0.5rem;
    top: 50%;
    transform: translateY(-50%);
}

.segmented-btn:hover:not(.active) {
    background-color: #f5f5f4;
}

.segmented-btn:focus {
    outline: none;
}


/* Search order popup */
.search-order-option {
    color: #3e352e;
}

.search-order-option:hover {
    background-color: #f5f5f4;
}

.search-order-option.active {
    background-color: rgba(255, 107, 53, 0.2);
    color: #ff6b35;
    font-weight: 500;
}

.search-order-option:hover {
    background-color: rgba(255, 107, 53, 0.1);
}

/* Search order button active state */
#search-order-btn.active {
    background-color: rgba(255, 107, 53, 0.2);
    border-color: #ff6b35;
}

#search-order-btn.active svg {
    color: #ff6b35;
}

#new-venues-toggle-btn.active {
    background-color: #ffd6e0;
    border-color: #3e352e;
}

/* "Narrowed from the default" on the wide bar chips — the same pink dot as
   the Social tab's narrow Filter button (.mob-badge-dot), pinned to the
   chip's top-right corner. Replaces a faint pink tint that all but vanished
   in dark mode. */
#chip-hot-toggle, #chip-filters, #bar-social-kind-btn, #bar-social-filter-btn { position: relative; }
#chip-hot-toggle.active::after, #chip-filters.active::after,
#bar-social-kind-btn.active::after, #bar-social-filter-btn.active::after {
    content: '';
    position: absolute;
    top: 3px;
    right: 3px;
    width: 0.6rem;
    height: 0.6rem;
    border-radius: 50%;
    background: #c83dac;
    pointer-events: none;
}

/* Genre and promoter pills */
.pill {
    display: inline-flex;
    align-items: center;
    font-size: 0.7rem;
    font-weight: 600;
    padding: 0.15rem 0.45rem;
    border-radius: 999px;
    white-space: nowrap;
    line-height: 1.4;
}
.pill-genre {
    background: #fef3c7;
    color: #92400e;
    border: 1px solid #fcd34d;
}
.pill-promoter {
    background: #e0f2fe;
    color: #0369a1;
    border: 1px solid #7dd3fc;
}

/* Attendance buttons */
.attendance-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.875rem;
    font-weight: 500;
    padding: 0.375rem 0.75rem;
    border-radius: 0.375rem;
    border: 1px solid #d6d3d1;
    background: #fff;
    color: #57534e;
    cursor: pointer;
    transition: background 0.1s, border-color 0.1s, color 0.1s;
}
.attendance-btn:hover {
    background: #f5f5f4;
}
.attendance-btn-active {
    background: #fdf2f8;
    border-color: #c83dac;
    color: #c83dac;
}


/* Date suffix on venue line: only visible when the event card is expanded */
.event-date-suffix {
    display: none;
}
[data-event-id].bg-white .event-date-suffix {
    display: inline;
}
.date-suffix-rest {
    display: none;
}
.date-suffix-rest.date-suffix-rest-shown {
    display: inline;
}
.date-suffix-toggle {
    background: none;
    border: none;
    padding: 0;
    margin-left: 0.25em;
    color: #c83dac;
    font-weight: 600;
    font-size: inherit;
    cursor: pointer;
    text-decoration: underline;
}

/* Status indication icons in collapsed header */
.status-icon {
    width: 13px;
    height: 13px;
    flex-shrink: 0;
    color: #c83dac;
}

/* GOING / INTERESTED / RECOMMENDED labels on event cards (ui.js
   createEventHTML) — same shape as NEW / PAST but bordered, in the card
   tint's colour, so your own tags are the first thing you spot. */
.ev-status-label {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    border: 1px solid;
    line-height: 1.15;
}
.ev-status-label.hidden { display: none; }
.ev-status-going { color: #047857; background-color: #ecfdf5; border-color: #34d399; }
.ev-status-interested { color: #0369a1; background-color: #f0f9ff; border-color: #38bdf8; }
.ev-status-recommended { color: #be185d; background-color: #fdf2f8; border-color: #f472b6; }

/* The open card — Event Feed and Social feed alike (ui.js toggleEvent adds
   is-expanded) — gets the pink rule down its left edge, so the one you're
   looking at stands out from the closed ones around it. (This used to mark
   new events instead; NEW is a label now, nothing more.) */
[data-event-id].is-expanded {
    border-left: 3px solid #e83d85 !important;
}

/* Past events — de-emphasised */
.event-past {
    opacity: 0.55;
}
.event-past:hover,
.event-past:focus-within {
    opacity: 0.85;
}

/* Flash highlight after adding an event */
@keyframes just-added-flash {
    0%   { box-shadow: 0 0 0 3px #c83dac; }
    100% { box-shadow: 0 0 0 0px transparent; }
}
.event-just-added {
    animation: just-added-flash 1.8s ease-out forwards;
    border-radius: 0.5rem;
}

/* New venues message toast */
#new-venues-message {
    transition: opacity 0.2s ease-in-out, transform 0.2s ease-in-out;
    pointer-events: none;
}

/* Hot filter message toast */
#hot-filter-message {
    transition: opacity 0.2s ease-in-out, transform 0.2s ease-in-out;
    pointer-events: none;
}

/* ── Share image attention treatment ─────────────────────────── */

.share-dimmed {
    opacity: 0.32;
    filter: saturate(0.65);
    transition: opacity 0.3s ease, filter 0.3s ease;
    pointer-events: none;
}

.share-glow {
    border-radius: 14px;
    background: #ffffff;
    border: 1px solid rgba(192,112,184,0.2);
    box-shadow: 0 4px 20px rgba(0,0,0,0.1);
    overflow: hidden;
}
.share-inner {
    background: #ffffff;
    border-radius: 0;
    padding: 13px 15px 15px;
}

.share-head {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: -13px -15px 12px;
    padding: 10px 15px;
    background: #c070b8;
}
.share-label {
    flex: 1;
    font-size: 13px;
    font-weight: 700;
    color: #fff;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}
.share-close {
    width: 26px; height: 26px;
    flex-shrink: 0;
    border-radius: 50%;
    border: 1px solid rgba(255,255,255,0.4);
    background: transparent;
    color: #fff;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    transition: background 0.12s;
}
.share-close:hover {
    background: rgba(255,255,255,0.2);
}

/* Collapsible section headers in the share image dialog */
.share-section-summary {
    display: flex;
    align-items: center;
    gap: 6px;
    background: #fdeef9;
    color: #555;
    padding: 9px 12px;
    border-radius: 5px;
    margin-top: 6px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    cursor: pointer;
    user-select: none;
    list-style: none;
    border: 1px solid rgba(200,61,172,0.25);
    transition: background 0.12s, color 0.12s;
    font-family: inherit;
}
.share-section-summary:hover {
    background: #f9d8f3;
}
.share-section-summary::-webkit-details-marker { display: none; }

.share-poster { border-radius: 8px; overflow: hidden; margin-bottom: 10px; }
.share-poster canvas, .share-poster img { display: block; width: 100%; height: auto; }

.share-edit { margin-top: 8px; }
.share-edit > summary {
    font-size: 13px;
    font-weight: 600;
    color: #78716c;
    cursor: pointer;
    list-style: none;
    user-select: none;
}
.share-edit > summary::-webkit-details-marker { display: none; }
.share-fields { margin-top: 10px; }

.share-actions { display: flex; gap: 7px; margin-top: 12px; flex-wrap: nowrap; align-items: center; }
.share-primary,
.share-secondary {
    font-size: 13px;
    font-weight: 600;
    color: #c83dac;
    padding: 8px 14px;
    border: 1px solid #c83dac;
    border-radius: 9px;
    background: rgba(255,255,255,0.6);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
    transition: background 0.15s;
}
.share-primary:hover,
.share-secondary:hover {
    background: rgba(255,255,255,0.85);
}
.share-primary {
    background: #fdeef9;
}
.share-primary:hover {
    background: #f9d8f3;
}
.share-flex { flex: 1; justify-content: center; }

/* Share Image dialog — editor panel controls (font row, toggle buttons, etc.) */
.share-panel-box { background: #f9f9f9; border: 1px solid #e5e7eb; }
.share-select { border-radius: 4px; border: 1px solid rgba(192,112,184,0.5); background: #fff; color: #44403c; }
.share-swatch { border: 2px solid #d6d3d1; }
.share-muted { color: #78716c; }
.share-toggle-btn { border: 1.5px solid #d6d3d1; background: #fff; color: #44403c; }
.share-toggle-btn.active { border-color: #c070b8; color: #c070b8; }
.share-accent-btn { background: #fff; color: #c070b8; }

/* Background source field (Fit/Opacity/photo picker) dimmed when its source
   choice makes it inapplicable, rather than hidden — keeps the panel's shape
   stable as the source selection changes. */
.share-field--disabled { opacity: 0.45; }

/* Pink uppercase sub-header — same treatment as the Fonts section's Title/
   Event text/Location/Logo labels, applied to other field labels in the
   dialog for a consistent visual hierarchy. */
.share-pink-label {
    font-size: 10px;
    font-weight: 700;
    color: #c070b8;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.share-pane-in { animation: sharePaneIn 0.1s ease-out both; }

@keyframes sharePaneIn {
    0%   { opacity: 0; transform: scale(0.97); }
    100% { opacity: 1; transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
    .share-pane-in { animation: none; opacity: 1; }
}

/* ── Share modal overlay ──────────────────────────────────────── */

#share-modal-overlay {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 10050;
    align-items: center;
    justify-content: center;
    padding: 16px;
    box-sizing: border-box;
    /* Force this fixed element onto its own GPU compositor layer as soon as it
       exists, rather than letting the browser promote it lazily. Without this,
       Android WebView/Chrome can paint the overlay at a stale position on first
       show (display:none -> flex) until a touch event forces a resync — seen as
       the modal appearing too low, then "snapping" into place when tapped. */
    transform: translateZ(0);
}
#share-modal-overlay.share-modal-open {
    display: flex;
    animation: shareOverlayIn 0.1s ease both;
}
#share-modal-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}
#share-modal-content {
    position: relative;
    width: 100%;
    max-width: 600px;
    max-height: calc(100dvh - 32px);
    overflow-y: auto;
}
@keyframes shareOverlayIn {
    0%   { opacity: 0; }
    100% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
    #share-modal-overlay.share-modal-open { animation: none; }
}


/* ── Tour overlay (image slideshow) ──────────────────────────────── */

#tour-overlay {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 10060;
    flex-direction: column;
    align-items: stretch;
    justify-content: center;
    transform: translateZ(0);
    box-sizing: border-box;
    padding-top: max(14px, env(safe-area-inset-top));
    padding-bottom: max(14px, env(safe-area-inset-bottom));
}
#tour-overlay.tour-open {
    display: flex;
    animation: tourOverlayIn 0.15s ease both;
}
#tour-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.88);
}
/* The topbar is a normal flex child (not pinned to the viewport edge) so it
   sits directly against the image's actual rendered top edge. The image's
   max-height is capped in JS (tour.js: fitImageToFrame) to exactly
   "available space minus topbar" — flex-grow alone can't do this, since
   object-fit:contain lets the image's layout box grow far taller than its
   visible content on wide screens, pushing the topbar apart to the screen
   edge instead of hugging the picture. Any leftover space (once the image
   is correctly capped) is centered as a group via justify-content:center
   above. The footer and Back/Next buttons are pinned to the bottom via
   position:absolute and deliberately overlap the image instead, so the
   image can claim that space too. */
#tour-topbar {
    position: relative; /* keeps this above #tour-backdrop in paint order despite being a normal-flow flex item */
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 max(16px, env(safe-area-inset-right)) 14px max(16px, env(safe-area-inset-left));
}
#tour-label {
    color: rgba(255,255,255,0.75);
    font-family: 'Poppins', sans-serif;
    font-size: 16px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}
#tour-skip {
    display: flex;
    align-items: center;
    gap: 5px;
    border: none;
    background: transparent;
    color: rgba(255,255,255,0.85);
    font-family: 'Poppins', sans-serif;
    font-size: 17px;
    font-weight: 600;
    cursor: pointer;
    padding: 6px 4px;
}
#tour-skip:hover { color: #fff; }
#tour-close {
    font-size: 24px;
    line-height: 1;
}
#tour-image {
    position: relative;
    flex: 0 0 auto;
    max-width: calc(100% - 2 * max(20px, env(safe-area-inset-left)));
    max-height: 70dvh; /* pre-JS fallback; tour.js sets a precise inline max-height once open */
    align-self: center;
    object-fit: contain;
    cursor: grab;
    touch-action: none;
    -webkit-user-drag: none;
    user-select: none;
    -webkit-user-select: none;
    transition: transform 0.2s ease;
    will-change: transform;
}
#tour-image.tour-image-dragging {
    transition: none;
    cursor: grabbing;
}
@media (prefers-reduced-motion: reduce) {
    #tour-image { transition: none; }
}
/* Overlaps the bottom of the image (rather than reserving its own flex
   row) so the image can claim that space too. */
#tour-footer {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 10px;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
}
/* Back/Next sit low beside the image, near the bottom of the screen, so
   they're within easy thumb reach on mobile. */
.tour-side-btn {
    position: absolute;
    bottom: 28px;
    z-index: 2;
    border: none;
    border-radius: 999px;
    font-family: 'Poppins', sans-serif;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    padding: 10px 16px;
    background: rgba(0,0,0,0.55);
    color: rgba(255,255,255,0.9);
    box-shadow: 0 8px 16px rgba(0,0,0,0.65), 0 3px 6px rgba(0,0,0,0.5);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
}
.tour-side-btn:hover { background: rgba(0,0,0,0.7); color: #fff; }
#tour-back { left: max(10px, env(safe-area-inset-left)); }
#tour-next { right: max(10px, env(safe-area-inset-right)); }
.tour-side-btn-cta {
    background: #c83dac;
    color: #fff;
}
.tour-side-btn-cta:hover { background: #a01f87; }
#tour-dots {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    border-radius: 999px;
    background: rgba(0,0,0,0.55);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
}
.tour-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: rgba(255,255,255,0.4);
    transition: background 0.15s;
}
.tour-dot-active { background: #fff; }
@keyframes tourOverlayIn {
    0%   { opacity: 0; }
    100% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
    #tour-overlay.tour-open { animation: none; }
}


/* ── Alerts-blocked modal ─────────────────────────────────────── */
@keyframes alertsModalIn {
    from { opacity: 0; transform: scale(0.96) translateY(6px); }
    to   { opacity: 1; transform: scale(1)    translateY(0);   }
}
#alerts-blocked-modal.alerts-modal-visible {
    display: flex;
    animation: alertsModalIn 0.18s cubic-bezier(0.22,1,0.36,1) both;
}
/* Unscoped so any modal can use it - #auth-modal does too. The dark-mode rule below was
   already unscoped, which is why a second user of the class looked half-styled. */
.alerts-modal-card {
    background: #fbf7f0;
    border: 1px solid #e7e0d8;
    border-radius: 1.25rem;
    padding: 1.5rem;
    max-width: 420px;
    width: 90%;
    box-shadow: 0 16px 48px rgba(50,30,20,0.18);
    font-family: 'Poppins', sans-serif;
}

/* Poster banner */
#poster-banner {
    margin-top: 0;
    margin-bottom: 8px;
}


.poster-banner-inner {
    background: #fff;
    border-radius: 12px;
    border: 1px solid rgba(192, 38, 163, 0.25);
    box-shadow: 0 8px 22px rgba(192, 38, 163, 0.10);
    padding: 10px 14px;
    margin-bottom: 12px;
    display: flex;
    align-items: center;
    gap: 10px;
}
.poster-banner-icon-tile {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: 8px;
    background: #fbe4f3;
    display: flex;
    align-items: center;
    justify-content: center;
}
.poster-banner-text {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
    flex: 1;
}
.poster-banner-top-row {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}
.poster-banner-title {
    flex: 1;
    min-width: 0;
    font-size: 14px;
    font-weight: 700;
    color: #231f1c;
    line-height: 1.2;
    font-family: 'Poppins', sans-serif;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.poster-banner-subtitle {
    font-size: 11.5px;
    color: #7c6f64;
    line-height: 1.3;
    font-family: 'Poppins', sans-serif;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.poster-banner-btn {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    background: #c026a3;
    color: #fff;
    font-weight: 700;
    font-size: 12px;
    font-family: 'Poppins', sans-serif;
    padding: 6px 12px;
    border-radius: 999px;
    border: none;
    cursor: pointer;
    box-shadow: 0 4px 12px rgba(192, 38, 163, 0.28);
    transition: background 0.15s;
    white-space: nowrap;
}
.poster-banner-btn:hover {
    background: #a01f87;
}


/* ── Cookie consent banner ────────────────────────────────────── */

#cookie-banner[hidden] {
    display: none !important;
}
#cookie-banner {
    position: fixed;
    inset: 0;
    z-index: 10100;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    background: rgba(0, 0, 0, 0.55);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    animation: cookieBannerIn 0.3s ease both;
}
#cookie-banner-inner {
    max-width: 420px;
    width: 100%;
    background: linear-gradient(145deg, #f9d4f3 0%, #f0b8e8 100%);
    border: 1px solid rgba(200, 61, 172, 0.35);
    border-radius: 20px;
    box-shadow: 0 12px 48px rgba(0,0,0,0.3), 0 0 0 1px rgba(200,61,172,0.15);
    padding: 28px 24px 24px;
    display: flex;
    flex-direction: column;
    gap: 20px;
}
#cookie-banner-text {
    margin: 0;
    font-size: 14px;
    color: #3d1a32;
    line-height: 1.55;
    font-weight: 500;
}
#cookie-banner-buttons {
    display: flex;
    gap: 10px;
    justify-content: flex-end;
}
#cookie-decline-btn {
    font-size: 14px;
    font-weight: 600;
    padding: 9px 20px;
    border-radius: 999px;
    border: 1.5px solid rgba(160, 31, 135, 0.45);
    background: rgba(255, 255, 255, 0.45);
    color: #7a1f68;
    cursor: pointer;
    transition: background 0.15s;
}
#cookie-decline-btn:hover {
    background: rgba(255, 255, 255, 0.65);
}
#cookie-accept-btn {
    font-size: 14px;
    font-weight: 700;
    padding: 9px 24px;
    border-radius: 999px;
    border: none;
    background: #c83dac;
    color: #fff;
    cursor: pointer;
    box-shadow: 0 4px 16px rgba(192, 38, 163, 0.4);
    transition: background 0.15s, box-shadow 0.15s;
}
#cookie-accept-btn:hover {
    background: #a01f87;
    box-shadow: 0 4px 20px rgba(192, 38, 163, 0.55);
}
@keyframes cookieBannerIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}
@keyframes cookieBannerCardIn {
    from { opacity: 0; transform: scale(0.94) translateY(10px); }
    to   { opacity: 1; transform: scale(1) translateY(0); }
}
#cookie-banner-inner {
    animation: cookieBannerCardIn 0.3s ease both;
}
.cookie-banner-out {
    animation: cookieBannerOut 0.25s ease both !important;
}
@keyframes cookieBannerOut {
    from { opacity: 1; }
    to   { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
    #cookie-banner, #cookie-banner-inner { animation: none; }
    .cookie-banner-out { animation: none !important; }
}

/* ── Promo card (Android-web "get the app" / native "add a widget") ──
   Pinned at the top of the event feed, styled distinctly from a real event
   card (gradient fill, no border/expand chrome) and not clickable/expandable
   — only its own close (x) and CTA buttons do anything. See promo-card.js. */

.promo-card {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 1.5rem;
    padding: 9px 40px 9px 12px;
    border-radius: 14px;
    background: linear-gradient(145deg, #f9d4f3 0%, #f0b8e8 100%);
    border: 1px solid rgba(200, 61, 172, 0.35);
    box-shadow: 0 2px 10px rgba(200,61,172,0.15);
    animation: promoCardIn 0.25s ease both;
}
.promo-card-icon {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.875rem;
    height: 1.875rem;
    border-radius: 50%;
    background: rgba(255,255,255,0.55);
    color: #a01f87;
}
.promo-card-icon img {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    object-fit: cover;
    display: block;
}
.promo-card-body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
}
.promo-card-text {
    margin: 0;
    font-size: 13px;
    line-height: 1.4;
    color: #3d1a32;
    font-weight: 600;
}
.promo-card-cta {
    font-size: 13px;
    font-weight: 700;
    white-space: nowrap;
    padding: 7px 16px;
    border-radius: 999px;
    border: none;
    background: #c83dac;
    color: #fff;
    cursor: pointer;
    transition: background 0.15s;
}
.promo-card-cta:hover {
    background: #a01f87;
}
.promo-card-cta-link {
    padding: 0;
    background: transparent;
    color: #a01f87;
    text-decoration: underline;
}
.promo-card-cta-link:hover {
    background: transparent;
    color: #7a1867;
}
.promo-card-close {
    position: absolute;
    top: 6px;
    right: 6px;
    font-size: 24px;
    font-weight: 700;
    line-height: 1;
    color: #7a1867;
    background: transparent;
    border: none;
    cursor: pointer;
    padding: 4px 7px;
}
.promo-card-close:hover {
    color: #3d1a32;
}
@keyframes promoCardIn {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
    .promo-card { animation: none; }
}
html.dark .promo-card {
    background: linear-gradient(145deg, #3a2334 0%, #4a2340 100%);
    border-color: rgba(200,61,172,0.4);
    box-shadow: 0 2px 10px rgba(0,0,0,0.35);
}
html.dark .promo-card-text { color: #f3e3ee; }
html.dark .promo-card-icon { background: rgba(255,255,255,0.12); color: #f3a8de; }
html.dark .promo-card-close { color: #e0b0d3; }
html.dark .promo-card-close:hover { color: #f3e3ee; }
html.dark .promo-card-cta-link { color: #f3a8de; }
html.dark .promo-card-cta-link:hover { color: #f7c7e8; }

/* ===========================
   MOBILE BOTTOM BAR  ≤640px
   =========================== */

/* Hide chip bar on mobile; top-nav stays visible inside filter-bar-wrapper */
@media (max-width: 640px) {
    #filter-chips-and-buttons { display: none !important; }
    /* Hide the search/filter row but don't collapse the whole wrapper (top-nav lives there) */
    #search-container { display: none !important; }
    /* New view-specific bars — hidden on mobile (views handle their own chrome) */
    #bar-mygigs { display: none !important; }
    /* Clear both the bottom bar (4rem) and the add-event FAB that floats
       above it (bottom:5.5rem + 3.25rem tall = 8.75rem), plus a small gap,
       so the last list item can scroll fully clear of the FAB instead of
       being permanently covered by it at the end of the feed. */
    body { padding-bottom: calc(9.5rem + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px))); }

    /* Protect logo from settings FAB across all mobile widths (was only ≤400px) */
    #logo-img {
        margin-right: 6rem !important;
        max-width: calc(100% - 6rem) !important; object-fit: contain;
    }

}

/* Settings FAB — top of the three-button stack on mobile */
@media (max-width: 640px) {
    #settings-fab {
        bottom: calc(13.5rem + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px))) !important;
        top: auto !important;
    }
}

/* Push FABs above the bar */
@media (max-width: 640px) {
    #poster-fab     { bottom: calc(9.5rem + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px))) !important; z-index: 101 !important; }
    /* #mygigs-corner-toggle's own safe-area clearance lives further down,
       scoped to html.native-app/html.chip-overflow only (where
       _mygigsAlignCornerToggle is a no-op) — an earlier unscoped copy of that
       rule lived here and fought the JS-computed top/bottom:auto positioning
       (app.js) on ordinary narrow web, forcing the button off #action-bar-
       collapse-btn's actual position (over-constrained top+bottom+height:auto
       stretches the box) instead of tracking it. */
}

/* Search bar slides up from above the bottom bar on mobile when expanded */
@media (max-width: 640px) {
    /* z-index must beat the FABs (101, above) so the expanded search bar
       covers them instead of the + button poking through on top of it. */
    #search-container[data-search-expanded="true"] {
        display: flex !important;
        position: fixed !important;
        bottom: calc(4rem + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px)));
        top: auto !important;
        left: 0;
        right: 0;
        z-index: 102 !important;
        background: #fbf7f0;
        border-top: 1px solid #e7e0d8;
        padding: 6px 8px;
        min-height: auto !important;
    }
    #search-container[data-search-expanded="true"] #search-expand-row {
        flex: 1 1 auto !important;
        min-width: 0;
    }
    /* #filter-bar-wrapper AND its own ancestor #sticky-header are both
       "sticky" with their own z-index (30 each), which each create their
       own stacking context — so the search bar's z-index:102 above only
       ever wins *inside* those contexts and was still losing to the +
       FAB (a root-level sibling at z-index:101). Bump both ancestors'
       own stacking level past the FABs while expanded so the inner
       z-index actually has something to win against. */
    #filter-bar-wrapper:has(#search-container[data-search-expanded="true"]),
    #sticky-header:has(#search-container[data-search-expanded="true"]) {
        z-index: 103 !important;
    }
    /* Reserve extra room for the expanded search bar's own height (tracked
       live in --search-bar-height by app.js) on top of the usual bottom-bar
       clearance, so the last feed item isn't left behind the search bar. On
       devices with a tall soft-nav safe-area inset the flat 9.5rem clearance
       below doesn't leave enough slack to also cover the bar itself. */
    body:has(#search-container[data-search-expanded="true"]) {
        padding-bottom: calc(9.5rem + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px)) + var(--search-bar-height, 3.5rem)) !important;
    }
}

/* Bottom bar shell — hidden on desktop */
#mobile-bottom-bar {
    display: none;
}
@media (max-width: 640px) {
    #mobile-bottom-bar {
        display: flex;
        flex-direction: column;
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        z-index: 40;
        background: #fbf7f0;
        border-top: 1px solid #e7e0d8;
        padding-bottom: var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px));
    }
}

/* Status bar — hidden until a filter is active */
#mobile-status-bar {
    display: none;
    padding: 4px 12px;
    font-size: 11px;
    font-family: 'DM Sans', sans-serif;
    color: #7a1f68;
    background: #fbf7f0;
    border-bottom: 1px solid #f0d0ea;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
#mobile-status-bar.visible {
    display: block;
}

/* Icon row */
#mobile-bottom-icons {
    display: flex;
    align-items: center;
    justify-content: space-around;
    min-height: 4rem;
    padding: 0 4px;
}

/* Individual icon buttons — column layout: icon slot on top, label below */
.mob-icon-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    min-width: 2.5rem;
    width: auto;
    height: auto;
    padding: 5px 6px 4px;
    border: none;
    background: transparent;
    color: #374151;
    border-radius: 10px;
    transition: color 0.12s;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    flex-shrink: 0;
}
.mob-icon-btn.active {
    color: #374151;
}
/* Narrowed from the default (Filter / View, and the Social tab's kind
   button) — the same dot as .mob-badge-dot, drawn by CSS so buttons that
   only toggle .active don't need their own badge element. */
.mob-icon-btn.active .mob-icon-slot::after {
    content: '';
    position: absolute;
    top: 2px;
    right: 2px;
    width: 0.6rem;
    height: 0.6rem;
    border-radius: 50%;
    background: #c83dac;
    pointer-events: none;
}
.mob-icon-btn:active .mob-icon-slot {
    background: rgba(200, 61, 172, 0.22);
}

/* Event Feed's More menu (app.js openFeedMoreMenu). Wide: a column of the
   toolbar's own buttons (their Tailwind classes, index.html) under the ⋮
   button. Narrow (.is-narrow): the bottom bar's icon-over-label buttons, on
   the bar's own colour, stacked upwards from above the ⋮ so Jump to — the
   one it replaced — sits nearest it. */
#feed-more-menu {
    position: fixed;
    z-index: 102;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
}
/* Wide Event Feed toolbar: Jump to / Add event as their own buttons when
   they fit (html.feed-more-inline — app.js updateToolbarOverflow), the ⋮
   More button in their place when they don't. */
html:not(.feed-more-inline) .feed-inline-btn { display: none !important; }
html.feed-more-inline #feed-more-btn { display: none !important; }
#feed-more-menu.hidden { display: none; }
#feed-more-backdrop {
    position: fixed;
    inset: 0;
    z-index: 101;
    background: rgba(0, 0, 0, 0.4);
}
#feed-more-backdrop.hidden { display: none; }
#feed-more-menu .feed-more-item { box-shadow: 0 4px 14px rgba(0, 0, 0, 0.25); }
#feed-more-menu .feed-more-icon { display: flex; flex-shrink: 0; }
#feed-more-menu.is-narrow {
    flex-direction: column-reverse;
}
#feed-more-menu.is-narrow .feed-more-item {
    flex-direction: column;
    justify-content: center;
    gap: 2px;
    min-width: 4rem;
    padding: 5px 6px 4px;
    border-radius: 10px;
    background: #fbf7f0;
    color: #374151;
}
#feed-more-menu.is-narrow .feed-more-icon {
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
}
#feed-more-menu.is-narrow .feed-more-item:active .feed-more-icon { background: rgba(200, 61, 172, 0.22); }
#feed-more-menu.is-narrow .feed-more-label {
    font-size: 14px;
    line-height: 1;
    font-family: 'DM Sans', sans-serif;
    font-weight: 500;
}
/* Dark: a shade lighter than the bar, with a visible edge, so the buttons
   don't sink into the dimmed page behind them. */
html.dark #feed-more-menu .feed-more-item { background: #3a332b; border-color: #6b5f52; color: #e7ddd2; }
html.dark #feed-more-backdrop { background: rgba(0, 0, 0, 0.6); }

/* Icon slot — contains the SVG and optional badge */
.mob-icon-slot {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    transition: background 0.12s;
}

/* Text label under icon */
.mob-label {
    font-size: 14px;
    line-height: 1;
    font-family: 'DM Sans', sans-serif;
    font-weight: 500;
    color: inherit;
    text-align: center;
    white-space: nowrap;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* The attendance / kind buttons' labels can be long ("Recommended"); with
   large system text on a small phone (MainActivity textZoom) the row can
   overflow, so let just these shrink and ellipsise rather than the fixed
   labels around them. */
#mob-view-btn, #social-kind-btn { flex-shrink: 1; }

/* Number badge (venue / genre count) */
.mob-badge {
    position: absolute;
    top: 0;
    right: 0;
    min-width: 1.1rem;
    height: 1.1rem;
    padding: 0 3px;
    border-radius: 999px;
    background: #c83dac;
    color: #fff;
    font-size: 10px;
    font-family: 'DM Sans', sans-serif;
    font-weight: 700;
    line-height: 1.1rem;
    text-align: center;
    pointer-events: none;
}

/* Plain dot variant — used by the combined Filters button below, which
   can't show a single count (it may be standing in for a venue count, a
   genre count, or both) without it looking like it belongs to one or the
   other. */
.mob-badge-dot {
    min-width: 0.6rem;
    width: 0.6rem;
    height: 0.6rem;
    padding: 0;
    top: 2px;
    right: 2px;
}

/* What the feed is filtered to, above the first group (app.js renderActiveFilters) */
#active-filters, .active-filters-line {
    padding: 8px 4px 4px;
    font-size: 13px;
    color: #78716c;
}
#active-filters[hidden] { display: none; }
#active-filters button, .active-filters-line button { color: #7a1f68; text-decoration: underline; text-underline-offset: 2px; }

/* Attendance menu as bottom sheet on mobile */
@media (max-width: 640px) {
    #attendance-menu, #soc-kind-menu {
        position: fixed !important;
        top: auto !important;
        bottom: calc(4rem + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px))) !important;
        left: 0 !important;
        right: 0 !important;
        width: 100% !important;
        border-radius: 12px 12px 0 0 !important;
        border-left: none !important;
        border-right: none !important;
        border-bottom: none !important;
        padding: 8px 0 12px !important;
        z-index: 200 !important;
        box-shadow: 0 -4px 20px rgba(0,0,0,0.15) !important;
        min-width: unset !important;
    }
}

/* Filter/settings panel (venue + genre filters) as a bottom sheet on mobile,
   consistent with the My Gigs settings panel (mygigs/styles.css) instead of
   sliding in from the right like the wide side-drawer. Fixed height (top
   pinned level with the main tabs — see --fn-sheet-top-clamped in
   social.css — and bottom pinned) so switching between the Venues/Genres tabs — which hold very
   different amounts of content — doesn't grow/shrink the sheet; it opens at
   one size and stays there, scrolling its body internally instead. */
@media (max-width: 640px) {
    #settings-panel {
        top: var(--fn-sheet-top-clamped);
        right: 0;
        left: 0;
        bottom: 0;
        width: 100%;
        max-width: 100%;
        height: auto;
        border-left: none !important;
        border-top: 2px solid #C070B8;
        border-radius: 16px 16px 0 0;
        box-shadow: 0 -4px 24px rgba(0,0,0,0.15);
        transform: translateY(100%);
        padding-bottom: var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px));
    }
    #settings-panel.panel--open {
        transform: translateY(0);
    }
}

/* ===========================
   NATIVE ANDROID APP OVERRIDES
   Mirror all ≤640px mobile-bar rules so the bottom bar is always shown
   when running inside the Capacitor shell, regardless of screen width.
   html.chip-overflow shares these rules — it's set by JS (see app.js
   updateToolbarOverflow) whenever the wide-view chip row no longer fits its
   available width, so the toolbar drops to the mobile bar instead of letting
   chips overlap or scroll off-screen.
   =========================== */
html.native-app #filter-chips-and-buttons, html.chip-overflow #filter-chips-and-buttons { display: none !important; }
html.native-app #search-container, html.chip-overflow #search-container { display: none !important; }
/* See the ≤640px rule above for why this clears 9.5rem, not just the 4rem bar. */
html.native-app body, html.chip-overflow body { padding-bottom: calc(9.5rem + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px))); }
html.native-app #logo-img, html.chip-overflow #logo-img { margin-right: 6rem !important; max-width: calc(100% - 6rem) !important; object-fit: contain; }
/* #bar-mygigs (the My Gigs tab's own action bar, in the main app header — see
   index.html) is "wide only" by design: it's hidden on web whenever the
   ≤640px mobile rule below fires, but was never mirrored here, so a
   phone/tablet rotated to landscape inside the app could still show it
   alongside mygigs/styles.css's own now-forced-narrow #style-bar. */
html.native-app #bar-mygigs, html.chip-overflow #bar-mygigs { display: none !important; }
/* Content that only makes sense inside the native app (add-widget/rate menu
   items, and the divider that separates them) — hidden on web, shown once
   html.native-app is set. */
.native-only { display: none; }
html.native-app .native-only { display: block; }
.native-only-menu-item { display: none; }
html.native-app .native-only-menu-item { display: flex; }
html.no-widgets #user-menu-widget-btn { display: none; }
.ios-only-steps { display: none; }
html.ios-app .ios-only-steps { display: block; }
html.ios-app .android-only-steps { display: none; }
.web-only-menu-item { display: flex; }
html.native-app .web-only-menu-item { display: none; }

.user-menu-divider { margin: 0.25rem 0; border-top: 1px solid #e7e0d8; }
html.dark .user-menu-divider { border-top-color: #52483d; }

html.native-app #settings-fab, html.chip-overflow #settings-fab { bottom: calc(13.5rem + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px))) !important; top: auto !important; }
html.native-app #poster-fab, html.chip-overflow #poster-fab    { bottom: calc(9.5rem + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px))) !important; z-index: 101 !important; }
/* Same clearance as the FABs above, and for the same reason: unlike the
   ≤640px web rule (which the JS-computed position from
   _mygigsAlignCornerToggle usually overrides once the poster reveals), that
   function bails out immediately in native-app, so its flat inline
   bottom:1.5rem (index.html) is what actually renders there — needs its own
   safe-area clearance to stay clear of a soft nav/gesture bar. */
html.native-app #mygigs-corner-toggle, html.chip-overflow #mygigs-corner-toggle { bottom: calc(1.5rem + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px))) !important; }

html.native-app #search-container[data-search-expanded="true"],
html.chip-overflow #search-container[data-search-expanded="true"] {
    display: flex !important;
    position: fixed !important;
    bottom: calc(4rem + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px)));
    top: auto !important;
    left: 0;
    right: 0;
    z-index: 102 !important;
    background: #fbf7f0;
    border-top: 1px solid #e7e0d8;
    padding: 6px 8px;
    min-height: auto !important;
}
html.native-app #search-container[data-search-expanded="true"] #search-expand-row,
html.chip-overflow #search-container[data-search-expanded="true"] #search-expand-row {
    flex: 1 1 auto !important;
    min-width: 0;
}
/* Same nested-stacking-context fix as the mobile media query above. */
html.native-app #filter-bar-wrapper:has(#search-container[data-search-expanded="true"]),
html.native-app #sticky-header:has(#search-container[data-search-expanded="true"]),
html.chip-overflow #filter-bar-wrapper:has(#search-container[data-search-expanded="true"]),
html.chip-overflow #sticky-header:has(#search-container[data-search-expanded="true"]) {
    z-index: 103 !important;
}
/* Same extra-clearance fix as the mobile media query above. */
html.native-app body:has(#search-container[data-search-expanded="true"]),
html.chip-overflow body:has(#search-container[data-search-expanded="true"]) {
    padding-bottom: calc(9.5rem + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px)) + var(--search-bar-height, 3.5rem)) !important;
}

html.native-app #mobile-bottom-bar, html.chip-overflow #mobile-bottom-bar {
    display: flex;
    flex-direction: column;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 40;
    background: #fbf7f0;
    border-top: 1px solid #e7e0d8;
    padding-bottom: var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px));
}

html.native-app #attendance-menu, html.chip-overflow #attendance-menu,
html.native-app #soc-kind-menu, html.chip-overflow #soc-kind-menu {
    position: fixed !important;
    top: auto !important;
    bottom: calc(4rem + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px))) !important;
    left: 0 !important;
    right: 0 !important;
    width: 100% !important;
    border-radius: 12px 12px 0 0 !important;
    border-left: none !important;
    border-right: none !important;
    border-bottom: none !important;
    padding: 8px 0 12px !important;
    z-index: 200 !important;
    box-shadow: 0 -4px 20px rgba(0,0,0,0.15) !important;
    min-width: unset !important;
}

/* Filter/settings panel as bottom sheet, forced regardless of viewport width
   — mirrors the ≤640px rule above (see #settings-panel there for context). */
html.native-app #settings-panel, html.chip-overflow #settings-panel {
    top: var(--fn-sheet-top-clamped) !important;
    right: 0 !important;
    left: 0 !important;
    bottom: 0 !important;
    width: 100% !important;
    max-width: 100% !important;
    height: auto !important;
    border-left: none !important;
    border-top: 2px solid #C070B8 !important;
    border-radius: 16px 16px 0 0 !important;
    box-shadow: 0 -4px 24px rgba(0,0,0,0.15) !important;
    transform: translateY(100%) !important;
    padding-bottom: var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px)) !important;
}
html.native-app #settings-panel.panel--open, html.chip-overflow #settings-panel.panel--open {
    transform: translateY(0) !important;
}

/* Sort slide-up sheet */
#mob-sort-sheet, #soc-sort-sheet {
    position: fixed;
    bottom: calc(4rem + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px)));
    left: 0;
    right: 0;
    background: #fff;
    border-radius: 12px 12px 0 0;
    border-top: 1px solid #e7e0d8;
    z-index: 200;
    padding: 8px 0 16px;
    box-shadow: 0 -4px 20px rgba(0,0,0,0.15);
}
.mob-sheet-handle {
    width: 36px;
    height: 4px;
    background: #d1c8c0;
    border-radius: 2px;
    margin: 4px auto 10px;
}
.mob-sheet-title {
    font-family: 'DM Sans', sans-serif;
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: #D4537E;
    padding: 0 16px 6px;
    margin: 0;
}
.mob-sheet-option {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 16px;
    font-size: 14px;
    font-family: 'DM Sans', sans-serif;
    color: #3e352e;
    cursor: pointer;
    user-select: none;
}
.mob-sheet-option input[type="radio"] {
    accent-color: #c83dac;
    flex-shrink: 0;
}

/* Sheet backdrop */
#mob-sheet-overlay {
    position: fixed;
    inset: 0;
    z-index: 199;
    background: rgba(0,0,0,0.25);
}

/* Jump-to calendar: reposition above the bar on mobile */
@media (max-width: 640px) {
    #jump-to-dropdown {
        bottom: calc(4.1rem + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px))) !important;
        top: auto !important;
        left: 50% !important;
        transform: translateX(-50%) !important;
    }
}

/* ── Top navigation bar ── */
#top-nav {
    display: flex;
    border-top: 1px solid #e7e0d8;
    border-bottom: 1px solid #e7e0d8;
    background: #fbf7f0;
    max-height: 100px;
    overflow: hidden;
    transition: max-height 0.25s ease, opacity 0.2s ease;
}
.top-nav-btn {
    flex: 1;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 0.45rem 0.25rem;
    color: #5c5c5c;
    background: transparent;
    border: none;
    cursor: pointer;
    position: relative;
    transition: color 0.15s;
    font-family: 'DM Sans', sans-serif;
}
.top-nav-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
}
.top-nav-label {
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    line-height: 1;
}
.top-nav-btn.active {
    color: #000;
}
.top-nav-btn.active::after {
    content: '';
    position: absolute;
    bottom: -1px;
    left: 0;
    right: 0;
    height: 4px;
    background: #000;
}

/* ── Main view switching ── */
.main-view.hidden { display: none !important; }

/* #about-view is gone — About is a modal now (#about-modal, index.html) and
   the Social tab took its top-nav slot (#social-view, social.css). The
   rules below are shared by the modal's content, which kept the same ids. */

#about-social-row {
    display: flex;
    margin-top: 0.75rem;
}

#about-social-row a {
    flex: 1;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 0.5rem 0.25rem;
    transition: opacity 0.12s;
}
#about-social-row a:hover { opacity: 0.7; }

.store-link-slot {
    display: flex;
    justify-content: center;
    margin: 1.5rem 0;
}
.store-link-slot:empty { display: none; }
.store-link-slot a { transition: opacity 0.12s; }
.store-link-slot a:hover { opacity: 0.8; }

#about-footer-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.65rem 1rem 0.65rem 1rem;
}
#about-privacy {
    text-align: left;
    font-size: 0.75rem;
    color: #8a7a6a;
    padding: 0;
    margin: 0;
}
#about-privacy a {
    color: inherit;
    text-decoration: underline;
}

/* Fix both views to the viewport so they always sit directly below the sticky header —
   this ensures bottom bars stay pinned at the viewport bottom regardless of scroll position */
#mygigs-view, #social-view {
    position: fixed !important;
    top: var(--sticky-header-height, 0px) !important;
    left: 0 !important;
    right: 0 !important;
    bottom: 0 !important;
    height: auto !important;
    margin: 0 !important;
    z-index: 25;
}

/* mygigs content is injected directly — needs scroll + padding for fixed action-bar */
#mygigs-view {
    overflow-y: auto !important;
    padding: 12px 12px 80px !important;
}

/* Narrow only: mygigs/styles.css docks a quick style-switcher bar (~50px)
   above its own #action-bar — the injected content needs the same extra
   scroll clearance here so the last item isn't hidden behind it. */
@media (max-width: 640px) {
    #mygigs-view {
        padding-bottom: 138px !important;
    }
}

/* ── My Gigs tab (#mygigs or /home — same view) — poster by default ────────
   Toggled by switchMainView() (app.js) for viewName 'mygigs'. By default
   hides every piece of app/mygigs chrome so only the poster itself is on
   screen (events clickable, jumping to the Event Feed — poster.js). Poster ⇄
   Controls (title bar + action bar) is moved by mygigsToggleCornerPeek
   (app.js) — #action-bar-collapse-btn, a regular button inside #action-bar
   itself (mygigs/index.html), collapses; the floating #mygigs-corner-toggle
   (index.html), only ever shown while collapsed, expands back. Settings
   opens/closes independently via the action bar's real
   Settings button (#panel-toggle) or #panel-close, remembered across a
   collapse/expand cycle by that same function. html.mygigs-controls-peek
   covers both the Controls and Settings steps (i.e. "at least the
   title/action bar are showing") — the slide/resize CSS below doesn't need
   to distinguish further, since #mg-settings-panel is a floating overlay on
   top of the action bar, not something that changes the Controls-step chrome
   underneath it. Peeking makes events inert (poster.js); the real top-nav
   (now visible) and the action bar's Settings button are the way back to the
   rest of the app / into the settings panel at that point — #mg-settings-panel
   itself isn't force-hidden here, since it can only ever be opened via that
   Settings button (or the corner toggle restoring it) in the first place. */
html.mygigs-homepage-mode #mobile-bottom-bar,
html.mygigs-homepage-mode #offline-banner {
    display: none !important;
}

/* Collapsed: full-bleed poster — the (off-screen) header/action bar don't
   need any clearance. Without the explicit top:0, --sticky-header-height
   (app.js) would still reserve the header's normal, non-zero offsetHeight
   even while it's translated away, since a transform doesn't remove an
   element from layout flow. Peeked open: the reverse — the header/action bar
   are now real on-screen content again, so the canvas must shrink to sit
   between them (top clears the header, padding-bottom clears the action bar,
   reusing the same clearance #mygigs-view uses outside My Gigs entirely —
   see above) rather than being covered by them. */
html.mygigs-homepage-mode #mygigs-view {
    top: 0 !important;
    padding-bottom: 12px !important;
    transition: top 0.28s ease, padding-bottom 0.28s ease;
}
html.mygigs-homepage-mode.mygigs-controls-peek #mygigs-view {
    top: var(--sticky-header-height, 0px) !important;
    padding-bottom: 80px !important;
}
@media (max-width: 640px) {
    html.mygigs-homepage-mode.mygigs-controls-peek #mygigs-view {
        padding-bottom: 138px !important;
    }
}

/* #sticky-header's own inline margin:-1rem/padding:1rem (index.html) are a
   matched pair that cancel out under its normal position:sticky flow inside
   #main-content's px-4 padding, netting a 1rem inset from the viewport edge
   for its content (and #user-account-btn within it). Once position:fixed
   takes it out of #main-content's box, that containing block is the viewport
   itself (no padding to cancel against), so the negative margins just expand
   the box 1rem past each edge instead — the padding then only claws back
   its OWN 1rem, leaving content flush with the true viewport edge and
   #user-account-btn 1rem further right than on every other tab. Zeroing the
   margins here for the fixed case removes the mismatch without touching the
   sticky case's own trick. */
html.mygigs-homepage-mode #sticky-header {
    position: fixed !important;
    top: 0; left: 0; right: 0;
    margin-left: 0 !important;
    margin-right: 0 !important;
    transition: transform 0.28s ease !important;
    transform: translateY(-100%);
}
html.mygigs-homepage-mode.mygigs-controls-peek #sticky-header {
    transform: translateY(0);
}

/* #action-bar is already position:fixed (mygigs/styles.css) — just add the
   slide. Stays hidden entirely on wide (existing html.embedded:not(.native-app)
   rule, higher specificity) — wide's equivalent controls live in #bar-mygigs,
   inside the sticky-header above, so nothing extra is needed for that layout
   here. */
html.mygigs-homepage-mode #action-bar {
    transition: transform 0.28s ease !important;
    transform: translateY(100%);
}
html.mygigs-homepage-mode.mygigs-controls-peek #action-bar {
    transform: translateY(0);
}
/* Narrow-only style-switcher strip (#style-bar, mygigs/styles.css) docks
   above #action-bar via its own viewport-anchored position:fixed — despite
   being a DOM descendant of #action-bar, it does NOT ride along with that
   element's transform above in practice (expected per spec — a transformed
   ancestor should become the containing block for fixed descendants — but
   not what's observed here, so don't rely on it). Fade it independently
   instead of chasing the exact slide distance. */
html.mygigs-homepage-mode #style-bar {
    transition: opacity 0.15s ease !important;
}
html.mygigs-homepage-mode:not(.mygigs-controls-peek) #style-bar {
    opacity: 0 !important;
    pointer-events: none !important;
}

/* #mygigs-corner-toggle (index.html) is My Gigs' only way back from
   bare-poster mode to Controls — the trip the other way (Controls -> Poster)
   is #action-bar-collapse-btn, a regular button inside #action-bar itself
   (mygigs/index.html), not this floating one. Single-purpose now (it only
   ever means "expand"), so unlike most of My Gigs's other fixed elements it
   deliberately doesn't need to stay clear of anything: bare-poster mode
   hides #mobile-bottom-bar unconditionally and slides #action-bar/#style-bar
   off-screen (below), so nothing else is ever docked along the bottom of the
   screen while this button can show — a static bottom:1.5rem;right:1.25rem
   (index.html) is all it needs, no per-breakpoint math. Only shown at all
   while .mygigs-homepage-mode and not .mygigs-controls-peek — everywhere
   else (including Event Feed/About, which have no Poster/Controls concept
   of their own) it stays at its display:none default. */
html.mygigs-homepage-mode:not(.mygigs-controls-peek) #mygigs-corner-toggle {
    display: flex !important;
}
/* Matches #action-bar's own dark background (mygigs/styles.css) — see the
   light value inline in index.html for why (same spot, same colour, reads
   as "the bar faded except this button" rather than a new control). */
html.dark #mygigs-corner-toggle {
    background: #2b251e;
}
/* Idle-fades instead of sitting on the poster indefinitely. switchMainView
   (app.js) starts it shown whenever My Gigs is entered (tab click, /home, a
   plain #mygigs link) — only a /poster deep link forces it to start hidden,
   so a browser homepage bookmarked there reads as a clean poster rather than
   an app with a UI button sitting on it. Either way, any interaction reveals
   it (_mygigsShowPosterChrome/app.js) and restarts the idle timer that fades
   it back out after MYGIGS_POSTER_IDLE_FADE_MS (app.js, 30s). Layers opacity on top of the
   display:flex above so it still occupies its fixed slot, just
   invisible/inert in between. native-app is excluded — there's no /poster
   there (no address bar to bookmark it), and the button should stay its
   normal always-on self during ordinary in-app poster browsing. */
html.mygigs-homepage-mode:not(.mygigs-controls-peek):not(.native-app) #mygigs-corner-toggle {
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.4s ease;
}
html.mygigs-homepage-mode:not(.mygigs-controls-peek):not(.native-app).mg-poster-chrome-active #mygigs-corner-toggle {
    opacity: 1;
    pointer-events: auto;
}

/* ── Offline banner (position:fixed) ───────────────────────────────────────── */
/* Push main content and sticky filter bar down when offline banner is visible  */
html.is-offline #main-content {
    padding-top: 1.85rem;
}
html.is-offline #filter-bar-wrapper {
    top: 1.85rem !important;
}

/* ═══════════════════════════════════════════════════════════════
   DARK MODE — html.dark, toggled from the account menu.
   Warm dark palette mirroring the sepia light theme:
     page #211c17 · surface #2b251e · elevated #332c24 · hover #3a332a
     border #3a332b / #463d33 · pink hover-tint #3a2334
     text #ede5da / #c9bcae / #8f8275 · accent-as-text #e06ac8
   !important is only used where an inline style must be beaten.
   ═══════════════════════════════════════════════════════════════ */

/* ── App shell ── */
html.dark body { background-color: #211c17; color: #c9bcae; }
html.dark h1, html.dark h2, html.dark h3, html.dark h4, html.dark h5 { color: #ede5da; }
html.dark #splash-screen { background: #211c17; }
html.dark #sticky-header, html.dark #main-header { background-color: #211c17 !important; }
html.dark #sticky-header { box-shadow: 0 2px 10px rgba(0,0,0,0.4); }
/* Tagline is an image of dark glyphs — invert so it reads as light grey (≈#bcbab8, ~8.8:1) */
html.dark #tagline-img { filter: grayscale(1) invert(1) opacity(0.7); }
html.dark #splash-tag { filter: grayscale(1) invert(1) opacity(0.7); }
html.dark #filter-bar-wrapper { background-color: #211c17 !important; }
html.dark #top-nav { background: #2b251e; border-top-color: #3a332b; border-bottom-color: #3a332b; }
html.dark .top-nav-btn { color: #9a8d80; }
html.dark .top-nav-btn.active { color: #fff; }
html.dark .top-nav-btn.active::after { background: #fff; }
html.dark #mobile-bottom-bar { background: #2b251e; border-top-color: #3a332b; }
html.dark #active-filters, html.dark .active-filters-line { color: #9a8d80; }
html.dark #active-filters button, html.dark .active-filters-line button { color: #e0a8d2; }
html.dark #mobile-status-bar { background: #2b251e; border-bottom-color: #4a2340; color: #e0a8d2; }
html.dark .mob-icon-btn, html.dark .mob-icon-btn.active { color: #c9bcae; }
/* Filter dots: the dark-mode accent pink, with a ring in the bar colour so
   they stand clear of the icon/chip border (as .soc-tab-dot does) */
html.dark .mob-badge-dot, html.dark .mob-icon-btn.active .mob-icon-slot::after { background: #e06ac8; box-shadow: 0 0 0 2px #2b251e; }
html.dark #chip-hot-toggle.active::after, html.dark #chip-filters.active::after,
html.dark #bar-social-kind-btn.active::after, html.dark #bar-social-filter-btn.active::after { background: #e06ac8; box-shadow: 0 0 0 2px #211c17; }
html.dark #search-container[data-search-expanded="true"] { background: #211c17; border-top-color: #3a332b; }
html.dark #mygigs-view { background: #211c17 !important; }
html.dark #about-scroll span { color: #ede5da !important; }
html.dark #about-build-label, html.dark #about-privacy { color: #9a8d80 !important; }
html.dark #filter-chips-and-buttons::after { background: linear-gradient(to left, #211c17, rgba(33, 28, 23, 0)); }
html.dark input[type="search"], html.dark input[type="text"], html.dark textarea { color: #ede5da; }
html.dark input::placeholder, html.dark textarea::placeholder { color: #9a8d80; }
html.dark #search-clear-btn { color: #9a8d80; }
html.dark #search-clear-btn:hover { color: #ede5da; }

/* ── Tailwind utility remaps (surfaces) ── */
html.dark .bg-white { background-color: #2b251e; }
html.dark .bg-white\/50 { background-color: #2a241d; }
html.dark .bg-white\/60 { background-color: #2d271f; }
html.dark .bg-white\/80 { background-color: #322b22; }
html.dark .hover\:bg-white\/80:hover { background-color: #3a332a; }
html.dark .bg-stone-50, html.dark .hover\:bg-stone-50:hover { background-color: #332c24; }
html.dark .hover\:bg-gray-50:hover { background-color: #332c24; }
html.dark .bg-stone-100, html.dark .hover\:bg-stone-100:hover { background-color: #3a332a; }
html.dark .bg-stone-200 { background-color: #3f362c; }
html.dark .bg-blue-50 { background-color: #26303a; }
html.dark .bg-red-50, html.dark .hover\:bg-red-50:hover { background-color: #3a2626; }
html.dark .bg-red-50\/40 { background-color: rgba(220, 38, 38, 0.10); }
html.dark .bg-pink-50\/60 { background-color: rgba(224, 106, 200, 0.10); }
html.dark .bg-emerald-50\/30 { background-color: rgba(16,185,129,0.10); }
html.dark .bg-sky-50\/20 { background-color: rgba(56,189,248,0.10); }
html.dark .ev-tone-sent-you { border-color: #c29033; background-color: rgba(232,170,60,0.18); }
html.dark .ev-tone-sent-group { border-color: #6e5630; background-color: rgba(232,170,60,0.07); }
html.dark .ev-sent-label { color: #f2c572; background-color: #4a3715; }
html.dark .bg-\[\#f5d0f0\] { background-color: #4a2340; }
html.dark .text-\[\#7a1f68\] { color: #f0d9e8; }
html.dark .bg-gray-100 { background-color: #2b251e; }

/* ── Tailwind utility remaps (borders / rings) ── */
html.dark .border-stone-100, html.dark .border-stone-200, html.dark .border-stone-200\/80 { border-color: #3a332b; }
html.dark .border-stone-300 { border-color: #463d33; }
html.dark .border-stone-400, html.dark .border-gray-400 { border-color: #52483d; }
html.dark .border-gray-300 { border-color: #463d33; }
html.dark .border-gray-200 { border-color: #3a332b; }
html.dark .border-red-200 { border-color: #5a3333; }
html.dark .border-red-300 { border-color: #7f3a3a; }
html.dark .border-pink-300 { border-color: #6b3560; }
html.dark .border-emerald-300 { border-color: #2f6b52; }
html.dark .border-sky-300 { border-color: #33627e; }
html.dark .border-blue-300 { border-color: #3d6a8c; }
html.dark .border-blue-400 { border-color: #5a8db5; }
html.dark .ring-stone-200 { --tw-ring-color: #463d33; }

/* ── Tailwind utility remaps (text) ── */
html.dark .text-stone-300 { color: #6b6154; }
html.dark .text-stone-400 { color: #9a8d80; }
html.dark .text-gray-400 { color: #736657; }
html.dark .text-stone-500 { color: #a3968a; }
html.dark .text-stone-600 { color: #b3a698; }
html.dark .text-stone-700 { color: #c9bcae; }
html.dark .text-stone-800 { color: #ded3c5; }
html.dark .text-gray-700 { color: #c9bcae; }
html.dark .hover\:text-stone-600:hover { color: #c9bcae; }
html.dark .hover\:text-gray-900:hover { color: #ede5da; }
html.dark .hover\:text-stone-700:hover, html.dark .hover\:text-stone-800:hover { color: #ede5da; }
html.dark .text-blue-600 { color: #7ab8f5; }
html.dark .text-red-700 { color: #f0a0a0; }
html.dark .text-\[\#c83dac\] { color: #e06ac8; }

/* ── Account menu (inline-styled) ── */
html.dark #user-account-menu { background: #332c24 !important; border-color: #463d33 !important; box-shadow: 0 8px 24px rgba(0,0,0,0.5) !important; }
html.dark #user-account-menu button[role="menuitem"] { color: #fff !important; }
/* "Signed in as" + the address: the light-mode greys vanish on the dark menu */
html.dark #user-menu-account-label { color: #c9bcae !important; }
html.dark #user-menu-account-email { color: #ede5da !important; }
html.dark #user-menu-account > div { border-top-color: #52483d !important; }

/* ── Event feed details ── */
/* Titles and date blocks are inline-styled in ui.js (createEventHTML), so these
   attribute-scoped overrides must track the colour literals used there. */
html.dark [data-event-id] h3[style*="color:#111"] { color: #ece5db !important; }
html.dark [data-event-id] h3[style*="color:#e83d85"] { color: #f0619c !important; }
html.dark [data-event-id] span[style*="color:#878582"] { color: #a09d99 !important; }
html.dark .highlight { background-color: #4a2334 !important; }
html.dark .pill-genre { background: #3d3014; color: #e8c15c; border-color: #6b5416; }
html.dark .pill-promoter { background: #14303d; color: #62b8e8; border-color: #1e4a5e; }
html.dark .attendance-btn { background: #2b251e; color: #c9bcae; border-color: #463d33; }
html.dark .attendance-btn:hover { background: #3a332a; }
html.dark .attendance-btn-active { background: #3a2334; border-color: #c83dac; color: #e06ac8; }
html.dark .status-icon { color: #e06ac8; }
html.dark .ev-status-going { color: #6ee7b7; background-color: rgba(16,185,129,0.14); border-color: #059669; }
html.dark .ev-status-interested { color: #7dd3fc; background-color: rgba(56,189,248,0.14); border-color: #0284c7; }
html.dark .ev-status-recommended { color: #f9a8d4; background-color: rgba(236,72,153,0.14); border-color: #db2777; }
html.dark .poster-banner-inner { background: #2b251e; border-color: rgba(224,106,200,0.3); box-shadow: 0 8px 22px rgba(0,0,0,0.3); }
html.dark .poster-banner-icon-tile { background: #4a2340; }
html.dark .poster-banner-title { color: #ede5da; }
html.dark .poster-banner-subtitle { color: #a3968a; }

/* ── Popups, sheets and menus ── */
html.dark .search-order-option { color: #ded3c5; }
html.dark .search-order-option:hover { background-color: #3a332a; }
html.dark .search-order-option.active { color: #ff8f63; }
html.dark #search-order-btn.active svg { color: #ff8f63; }
html.dark #new-venues-toggle-btn.active { background-color: #4a2340; border-color: #8f8275; }
html.dark #mob-sort-sheet, html.dark #soc-sort-sheet { background: #2b251e; border-top-color: #463d33; box-shadow: 0 -4px 20px rgba(0,0,0,0.5); }
html.dark .mob-sheet-handle { background: #52483d; }
html.dark .mob-sheet-option { color: #ded3c5; }

/* ── Segmented controls ── */
html.dark .segmented-control { border-color: #8f8275; background-color: #2b251e; }
html.dark .segmented-btn { background-color: #2b251e; color: #ded3c5; }
html.dark .segmented-btn:not(:last-child) { border-right-color: #8f8275; }
html.dark .segmented-btn.active { background-color: #4a2340; color: #f0d9e8; }
html.dark .segmented-btn:hover:not(.active) { background-color: #3a332a; }

/* ── Share / Tag / overflow pickers (inline-styled background) ── */
html.dark [id^="share-picker-"], html.dark [id^="tag-picker-"], html.dark [id^="overflow-menu-"], html.dark [id^="details-picker-"], html.dark [id^="ticket-picker-"] { background: #332c24 !important; border-color: #6b3560 !important; box-shadow: 0 8px 24px rgba(0,0,0,0.5) !important; }
html.dark [id^="share-picker-"] button:hover, html.dark [id^="tag-picker-"] button:hover, html.dark [id^="overflow-menu-"] button:hover, html.dark [id^="details-picker-"] button:hover, html.dark [id^="ticket-picker-"] button:hover { background-color: #3a2334 !important; }
html.dark [id^="share-picker-"] .border-stone-100, html.dark [id^="tag-picker-"] .border-stone-100 { border-color: #463d33; }

/* ── Alerts-blocked modal (inline-styled text) ── */
html.dark .alerts-modal-card { background: #2b251e !important; border-color: #463d33 !important; box-shadow: 0 16px 48px rgba(0,0,0,0.5) !important; }
/* A dark card on a darkened dark page doesn't stand out — lighten what's
   behind a modal instead (a pale haze), for every centred-card dialog.
   The sheet backdrop (social.css) and the Add Event overlay below match. */
html.dark #about-modal, html.dark #tab-help-modal, html.dark #alerts-blocked-modal, html.dark #auth-modal { background: rgba(237, 229, 218, 0.28) !important; }
html.dark #alerts-blocked-modal h2, html.dark #auth-modal h2 { color: #ede5da !important; }
html.dark #alerts-blocked-modal p, html.dark #alerts-blocked-modal li,
html.dark #auth-modal p, html.dark #auth-modal label { color: #b3a698 !important; }
/* The auth modal has inputs, which the alerts modal does not. */
html.dark #auth-modal input { background: #1b1713 !important; border-color: #463d33 !important; color: #ded3c5 !important; }
/* More specific than "html.dark #auth-modal p" above, so this wins over the muted p color. */
html.dark #auth-modal #auth-error { color: #ff8a80 !important; background: rgba(255,138,128,0.14) !important; border-color: rgba(255,138,128,0.4) !important; }
html.dark #auth-close-btn { border-color: #463d33 !important; color: #b3a698 !important; }
/* Secondary buttons are inline-styled for light mode only (white fill, or plain
   muted text) - unfixed, "Email Link" rendered as a near-opaque white box sitting
   in the middle of the dark card, and the two "Use a different email" buttons were
   too close in tone to the card to read. */
html.dark #auth-send-link-btn, html.dark #auth-google-btn { background: #2b251e !important; border-color: #c83dac !important; color: #e06ac8 !important; }
html.dark #auth-back-btn, html.dark #auth-link-back-btn, html.dark #auth-form-back-btn { color: #b3a698 !important; }
html.dark #alerts-blocked-modal strong { color: #ded3c5 !important; }
html.dark #alerts-open-settings-btn { background: #332c24 !important; }

/* ── Settings panel ── */
html.dark #settings-panel > div:has(> .tab-btn) { background-color: #2b251e !important; }
html.dark #settings-panel .flex.border-b.border-stone-300 { border-bottom: 1px solid #463d33 !important; }
html.dark #settings-panel-body { background-color: #211c17 !important; }
html.dark .tab-btn { color: #9a8d80; }
html.dark .collapsible-section { border-bottom-color: #3a332b; }
html.dark #settings-panel-body::-webkit-scrollbar-track { background: #211c17; }
html.dark #settings-panel-body::-webkit-scrollbar-thumb { background: #52483d; }
html.dark #settings-panel-body::-webkit-scrollbar-thumb:hover { background: #6b5f4f; }

/* QR code box under the share icon row (share.js showShareTextModal, qr: true).
   Kept white in dark mode too — a code on a dark tile doesn't scan. */
.share-qr { margin-top: 0.75rem; padding: 0.5rem; border-radius: 0.75rem; background: #fff; text-align: center; }
.share-qr svg { display: block; width: min(220px, 70vw); height: auto; margin: 0 auto; }
.share-qr-status { margin: 0.25rem 0 0; font-size: 0.75rem; color: #8a7a6a; }
html.dark .share-qr .share-qr-status { color: #6b5f58; }

/* ── Share dialog chrome (poster preview itself is untouched) ── */
html.dark .share-glow { background: #2b251e; border-color: rgba(192,112,184,0.35); box-shadow: 0 4px 20px rgba(0,0,0,0.4); }
html.dark .share-qr { background: #fff; }
html.dark .share-inner { background: #2b251e; }
html.dark .share-section-summary { background: #3a2334; color: #e06ac8; border-color: rgba(224,106,200,0.35); }
html.dark .share-section-summary:hover { background: #4a2340; }
html.dark .share-edit > summary { color: #a3968a; }
html.dark .share-primary, html.dark .share-secondary { background: rgba(255,255,255,0.06); color: #e06ac8; }
html.dark .share-primary { background: #3a2334; }
html.dark .share-primary:hover { background: #4a2340; }
html.dark .share-secondary:hover { background: rgba(255,255,255,0.12); }
html.dark .share-panel-box { background: #332c24; border-color: #3a332b; }
html.dark .share-select { background: #332c24; color: #ede5da; }
html.dark .share-select option { background: #332c24; color: #ede5da; }
html.dark .share-swatch { border-color: #6b5f4f; }
html.dark .share-muted { color: #a3968a; }
/* The Share Text dialog's text box and link box keep their white fill in
   dark mode, so the global light-on-dark input colour left them near
   unreadable — dark ink on white here, wherever the dialog's opened from. */
html.dark .share-inner textarea, html.dark .share-inner input[type="text"] { background: #fff; color: #111; }
html.dark .share-inner textarea::placeholder { color: #78716c; }
/* The optional checkbox under the Link (share.js option — "One use auto approve"). */
.share-option-box { accent-color: #c070b8; width: 1rem; height: 1rem; }
html.dark .share-option { color: #ede5da; }
html.dark .share-option-msg.text-stone-500 { color: #a3968a; }
html.dark .share-option-msg.text-red-700 { color: #f19a9a; }
html.dark .share-toggle-btn { background: rgba(255,255,255,0.06); color: #c9bcae; border-color: #463d33; }
html.dark .share-toggle-btn.active { background: #3a2334; border-color: #e06ac8; color: #e06ac8; }
html.dark .share-accent-btn { background: #3a2334; color: #e06ac8; }
html.dark .share-pink-label { color: #e06ac8; }
html.dark [id^="bg-photo-thumb-"] { border-color: #463d33; background: #332c24; }

/* ── Add Event dialog (local-events.js, inline-styled) ── */
html.dark #le-dialog-overlay { background: rgba(237, 229, 218, 0.28) !important; }
html.dark #le-dialog-card { background: #2b251e !important; border-color: #463d33 !important; }
html.dark #le-dialog-card [style*="border:1px solid #e7e0d8"],
html.dark #le-dialog-card [style*="border-bottom:1px solid #e7e0d8"],
html.dark #le-dialog-card [style*="border-top:1px solid #e7e0d8"],
html.dark #le-dialog-card [style*="border:1px solid #d0c8c0"] { border-color: #463d33 !important; }
html.dark #le-dialog-card [style*="color:#4f463c"] { color: #ded3c5 !important; }
html.dark #le-dialog-card [style*="color:#6b5f58"] { color: #a3968a !important; }
html.dark #le-dialog-title { color: #ede5da !important; }
html.dark #le-x-btn { color: #b3a698 !important; }
html.dark #le-x-btn:hover { background: #3a2334 !important; color: #e06ac8 !important; }
html.dark #le-title-input, html.dark #le-date-input, html.dark #le-venue-search, html.dark #le-bulk-text {
    background: #211c17 !important; color: #ede5da !important;
}
html.dark #le-genre-btn { background: #211c17 !important; }
html.dark #le-genre-btn:hover { background: #332c24 !important; }
html.dark #le-genre-label { color: #9a8d80 !important; }
html.dark #le-date-cal-btn, html.dark #le-bulk-toggle, html.dark #le-bulk-back { color: #b3a698 !important; }
html.dark #le-bulk-toggle:hover, html.dark #le-bulk-back:hover { color: #e06ac8 !important; }
html.dark #le-date-error { color: #f0a0a0 !important; }
html.dark #le-dialog-card code { background: #332c24 !important; color: #ded3c5 !important; }
html.dark #le-cancel-btn { background: #332c24 !important; }
html.dark #le-cancel-btn:hover { background: #3a332a !important; }
html.dark #le-delete-btn.text-red-500 { color: #f0a0a0 !important; }
html.dark #le-delete-confirm-no:hover { background: #3a332a !important; }
html.dark #le-reset-btn:hover { background: #3a332a !important; }
html.dark #le-reset-confirm { background: #332c24 !important; }
html.dark #le-reset-confirm-yes { background: #52483d !important; }
html.dark #le-reset-confirm-yes:hover { background: #6b5f4f !important; }
html.dark #le-reset-confirm-no:hover { background: #3a332a !important; }

