/* ===================================================================
   Bechdoo — Unified App Design System
   Shared by every page except index.html (which has its own inline
   style block for its heavier hero/illustration work, but uses the same
   token family below so the whole site reads as one product).

   Rewritten from the original blue/violet "institutional-app" palette
   to match the bold yellow/black poster identity introduced on the
   homepage: thick borders, hard offset drop-shadows instead of soft
   blurs, Anton for headlines, cream page background instead of grey.
=================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Anton&family=Inter:wght@400;500;600;700;800&family=IBM+Plex+Mono:wght@400;500;600&display=swap');

:root {
    --color-primary: #0D0D0D;          /* was electric blue — now our ink */
    --color-primary-dark: #0D0D0D;     /* header bg — was navy, now ink */
    --color-primary-light: #FFD400;    /* yellow — used for hover/light accents */
    --color-primary-tint: #FFF3D6;     /* pale yellow tint — was pale blue */
    --color-violet: #FFD400;
    --gradient-primary: none;          /* flat colors now, not gradients — matches the poster aesthetic */
    --color-accent: #E11D2E;           /* red — was hot pink */
    --color-accent-dark: #B0141F;
    --color-accent-tint: #FDE3E5;
    --gradient-accent: none;
    --color-gold: #FFD400;
    --color-success: #16A34A;
    --color-success-tint: #DFF6E6;
    --color-bg: #FFF9E8;               /* cream page background — was cool grey */
    --color-surface: #FFFFFF;
    --color-text: #0D0D0D;
    --color-muted: rgba(13,13,13,0.62);
    --color-danger: #E11D2E;
    --color-danger-tint: #FDE3E5;
    --color-border: #0D0D0D;           /* bold black border — was a subtle lavender-grey */
    --color-danger-text: #7D2B22;
    --color-success-text: #0E4A2C;
    --color-pending-text: #7A5200;
    --radius: 12px;
    --radius-sm: 8px;
    --radius-lg: 16px;
    --shadow-sm: 3px 3px 0 rgba(13,13,13,1);
    --shadow: 5px 5px 0 rgba(13,13,13,1);
    --shadow-lg: 7px 7px 0 rgba(13,13,13,1);
    --shadow-accent: 4px 4px 0 rgba(13,13,13,1);
    --font: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    --font-display: 'Anton', sans-serif;
    --mono: 'IBM Plex Mono', "SF Mono", "Courier New", monospace;
}

/* ===================================================================
   DARK MODE — same approach as index.html: override the surface/text/
   border variables only, so every existing component (cards, tables,
   badges, modals) that already correctly reads from these variables
   inverts automatically, with zero changes needed to the components
   themselves. Shadows specifically switch from solid black to yellow —
   a black shadow on an already-dark card would be invisible, the same
   bug that was found and fixed on the homepage's focus ring and footer
   border for exactly this reason.
=================================================================== */
[data-theme="dark"] {
    --color-primary-tint: rgba(255,212,0,0.12);
    --color-accent-tint: rgba(225,29,46,0.18);
    --color-success-tint: rgba(22,163,74,0.18);
    --color-danger-tint: rgba(225,29,46,0.18);
    --color-bg: #0A0A0A;
    --color-surface: #1E1E1E;
    --color-text: #F3EEDD;
    --color-muted: rgba(243,238,221,0.62);
    --color-border: #FFD400;
    --color-danger-text: #FF8A80;
    --color-success-text: #6EE7A0;
    --color-pending-text: #FFC98B;
    --shadow-sm: 3px 3px 0 #FFD400;
    --shadow: 5px 5px 0 #FFD400;
    --shadow-lg: 7px 7px 0 #FFD400;
    --shadow-accent: 4px 4px 0 #FFD400;
}
body, .card, input, select, textarea, button {
    transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

body {
    margin: 0;
    font-family: var(--font);
    background: var(--color-bg);
    color: var(--color-text);
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
}

a { color: var(--color-text); text-decoration: underline; text-decoration-color: var(--color-primary-light); text-decoration-thickness: 2px; }
a:hover { color: var(--color-text); text-decoration-color: var(--color-text); }

:focus-visible {
    outline: 3px solid var(--color-primary-light);
    outline-offset: 2px;
    border-radius: 4px;
}

.container {
    max-width: 1080px;
    margin: 0 auto;
    padding: 0 20px;
}

h1, h2, h3, h4 {
    font-family: var(--font-display);
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 0.01em;
    line-height: 1.08;
    margin: 0 0 0.45em;
}
.mono { font-family: var(--mono); }

/* ---------------- Header ---------------- */
.site-header {
    background: var(--color-primary-dark);
    border-bottom: 4px solid var(--color-gold);
    position: sticky;
    top: 0;
    z-index: 50;
}
.site-header .container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 64px;
    flex-wrap: wrap;
    gap: 8px;
}
.logo {
    font-family: var(--font-display);
    text-transform: none;
    font-weight: 400;
    font-size: 1.25rem;
    color: #fff;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 10px;
}
.logo-mark {
    width: 32px; height: 32px; background: var(--color-gold); border-radius: 9px;
    display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.logo-mark svg { width: 18px; height: 18px; }
.nav-links { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.nav-links a {
    color: rgba(255,255,255,0.82); font-weight: 700; font-size: 0.9rem;
    text-decoration: none; padding: 8px 14px; border-radius: 999px;
    transition: background 0.15s ease, color 0.15s ease;
}
.nav-links a:hover { color: #fff; background: rgba(255,255,255,0.1); text-decoration: none; }

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 12px 24px;
    border-radius: 8px;
    border: 3px solid var(--color-border);
    font-family: var(--font);
    font-weight: 800;
    font-size: 0.93rem;
    cursor: pointer;
    transition: transform 0.15s cubic-bezier(.2,.9,.3,1.2), box-shadow 0.15s ease, background 0.15s ease;
    line-height: 1.2;
    position: relative;
    overflow: hidden;
    isolation: isolate;
}
.btn:active { transform: translate(2px, 2px) !important; box-shadow: none !important; }
.btn-primary { background: var(--color-gold); color: var(--color-primary); box-shadow: var(--shadow); }
.btn-primary:hover { transform: translate(-2px, -2px); box-shadow: var(--shadow-lg); text-decoration: none; }
.btn-accent { background: var(--color-primary); color: var(--color-gold); border-color: var(--color-primary); box-shadow: 4px 4px 0 var(--color-gold); }
.btn-accent:hover { transform: translate(-2px, -2px); text-decoration: none; box-shadow: 6px 6px 0 var(--color-gold); }
.btn-outline { background: transparent; border: 3px solid var(--color-border); color: var(--color-text); }
.btn-outline:hover { background: var(--color-primary-tint); text-decoration: none; transform: translate(-1px, -1px); }
.btn-danger { background: var(--color-danger); color: #fff; border-color: var(--color-text); }
.btn-danger:hover { background: #B0141F; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; box-shadow: none; }
.btn-sm { padding: 8px 16px; font-size: 0.82rem; }

/* Ripple effect on click (JS adds/removes the span — see ripple.js) */
.btn-ripple {
    position: absolute;
    border-radius: 50%;
    background: rgba(255,255,255,0.55);
    transform: scale(0);
    animation: ripple-expand 0.55s ease-out;
    pointer-events: none;
    z-index: 0;
}
@keyframes ripple-expand { to { transform: scale(2.8); opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
    .btn-ripple { display: none; }
}

/* ---------------- Hero (legacy pages still using .hero) ---------------- */
.hero {
    background: var(--color-primary);
    color: var(--color-gold);
    padding: 64px 0;
    text-align: center;
}
.hero h1 { font-size: 2.4rem; margin-bottom: 12px; color: #fff; }
.hero p { font-size: 1.1rem; opacity: 0.85; max-width: 640px; margin: 0 auto 28px; color: rgba(255,255,255,0.85); }

/* ---------------- Cards ---------------- */
.card {
    background: var(--color-surface);
    border: 3px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: 24px;
    transition: box-shadow 0.2s ease, transform 0.2s cubic-bezier(.2,.8,.2,1);
}
.grid {
    display: grid;
    gap: 18px;
}
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
/* Grid items default to min-width:auto, which lets content with a large
   intrinsic size (e.g. a QR code image, a long unbreakable string) force
   the track wider than its fair share — overflowing the grid entirely.
   This is the standard fix: let items actually shrink to their track. */
.grid > * { min-width: 0; }

/* Listing discovery grid — Browse, My Listings, Saved Listings. Always
   2 columns, even on mobile: a single full-width card per row is the
   "only one at a time" problem — a scannable browse grid needs to show
   several items in one glance, the same way every real marketplace app
   does it, not scroll like a feed of one. Card content is deliberately
   minimal (image, price, title, one line of context) since a half-width
   mobile card has no room for a paragraph — the detail page is where
   the rest lives. */
.listing-grid {
    display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; transition: opacity 0.15s ease;
}
.listings-grid-loading { opacity: 0.4; pointer-events: none; }
@media (min-width: 641px) {
    .listing-grid { grid-template-columns: repeat(3, 1fr); gap: 16px; }
}
@media (min-width: 1000px) {
    .listing-grid { grid-template-columns: repeat(4, 1fr); }
}
.listing-card {
    padding: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}
.listing-card:active { transform: translate(1px, 1px) !important; box-shadow: none !important; }
.listing-card-image-wrap {
    position: relative;
    aspect-ratio: 4 / 3;
    background: var(--color-bg);
    border-bottom: 2px solid var(--color-border);
    overflow: hidden;
}
.listing-card-image-wrap img {
    width: 100%; height: 100%; object-fit: cover;
    transition: transform 0.3s ease;
}
.listing-card:hover .listing-card-image-wrap img { transform: scale(1.06); }
.listing-card-placeholder {
    width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;
    background: repeating-linear-gradient(135deg, var(--color-primary-tint), var(--color-primary-tint) 12px, var(--color-bg) 12px, var(--color-bg) 24px);
}
.listing-card-placeholder svg { width: 32px; height: 32px; color: var(--color-border); opacity: 0.35; }
.listing-card-new-badge {
    position: absolute; top: 6px; left: 6px;
    background: var(--color-gold); color: var(--color-primary);
    font-size: 0.6rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.03em;
    padding: 2px 7px; border-radius: 999px; border: 1.5px solid var(--color-border);
}
.listing-card-distance {
    position: absolute; bottom: 6px; left: 6px;
    background: rgba(13,13,13,0.78); color: #fff;
    font-size: 0.6rem; font-weight: 700;
    padding: 2px 7px; border-radius: 999px;
}
.listing-card-body { padding: 12px 13px 14px; flex: 1; display: flex; flex-direction: column; }
.listing-card-title {
    font-weight: 700; font-size: 0.86rem; line-height: 1.3; margin-bottom: 4px; color: var(--color-text);
    display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;
    order: -1;
}
.listing-card-price {
    font-family: var(--font-display, inherit); font-weight: 700; font-size: 0.92rem;
    line-height: 1.15; letter-spacing: 0.01em; display: flex; align-items: center; gap: 5px; flex-wrap: wrap;
    color: var(--color-muted); margin-bottom: 5px;
}
.listing-card-rating-inline { font-size: 0.68rem; font-weight: 600; color: var(--color-muted); }
.listing-card-location {
    font-size: 0.72rem; color: var(--color-muted); margin-top: auto; padding-top: 6px;
    display: flex; align-items: center; gap: 3px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.listing-card-verified-inline { color: var(--color-success-text); display: inline-flex; }
.listing-card-verified-inline svg { width: 11px; height: 11px; }
.listing-card-photo-count {
    position: absolute; top: 6px; left: 6px;
    background: rgba(13,13,13,0.7); color: #fff; font-size: 0.6rem; font-weight: 700;
    padding: 2px 6px; border-radius: 999px; display: flex; align-items: center; gap: 3px;
}
.listing-card-photo-count svg { width: 9px; height: 9px; }

/* Compact search bar + filter icon button, replacing what used to be a
   stack of five full-width buttons. */
.browse-toolbar {
    background: var(--color-surface); border: 3px solid var(--color-border);
    border-radius: var(--radius); box-shadow: var(--shadow-sm); padding: 16px;
}
.browse-search-row { display: flex; gap: 8px; align-items: center; }
.browse-search-input-wrap {
    flex: 1; position: relative; display: flex; align-items: center; min-width: 0;
}
.browse-search-input-wrap svg { position: absolute; left: 12px; width: 16px; height: 16px; color: var(--color-muted); pointer-events: none; }
.browse-search-input-wrap input { width: 100%; padding-left: 36px; border-radius: 999px; height: 42px; }
.browse-filter-btn {
    position: relative; width: 42px; height: 42px; flex-shrink: 0; border-radius: 50%;
    background: var(--color-primary); border: none; display: flex; align-items: center; justify-content: center;
    cursor: pointer; transition: transform 0.15s cubic-bezier(.2,.9,.3,1.2);
}
.browse-filter-btn:hover { transform: scale(1.06); }
.browse-filter-btn:active { transform: scale(0.92); }
.browse-filter-btn svg { width: 18px; height: 18px; color: #fff; }
.browse-filter-dot {
    position: absolute; top: 2px; right: 2px; width: 9px; height: 9px; border-radius: 50%;
    background: var(--color-gold); border: 1.5px solid var(--color-surface);
}
.browse-nearme-row { display: flex; align-items: center; gap: 8px; margin-top: 8px; }
.browse-nearme-chip {
    display: inline-flex; align-items: center; gap: 6px; padding: 7px 14px; border-radius: 999px;
    border: 1.5px solid var(--color-border); background: var(--color-surface); font-size: 0.8rem; font-weight: 700;
    cursor: pointer; color: var(--color-text); transition: transform 0.12s ease, box-shadow 0.12s ease, background 0.15s ease, color 0.15s ease;
}
.browse-nearme-chip:hover { transform: translate(-1px, -1px); box-shadow: 2px 2px 0 var(--color-border); }
.browse-nearme-chip:active { transform: translate(0, 0); box-shadow: none; }
.browse-nearme-chip svg { width: 14px; height: 14px; }
.browse-nearme-chip.active { background: var(--color-primary); color: #fff; border-color: var(--color-primary); }
.browse-nearme-chip.loading { opacity: 0.6; pointer-events: none; }
.browse-nearme-refresh {
    width: 32px; height: 32px; border-radius: 50%; border: 1.5px solid var(--color-border);
    background: var(--color-surface); display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.browse-nearme-refresh svg { width: 15px; height: 15px; }
.browse-nearme-refresh:active svg { transform: rotate(180deg); transition: transform 0.3s ease; }

/* Desktop category tabs — mobile already had instant one-tap category
   filtering via pills; desktop required opening a filter sheet just to
   switch category, which was strictly more friction for the same task
   on a larger screen. This closes that gap. */
.browse-category-tabs { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
.browse-category-tab {
    padding: 8px 16px; border-radius: 999px; border: 2px solid var(--color-border);
    background: var(--color-surface); color: var(--color-text); font-size: 0.82rem; font-weight: 700;
    cursor: pointer; transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.browse-category-tab:hover { transform: translate(-1px, -1px); box-shadow: 2px 2px 0 var(--color-border); }
.browse-category-tab:active { transform: translate(1px, 1px); box-shadow: none; }
.browse-category-tab.active { background: var(--color-gold); color: var(--color-primary); }

.browse-results-bar {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    margin-top: 16px; padding-bottom: 12px; border-bottom: 2px solid var(--color-border);
    font-size: 0.84rem; color: var(--color-muted); flex-wrap: wrap;
}
.browse-results-count strong { color: var(--color-text); }
.browse-sort-select {
    border: 2px solid var(--color-border); border-radius: 999px; padding: 7px 32px 7px 14px;
    font-size: 0.82rem; font-weight: 700; background: var(--color-surface); color: var(--color-text);
    cursor: pointer; appearance: none; -webkit-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230D0D0D' stroke-width='2.5'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 10px center; background-size: 14px;
    transition: box-shadow 0.15s ease;
}
.browse-sort-select:hover { box-shadow: 2px 2px 0 var(--color-border); }
[data-theme="dark"] .browse-sort-select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23FFD400' stroke-width='2.5'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}

/* Scroll-to-top — shown once there's actually somewhere to scroll back
   to, i.e. after the grid has grown past one viewport. */
.scroll-top-fab {
    position: fixed; bottom: 24px; right: 24px; z-index: 60;
    width: 46px; height: 46px; border-radius: 50%;
    background: var(--color-primary); color: var(--color-gold);
    border: 3px solid var(--color-border); box-shadow: var(--shadow-sm);
    display: flex; align-items: center; justify-content: center; cursor: pointer;
    opacity: 0; pointer-events: none; transform: translateY(10px) scale(0.9);
    transition: opacity 0.2s ease, transform 0.2s ease;
}
.scroll-top-fab.visible { opacity: 1; pointer-events: auto; transform: translateY(0) scale(1); }
.scroll-top-fab:hover { transform: translate(0, -2px) scale(1.04); }
.scroll-top-fab svg { width: 20px; height: 20px; }
@media (max-width: 767px) { .scroll-top-fab { bottom: 88px; right: 16px; width: 42px; height: 42px; } .scroll-top-fab svg { width: 18px; height: 18px; } }

/* Dynamic card badges - distance/popular use a different tint than
   the default "new" yellow so they read as distinct signals, not
   just a recolored version of the same badge. */
.listing-card-distance-badge { background: var(--color-primary); color: #fff; border-color: var(--color-primary); }
.listing-card-popular-badge { background: var(--color-danger); color: #fff; border-color: var(--color-danger); }

/* "You're all caught up" end state - a dead-end last page feels worse
   than one that acknowledges you've seen everything and offers a
   next step. */
.end-of-results-inner { text-align: center; padding: 36px 20px; color: var(--color-muted); }
.end-of-results-emoji { font-size: 1.8rem; display: block; margin-bottom: 8px; }
.end-of-results-inner p { margin: 0 0 4px; }
.end-of-results-inner p:first-of-type { font-weight: 700; color: var(--color-text); font-size: 1rem; }
.end-of-results-sub { font-size: 0.84rem; }
.end-of-results-actions { display: flex; gap: 10px; justify-content: center; margin-top: 16px; flex-wrap: wrap; }

/* Discovery rows - Just Listed / Near You / Recently Viewed. Reuses
   .card.listing-card styling from the main grid so a card looks
   identical everywhere it appears; only the container becomes a
   horizontal scroller with fixed-width children instead of a grid. */
.discovery-row { margin-bottom: 32px; }
.discovery-row-header { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 12px; gap: 8px; }
.discovery-row-title { font-family: var(--font-display); font-weight: 400; text-transform: uppercase; letter-spacing: 0.01em; font-size: 1.05rem; display: flex; align-items: center; gap: 8px; }
.discovery-row-sub { font-size: 0.78rem; color: var(--color-muted); }
.discovery-row-scroll-wrap { position: relative; }
.discovery-scroll-arrow {
    position: absolute; top: 50%; transform: translateY(-50%); z-index: 5;
    width: 36px; height: 36px; border-radius: 50%; background: var(--color-surface);
    border: 2px solid var(--color-border); box-shadow: var(--shadow-sm);
    display: flex; align-items: center; justify-content: center; cursor: pointer;
    opacity: 0.55; transition: opacity 0.15s ease, transform 0.15s ease;
    color: var(--color-text);
}
.discovery-row-scroll-wrap:hover .discovery-scroll-arrow { opacity: 1; }
.discovery-scroll-arrow:hover { transform: translateY(-50%) scale(1.08); }
.discovery-scroll-arrow:active { transform: translateY(-50%) scale(0.94); }
.discovery-scroll-arrow svg { width: 16px; height: 16px; }
.discovery-scroll-arrow-left { left: -16px; }
.discovery-scroll-arrow-right { right: -16px; }
@media (max-width: 1023px) { .discovery-scroll-arrow { display: none; } }
.discovery-row-scroll { display: flex; gap: 12px; overflow-x: auto; padding-bottom: 6px; scroll-snap-type: x proximity; scroll-behavior: smooth; }
.discovery-row-scroll::-webkit-scrollbar { height: 5px; }
.discovery-row-scroll::-webkit-scrollbar-thumb { background: var(--color-border); border-radius: 999px; }
.discovery-row-scroll .listing-card { flex: 0 0 220px; scroll-snap-align: start; }
@media (max-width: 767px) {
    .discovery-row-scroll .listing-card { flex-basis: 168px; }
    .discovery-row-title { font-size: 0.92rem; }
}

/* Visual category cards - replaces plain text pills with icon+count
   tiles so category choice feels like exploring, not filtering. */
.category-visual-row { display: flex; gap: 10px; overflow-x: auto; padding-bottom: 4px; margin-bottom: 4px; }
.category-visual-row::-webkit-scrollbar { display: none; }
.category-visual-card {
    flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
    padding: 14px 16px; border-radius: var(--radius-sm); border: 2px solid var(--color-border);
    background: var(--color-surface); cursor: pointer; min-width: 108px; transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.category-visual-card:hover { transform: translate(-2px, -2px); box-shadow: 3px 3px 0 var(--color-border); }
.category-visual-card.active { background: var(--color-gold); }
.category-visual-card-icon { font-size: 1.3rem; }
.category-visual-card-label { font-weight: 700; font-size: 0.86rem; }
.category-visual-card-count { font-size: 0.72rem; color: var(--color-muted); }
.category-visual-card.active .category-visual-card-count { color: rgba(13,13,13,0.65); }


/* Listing detail hero — full-bleed image with a rounded white sheet
   rising up over its bottom edge, native-app pattern rather than a
   plain stacked-card layout. */
.listing-hero-wrap {
    position: relative; width: 100%; aspect-ratio: 4 / 3; max-height: 420px;
    background: var(--color-primary); overflow: hidden;
}
.lightbox-hero-scroller {
    width: 100%; height: 100%; display: flex; overflow-x: auto; overflow-y: hidden;
    scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch; scrollbar-width: none;
}
.lightbox-hero-scroller::-webkit-scrollbar { display: none; }
.lightbox-hero-slide { width: 100%; height: 100%; flex-shrink: 0; scroll-snap-align: start; cursor: pointer; position: relative; }
.lightbox-hero-slide img { width: 100%; height: 100%; object-fit: cover; display: block; }
.lightbox-hero-placeholder {
    width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;
    background: var(--color-primary-tint); color: var(--color-border); opacity: 0.4;
}
.lightbox-hero-placeholder svg { width: 64px; height: 64px; }
.lightbox-hero-count {
    position: absolute; top: 14px; right: 14px; background: rgba(13,13,13,0.7); color: #fff;
    font-size: 0.75rem; font-weight: 700; padding: 4px 10px; border-radius: 999px; pointer-events: none;
}
.lightbox-hero-dots {
    position: absolute; bottom: 14px; left: 50%; transform: translateX(-50%);
    display: flex; gap: 6px;
}
.lightbox-hero-dot {
    width: 7px; height: 7px; border-radius: 50%; background: rgba(255,255,255,0.5);
    border: 1px solid rgba(0,0,0,0.15); transition: all 0.15s ease; cursor: pointer;
}
.lightbox-hero-dot.active { background: #fff; width: 18px; border-radius: 4px; }

/* Loading skeleton - shown until the image actually loads, so the
   gallery never shows a blank flash before the photo appears. */
.lightbox-hero-skeleton {
    position: absolute; inset: 0; background: linear-gradient(90deg, var(--color-bg) 25%, var(--color-primary-tint) 50%, var(--color-bg) 75%);
    background-size: 200% 100%; animation: hero-shimmer 1.4s ease-in-out infinite;
}
@keyframes hero-shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .lightbox-hero-skeleton { animation: none; background: var(--color-bg); } }

/* Broken image fallback - a graceful placeholder instead of the
   browser's default broken-image icon. */
.lightbox-hero-broken {
    width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 8px; background: var(--color-bg); color: var(--color-muted);
}
.lightbox-hero-broken svg { width: 40px; height: 40px; }
.lightbox-hero-broken span { font-size: 0.78rem; font-weight: 600; }

/* "Listing unavailable" state - a dead end here is a worse outcome
   than one that offers a next step. */
.listing-unavailable { text-align: center; padding: 48px 20px; }
.listing-unavailable-emoji { font-size: 2rem; display: block; margin-bottom: 10px; }
.listing-unavailable h3 { margin-bottom: 6px; }
.listing-unavailable p { color: var(--color-muted); font-size: 0.9rem; margin-bottom: 4px; }
.listing-unavailable-sub { margin-bottom: 18px; }
.listing-sheet {
    position: relative; margin-top: -20px; background: var(--color-surface);
    border-radius: 20px 20px 0 0; border: 3px solid var(--color-border); border-bottom: none;
    padding: 20px; z-index: 2;
}
.detail-spec-card {
    background: var(--color-bg); border: 2px solid var(--color-border); border-radius: var(--radius-sm);
    padding: 14px; margin-bottom: 10px;
}
.detail-spec-card h4 {
    font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.03em; color: var(--color-muted);
    margin-bottom: 8px;
}
.detail-spec-card .listing-card-specs { grid-template-columns: 1fr 1fr; gap: 8px 12px; }
@media (min-width: 641px) {
    /* The rising-sheet overlap is a mobile pattern; on desktop, where the
       hero isn't full-viewport-width anyway, a flat card reads cleaner. */
    .listing-hero-wrap { border-radius: var(--radius); max-height: 380px; }
    .listing-sheet { margin-top: 20px; border-radius: var(--radius); border-bottom: 3px solid var(--color-border); }
}

/* ===================================================================
   DESKTOP TWO-COLUMN LAYOUT — previously the whole page was capped at
   640px and centered even on a 1920px monitor, wasting most of the
   screen regardless of any other polish. Below 1024px this is inert
   (both columns just stack full-width, identical to before); at
   1024px+ the gallery becomes a sticky left column and the details
   become a scrolling right column, the standard product-page pattern.
=================================================================== */
.listing-main-inner { max-width: 1080px; }
.listing-desktop-grid { max-width: 640px; margin: 0 auto; }
.listing-gallery-col, .listing-details-col { width: 100%; }
@media (min-width: 1024px) {
    .listing-desktop-grid {
        max-width: 1080px; margin: 24px auto 0; padding: 0 20px; display: grid;
        grid-template-columns: minmax(0, 1.15fr) minmax(340px, 0.85fr); gap: 32px; align-items: start;
    }
    .listing-gallery-col { position: sticky; top: 24px; }
    .listing-hero-wrap { border-radius: var(--radius); max-height: 560px; aspect-ratio: 4/3.2; }
    .listing-sheet { margin-top: 0; }
}

.listing-card-status-badges { position: absolute; top: 6px; right: 6px; display: flex; flex-direction: column; gap: 4px; align-items: flex-end; }

/* Breadcrumb - quick orientation + a path back to the category
   without relying on the browser back button. */
.listing-breadcrumb { display: flex; align-items: center; gap: 6px; font-size: 0.8rem; padding: 10px 4px 0; color: var(--color-muted); }
.listing-breadcrumb a { color: var(--color-muted); text-decoration: none; }
.listing-breadcrumb a:hover { color: var(--color-text); text-decoration: underline; }
.listing-breadcrumb a:last-child { color: var(--color-text); font-weight: 700; }
.listing-breadcrumb-sep { opacity: 0.5; }

/* Entrance animation - the details sheet settles into place rather
   than popping in instantly, giving the page a moment of life on
   load without being distracting on repeat visits. */
@media (prefers-reduced-motion: no-preference) {
    .listing-sheet { animation: listing-sheet-in 0.35s cubic-bezier(.2,.8,.2,1); }
}
@keyframes listing-sheet-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }

/* Interactive spec cards - a static icon grid felt inert; a subtle
   lift on hover signals these are worth reading, not just decoration. */
.detail-spec-card { transition: transform 0.15s ease, box-shadow 0.15s ease; }
.spec-row { border-radius: 8px; padding: 4px; margin: -4px; transition: background 0.15s ease; }
.spec-row:hover { background: var(--color-primary-tint); }
.spec-row:hover .spec-icon-chip { transform: scale(1.08); }
.spec-icon-chip { transition: transform 0.15s ease; }

/* Desktop image zoom-on-hover - a static hero photo on a wide screen
   with nothing else nearby to hover felt flat; a slow, subtle zoom
   signals the image itself is interactive (click to see it larger).
   Mobile keeps the swipe gesture as its only interaction, since hover
   isn't a touch concept. */
@media (min-width: 1024px) {
    .lightbox-hero-slide { overflow: hidden; }
    .lightbox-hero-slide img { transition: transform 0.5s ease; cursor: zoom-in; }
    .lightbox-hero-slide:hover img { transform: scale(1.06); }
}

/* Desktop thumbnail strip - mobile keeps the dots+swipe pattern since
   a thumbnail row would be redundant clutter on a narrow screen, but
   the two-column desktop layout has real room for one below the
   sticky hero. */
.lightbox-thumb-strip { display: none; }
@media (min-width: 1024px) {
    .lightbox-thumb-strip { display: flex; gap: 8px; margin-top: 10px; overflow-x: auto; padding-bottom: 2px; }
    .lightbox-thumb-strip-item {
        width: 64px; height: 64px; object-fit: cover; border-radius: 8px; cursor: pointer; flex-shrink: 0;
        border: 2px solid transparent; opacity: 0.6; transition: opacity 0.15s ease, border-color 0.15s ease;
    }
    .lightbox-thumb-strip-item:hover { opacity: 0.9; }
    .lightbox-thumb-strip-item.active { opacity: 1; border-color: var(--color-primary); }
}

/* Read more/less - long descriptions previously always dumped in
   full; now clamped to 4 lines with a toggle, only shown when the
   text actually overflows. */
.description-clamped {
    display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
}
.description-expanded { display: block; }
.description-toggle-btn {
    background: none; border: none; color: var(--color-primary); font-weight: 700; font-size: 0.85rem;
    padding: 4px 0; cursor: pointer; margin-top: 2px;
}
.description-toggle-btn:hover { text-decoration: underline; }

/* Save button bounce - reuses the same save-pop keyframe defined
   for browse.html's cards, applied to this page's own save controls. */
.save-btn.just-saved, .detail-float-btn.just-saved svg { animation: save-pop 0.4s cubic-bezier(.17,.89,.32,1.49); }
.listing-card-status-badge {
    background: rgba(13,13,13,0.82); color: #fff; font-size: 0.6rem; font-weight: 700;
    padding: 2px 7px; border-radius: 999px; white-space: nowrap;
}
.listing-card-save-btn {
    position: absolute; top: 6px; right: 6px; width: 26px; height: 26px; border-radius: 50%;
    background: rgba(255,255,255,0.92); border: none; display: flex; align-items: center; justify-content: center;
    cursor: pointer; box-shadow: 0 1px 4px rgba(0,0,0,0.25); z-index: 2;
}
.listing-card-save-btn svg { width: 14px; height: 14px; color: var(--color-primary); transition: transform 0.15s ease; }
.listing-card-save-btn.saved svg { fill: var(--color-danger); color: var(--color-danger); }
.listing-card-save-btn:active svg { transform: scale(1.3); }
.listing-card-save-btn.just-saved svg { animation: save-pop 0.4s cubic-bezier(.17,.89,.32,1.49); }
@keyframes save-pop { 0% { transform: scale(1); } 40% { transform: scale(1.5); } 100% { transform: scale(1); } }

/* Sticky mobile action bar on listing detail — the primary path to
   contacting the seller stays reachable regardless of scroll position.
   Desktop has enough screen real estate that the in-flow contact box is
   sufficient; this is a mobile-specific pattern. */
.sticky-cta-bar {
    display: none;
}
@media (max-width: 640px) {
    .sticky-cta-bar {
        display: flex; align-items: center; gap: 10px; position: fixed; bottom: 0; left: 0; right: 0;
        background: var(--color-surface); border-top: 3px solid var(--color-border);
        padding: 10px 16px calc(10px + env(safe-area-inset-bottom, 0px));
        z-index: 100; box-shadow: 0 -4px 16px rgba(0,0,0,0.08);
    }
    .sticky-cta-price-zone { flex: 1; min-width: 0; }
    .sticky-cta-price { font-family: var(--font-display, inherit); font-weight: 800; font-size: 1.2rem; line-height: 1.1; }
    .sticky-cta-price-label { font-size: 0.7rem; color: var(--color-muted); }
    .sticky-cta-main-btn { flex: 0 0 auto; padding-left: 20px; padding-right: 20px; }
    .sticky-cta-bar .sticky-cta-secondary {
        flex: 0 0 auto; width: 46px; padding: 0; display: flex; align-items: center; justify-content: center;
    }
    /* Push page content clear of the fixed bar so nothing at the bottom
       of the listing is permanently hidden behind it. The has-sticky-cta
       class is added by JS when the bar is actually created, rather than
       relying on :has() which isn't universally supported yet. */
    body.has-sticky-cta { padding-bottom: 76px; }
}

/* Loading skeletons — shown while the grid's real data is still in
   flight, so the page never sits blank during a fetch. */
.skeleton-shimmer {
    background: linear-gradient(90deg, var(--color-bg) 25%, var(--color-primary-tint) 50%, var(--color-bg) 75%);
    background-size: 200% 100%;
    animation: skeleton-shimmer-move 1.4s ease infinite;
}
.skeleton-line {
    height: 12px; border-radius: 4px; margin-bottom: 10px;
    background: linear-gradient(90deg, var(--color-bg) 25%, var(--color-primary-tint) 50%, var(--color-bg) 75%);
    background-size: 200% 100%;
    animation: skeleton-shimmer-move 1.4s ease infinite;
}
@keyframes skeleton-shimmer-move {
    0% { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
    .skeleton-shimmer, .skeleton-line { animation: none; background: var(--color-bg); }
}

/* Chat bubbles — shared across every message thread context (buyer
   post-unlock, seller inbox, buyer sent-interests) so a conversation
   actually reads as a conversation, not a list of prefixed lines. */
.chat-scroll {
    display: flex; flex-direction: column; gap: 10px;
    max-height: 280px; overflow-y: auto; padding: 4px 4px 10px;
}
.chat-row { display: flex; min-width: 0; }
.chat-row.mine { justify-content: flex-end; }
.chat-row.theirs { justify-content: flex-start; }
.chat-bubble {
    max-width: min(75vw, 480px); width: fit-content; padding: 9px 13px; border-radius: 16px; font-size: 0.88rem; line-height: 1.4;
    word-wrap: break-word; overflow-wrap: anywhere;
}
.chat-row.mine .chat-bubble {
    background: var(--color-primary); color: #fff; border-bottom-right-radius: 4px;
}
.chat-row.theirs .chat-bubble {
    background: var(--color-bg); color: var(--color-text); border: 2px solid var(--color-border);
    border-bottom-left-radius: 4px;
}
.chat-bubble-location { padding: 0; overflow: hidden; background: transparent !important; border: none !important; max-width: 220px; }
.chat-location-card { display: block; text-decoration: none; color: inherit; border: 2px solid var(--color-border); border-radius: 12px; overflow: hidden; background: var(--color-surface); }
.chat-location-card img { width: 100%; height: 130px; object-fit: cover; display: block; background: var(--color-bg); }
.chat-location-label { font-size: 0.74rem; font-weight: 700; padding: 8px 10px; color: var(--color-text); }
.chat-location-fallback { padding: 24px 10px; text-align: center; }
.chat-location-fallback::before { content: '📍'; font-size: 1.8rem; display: block; margin-bottom: 4px; }
.chat-bubble-attachment { padding: 4px !important; background: transparent !important; border: none !important; max-width: 240px; }
.chat-attachment-image-link { display: block; }
.chat-attachment-image-link img { width: 100%; max-height: 260px; object-fit: cover; border-radius: 12px; border: 2px solid var(--color-border); display: block; }
.chat-attachment-video { width: 100%; max-height: 260px; border-radius: 12px; border: 2px solid var(--color-border); display: block; background: #000; }
.chat-attachment-doc {
    display: flex; align-items: center; gap: 10px; padding: 12px; border-radius: 12px;
    border: 2px solid var(--color-border); background: var(--color-surface); text-decoration: none; color: inherit;
}
.chat-attachment-doc svg { width: 26px; height: 26px; color: var(--color-primary); flex-shrink: 0; }
.chat-attachment-doc span { font-size: 0.82rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-attachment-caption { font-size: 0.82rem; padding: 6px 4px 2px; }
.chat-timestamp {
    font-size: 0.68rem; color: var(--color-muted); margin-top: 3px; padding: 0 4px;
}
.chat-row.mine .chat-timestamp { text-align: right; }
.chat-date-divider {
    text-align: center; font-size: 0.72rem; color: var(--color-muted); font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.03em; margin: 6px 0;
}
.chat-empty { text-align: center; color: var(--color-muted); font-size: 0.85rem; padding: 24px 12px; }
.chat-input-row {
    display: flex; gap: 8px; padding-top: 10px; border-top: 2px solid var(--color-border);
}
.chat-input-row input {
    flex: 1; border-radius: 999px; padding: 10px 16px;
}
.chat-send-btn {
    width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0;
    display: flex; align-items: center; justify-content: center; padding: 0;
}

@media (max-width: 900px) {
    .grid-3 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
    .grid-3, .grid-2 { grid-template-columns: 1fr; }
    .container { padding: 0 16px; }
    .site-header .container { height: auto; padding-top: 10px; padding-bottom: 10px; }
    .nav-links { gap: 6px; font-size: 0.88rem; width: 100%; justify-content: space-between; }
}

.category-card {
    text-align: center;
    padding: 26px 16px;
    cursor: pointer;
}
.category-card:hover { box-shadow: var(--shadow); transform: translate(-3px, -3px); }
.category-card .emoji { font-size: 2.2rem; margin-bottom: 10px; }

/* ---------------- Forms ---------------- */
.form-group { margin-bottom: 18px; }
label { display: block; font-weight: 700; margin-bottom: 6px; font-size: 0.86rem; color: var(--color-text); text-transform: uppercase; letter-spacing: 0.02em; }
input, select, textarea {
    width: 100%;
    padding: 11px 14px;
    border: 2.5px solid var(--color-border);
    border-radius: var(--radius-sm);
    font-size: 0.94rem;
    font-family: inherit;
    background: #fff;
    color: var(--color-text);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--color-text);
    box-shadow: 0 0 0 3px var(--color-primary-tint);
}
input:disabled { background: var(--color-bg); color: var(--color-muted); }
.form-hint { font-size: 0.8rem; color: var(--color-muted); margin-top: 5px; }
.form-hint a { font-weight: 700; }
.form-error { font-size: 0.8rem; color: var(--color-danger); margin-top: 5px; font-weight: 600; }

.auth-page {
    max-width: 420px;
    margin: 48px auto;
}
.auth-page h2 { margin-bottom: 6px; }
.auth-page .subtitle { color: var(--color-muted); margin-bottom: 24px; text-transform: none; font-family: var(--font); }

/* ---------------- Alerts / toasts ---------------- */
.alert {
    padding: 13px 16px;
    border-radius: var(--radius-sm);
    font-size: 0.9rem;
    margin-bottom: 16px;
    display: flex;
    align-items: flex-start;
    gap: 10px;
    border: 2px solid var(--color-border);
    animation: alert-in 0.35s cubic-bezier(.2,1.3,.4,1) both;
}
@keyframes alert-in { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: translateY(0); } }
.alert-error { background: var(--color-danger-tint); color: var(--color-danger-text); }
.alert-success { background: var(--color-success-tint); color: var(--color-success-text); }
.alert-info { background: var(--color-primary-tint); color: var(--color-text); }

/* Floating toast variant (JS adds .toast to position it) */
.alert.toast {
    position: fixed;
    top: 20px;
    right: 20px;
    z-index: 500;
    min-width: 260px;
    max-width: 380px;
    box-shadow: var(--shadow-lg);
}
@media (max-width: 640px) {
    .alert.toast { left: 16px; right: 16px; top: 12px; max-width: none; }
}

/* ---------------- Mobile pass: Browse / Listing / Dashboard ----------------
   These three pages share most of their classes, so one consolidated pass
   here fixes all three at once rather than patching each page separately. */
@media (max-width: 640px) {
    /* Filter/search bars (browse.html) and any similar flex row of
       input+select+button — stack vertically instead of wrapping into an
       awkward half-width second line. */
    .filters-row { flex-direction: column; align-items: stretch !important; }
    .filters-row input, .filters-row select, .filters-row button { width: 100%; }

    /* Button groups (listing actions on dashboard, card action rows) —
       full-width stacked buttons are far easier to tap accurately than a
       row of small side-by-side ones. */
    .listing-action { flex-wrap: wrap; }

    /* Every button gets a real touch target on mobile, even the ones
       marked btn-sm for desktop density. */
    .btn, button { min-height: 44px; }
    .btn-sm { min-height: 38px; padding-top: 8px; padding-bottom: 8px; }

    /* The account-menu dropdown is positioned relative to its trigger
       via `right: 0`, which is safe on desktop but can push part of a
       ~200px-wide menu off a narrow viewport if the trigger itself sits
       near the edge — anchor to the viewport edge instead on mobile. */
    .an-dropdown { position: fixed !important; top: 64px !important; right: 12px !important; left: 12px !important; width: auto !important; min-width: 0 !important; }

    /* Cards lose some padding on mobile so content has more room without
       needing a wider viewport. */
    .card { padding: 16px; }
    .listing-card { padding: 0; }

    /* Chat gets more vertical room on mobile, where there's no
       side-by-side layout competing for space. */
    .chat-scroll { max-height: 340px; }
    .chat-bubble { max-width: min(85vw, 400px); }

    /* Notification dropdown, same edge-anchoring concern as the account
       menu. */
    #notif-dropdown { position: fixed !important; top: 64px !important; left: 12px; right: 12px !important; width: auto !important; }

    /* Dashboard's stacked sections get tighter spacing between them so
       the long scroll doesn't feel even longer than it has to. */
    main h3 { margin-top: 28px; }
}

/* ---------------- Badges ---------------- */
.badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 11px;
    border-radius: 999px;
    font-size: 0.74rem;
    font-weight: 700;
    letter-spacing: 0.01em;
}
.badge-verified { background: var(--color-success-tint); color: var(--color-success-text); }
.badge-pending { background: var(--color-primary-tint); color: var(--color-pending-text); }
.badge-locked { background: var(--color-danger-tint); color: var(--color-danger-text); }

/* Trust badge for a document-reviewed listing (not an identity claim —
   see the honesty-note pattern established on the homepage) */
.trust-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--color-success-tint);
    color: var(--color-success-text);
    padding: 5px 12px;
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: 700;
}
.trust-badge svg { width: 13px; height: 13px; flex-shrink: 0; }

/* ---------------- Plans ---------------- */
.plan-card {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.plan-price { font-family: var(--font-display); font-size: 1.6rem; font-weight: 400; color: var(--color-text); }
.plan-price small { font-family: var(--font); font-size: 0.85rem; font-weight: 500; color: var(--color-muted); text-transform: none; }

/* ---------------- Scan / listing detail ---------------- */
.qr-listing-detail img.hero-img { width: 100%; border-radius: var(--radius); margin-bottom: 16px; border: 3px solid var(--color-border); }
.contact-box {
    background: var(--color-success-tint);
    border: 2.5px dashed var(--color-success);
    border-radius: var(--radius);
    padding: 20px;
    text-align: center;
    margin-top: 20px;
}
.contact-box .phone-number { font-family: var(--font-mono); font-size: 1.4rem; font-weight: 800; color: var(--color-text); letter-spacing: 1px; }

/* ---------------- Tables (admin) — responsive scroll wrapper ---------------- */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table { width: 100%; border-collapse: collapse; min-width: 560px; }
th, td { text-align: left; padding: 11px 12px; border-bottom: 2px solid var(--color-border); font-size: 0.88rem; }
th { color: var(--color-muted); font-weight: 700; font-size: 0.76rem; text-transform: uppercase; letter-spacing: 0.03em; font-family: var(--mono); }
tbody tr { transition: background 0.1s ease; }
tbody tr:hover { background: var(--color-primary-tint); }

/* ---------------- Lifecycle stepper (listing status, visual not text-only) ---------------- */
.lifecycle {
    display: flex;
    align-items: center;
    margin: 10px 0 4px;
}
.lifecycle-step {
    flex: 1;
    text-align: center;
    position: relative;
    font-size: 0.68rem;
    color: var(--color-muted);
    font-weight: 700;
    font-family: var(--mono);
    text-transform: uppercase;
}
.lifecycle-step .dot {
    width: 12px; height: 12px; border-radius: 50%;
    background: var(--color-border);
    margin: 0 auto 6px;
    position: relative; z-index: 1;
    border: 2px solid var(--color-surface);
}
.lifecycle-step::before {
    content: '';
    position: absolute;
    top: 5px; left: -50%; width: 100%; height: 2px;
    background: var(--color-border);
    z-index: 0;
}
.lifecycle-step:first-child::before { display: none; }
.lifecycle-step.done .dot { background: var(--color-success); }
.lifecycle-step.done::before { background: var(--color-success); }
.lifecycle-step.current .dot { background: var(--color-gold); box-shadow: 0 0 0 4px var(--color-primary-tint); }
.lifecycle-step.rejected .dot { background: var(--color-danger); }

/* ---------------- Empty states ---------------- */
.empty-state {
    text-align: center;
    padding: 48px 20px;
    color: var(--color-muted);
}
.empty-state svg { width: 56px; height: 56px; margin-bottom: 14px; color: var(--color-border); opacity: 0.3; }
.empty-state p { margin: 0 0 14px; }

/* ---------------- Skeleton loaders ---------------- */
.skeleton {
    background: linear-gradient(90deg, var(--color-border) 25%, #3A3A3A 37%, var(--color-border) 63%);
    background-size: 400% 100%;
    animation: skeleton-wave 1.4s ease infinite;
    border-radius: var(--radius-sm);
    opacity: 0.15;
}
@keyframes skeleton-wave { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

/* ---------------- Modal (used to replace prompt()-based flows) ---------------- */
.modal-overlay {
    position: fixed; inset: 0;
    background: rgba(13,13,13,0.65);
    display: flex; align-items: center; justify-content: center;
    z-index: 1100;
    padding: 20px;
    animation: modal-fade-in 0.15s ease both;
}
@keyframes modal-fade-in { from { opacity: 0; } to { opacity: 1; } }
.modal-box {
    background: var(--color-surface);
    border: 3px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    max-width: 480px;
    width: 100%;
    max-height: 85vh;
    overflow-y: auto;
    padding: 26px;
    animation: modal-pop-in 0.4s cubic-bezier(.34,1.56,.64,1) both;
}
@keyframes modal-pop-in { 0% { opacity: 0; transform: scale(0.9) translateY(10px); } 60% { transform: scale(1.02) translateY(-2px); } 100% { opacity: 1; transform: scale(1) translateY(0); } }
.modal-box h3 { margin-bottom: 4px; }
.modal-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 20px; }

/* ---------------- Footer ---------------- */
footer {
    text-align: center;
    padding: 32px 0;
    color: var(--color-muted);
    font-size: 0.85rem;
    font-family: var(--mono);
}

.spinner {
    width: 18px; height: 18px;
    border: 2.5px solid currentColor;
    border-right-color: transparent;
    opacity: 0.9;
    border-radius: 50%;
    display: inline-block;
    animation: spin 0.6s linear infinite;
    vertical-align: middle;
}
@keyframes spin { to { transform: rotate(360deg); } }

.hidden { display: none !important; }

/* Bell gives a little shake when a new notification actually arrives —
   not on every poll, only when the unread count goes up (see dashboard.html) */
.notif-wiggle { animation: bell-wiggle 0.5s ease; }
@keyframes bell-wiggle {
    0%, 100% { transform: rotate(0); }
    20% { transform: rotate(-15deg); }
    40% { transform: rotate(12deg); }
    60% { transform: rotate(-8deg); }
    80% { transform: rotate(4deg); }
}
@media (prefers-reduced-motion: reduce) {
    .notif-wiggle { animation: none; }
}

/* ---------------- Reward-moment micro-interactions ---------------- */
.celebrate-pulse {
    position: absolute;
    top: 50%; left: 50%;
    width: 64px; height: 64px;
    margin: -32px 0 0 -32px;
    border-radius: 50%;
    background: var(--color-success);
    color: #fff;
    display: flex; align-items: center; justify-content: center;
    z-index: 50;
    animation: celebrate-pop 0.9s cubic-bezier(.2,1.4,.4,1) both;
    pointer-events: none;
}
.celebrate-pulse svg { width: 30px; height: 30px; }
@keyframes celebrate-pop {
    0% { transform: scale(0); opacity: 0; }
    40% { transform: scale(1.15); opacity: 1; }
    70% { transform: scale(1); opacity: 1; }
    100% { transform: scale(1); opacity: 0; }
}

/* Buttons already get their active/hover treatment above — cards get a
   livelier lift on hover here, matching the poster aesthetic. */
.card { will-change: transform; }
.card:hover { box-shadow: var(--shadow); transform: translate(-3px, -3px); }

/* Animated number count-up target (JS toggles the value; CSS just gives
   it a nice settling motion when it changes) */
.count-up {
    display: inline-block;
    transition: transform 0.25s cubic-bezier(.3,1.5,.4,1);
}
.count-up.bump { transform: scale(1.18); }

/* "Best value" plan badge — awarded honestly by comparing real per-unit
   cost across plans (see the JS that applies this class), never fixed. */
.best-value-badge {
    position: absolute;
    top: -11px;
    right: 16px;
    background: var(--color-gold);
    color: var(--color-primary);
    font-size: 0.68rem;
    font-weight: 800;
    padding: 4px 10px;
    border-radius: 999px;
    letter-spacing: 0.02em;
    border: 2px solid var(--color-border);
}
.plan-card { position: relative; }

/* Scroll-reveal (JS adds .in-view once an element enters the viewport) */
.reveal-on-scroll {
    opacity: 0;
    transform: translateY(18px);
    transition: opacity 0.5s ease, transform 0.5s cubic-bezier(.2,.8,.2,1);
}
.reveal-on-scroll.in-view { opacity: 1; transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
    .reveal-on-scroll { opacity: 1; transform: none; transition: none; }
}