/* ═══════════════════════════════════════════
   TapShare — Mobile-First Dark Theme
   ═══════════════════════════════════════════ */

:root {
    --bg-primary: #0d0d0d;
    --bg-secondary: #1a1a1a;
    --bg-card: #222222;
    --text-primary: #f0f0f0;
    --text-secondary: #999999;
    --accent-red: #c0392b;
    --accent-red-hover: #e74c3c;
    --accent-leather: #8b4513;
    --border-color: #333333;
    --success: #27ae60;
    --error: #e74c3c;
    --radius: 12px;
    --shadow: 0 4px 24px rgba(0, 0, 0, 0.5);
}

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

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    background: var(--bg-primary);
    color: var(--text-primary);
    min-height: 100dvh;
    overflow-x: hidden;
    -webkit-tap-highlight-color: transparent;
}

.container {
    max-width: 480px;
    margin: 0 auto;
    padding: 16px;
    min-height: 100dvh;
}

.hidden { display: none !important; }

/* ── Buttons ──────────────────────────────── */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 14px 24px;
    border: none;
    border-radius: var(--radius);
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s ease;
    text-decoration: none;
    touch-action: manipulation;
}

.btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.btn-primary {
    background: var(--accent-red);
    color: white;
}
.btn-primary:hover { background: var(--accent-red-hover); }

.btn-secondary {
    background: var(--bg-card);
    color: var(--text-primary);
    border: 1px solid var(--border-color);
}

.btn-ghost {
    background: transparent;
    color: var(--text-secondary);
}
.btn-ghost:hover { color: var(--text-primary); }

.btn-full { width: 100%; }

.btn-link {
    background: var(--bg-card);
    color: var(--accent-red-hover);
    border: 1px solid var(--accent-red);
}

.btn-location {
    background: var(--bg-card);
    color: #c8935a;
    border: 1px solid var(--accent-leather);
}
.btn-location:hover { background: rgba(139, 69, 19, 0.15); }

.btn-icon {
    background: var(--bg-card);
    color: var(--text-primary);
    width: 48px;
    height: 48px;
    padding: 0;
    font-size: 20px;
}

.icon-share,
.icon-qr {
    flex-shrink: 0;
    vertical-align: middle;
}

.btn-delete {
    background: rgba(231, 76, 60, 0.2);
    color: var(--error);
    border: none;
    border-radius: 8px;
    padding: 6px 10px;
    cursor: pointer;
    font-size: 14px;
}

/* ── Inputs ───────────────────────────────── */
.input {
    width: 100%;
    padding: 14px 16px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius);
    color: var(--text-primary);
    font-size: 16px;
    outline: none;
    transition: border-color 0.2s;
}
.input:focus { border-color: var(--accent-red); }

/* ── Setup Page ───────────────────────────── */
.setup-page {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 80dvh;
    text-align: center;
}

.logo-area { margin-bottom: 32px; }
.app-icon { font-size: 64px; margin-bottom: 8px; }
.app-icon-img {
    width: 64px;
    height: 64px;
    margin-bottom: 8px;
}

.home-icon {
    width: 140px;
    height: 140px;
    margin-bottom: 12px;
}

.gyro-eye { display: block; }
.gyro-eye-ring { fill: var(--accent-red); }
.gyro-eye-white { fill: #ffffff; }
.gyro-eye-pupil {
    fill: #0d0d0d;
    /* No CSS transition here — the spring-damper simulation in
       initGyroEyes() already animates every frame itself; a CSS
       transition on top would just add lag on top of the physics. */
}

.home-page {
    max-width: 560px;
    margin: 0 auto;
}

.home-page .card {
    margin-bottom: 20px;
    text-align: left;
}

.home-tagline {
    color: var(--text-secondary);
    font-size: 15px;
    margin-top: 4px;
}

.home-copy {
    color: var(--text-primary);
    line-height: 1.6;
    margin-bottom: 12px;
    text-align: left;
}
.home-copy:last-child { margin-bottom: 0; }

.home-steps {
    text-align: left;
    padding-left: 20px;
    line-height: 1.8;
}

.home-footnote {
    color: var(--text-secondary);
    font-size: 14px;
    margin-top: 24px;
}

.directory-cta,
.hunt-cta {
    display: block;
    color: inherit;
    text-decoration: none;
    text-align: left;
    border: 1px solid var(--border-color);
    transition: transform 0.15s ease, border-color 0.15s ease;
}

.directory-cta:active,
.hunt-cta:active {
    transform: scale(0.98);
}

.directory-cta {
    border-color: var(--accent-red-hover, #c0392b);
}

.directory-cta h2,
.hunt-cta h2 {
    margin-bottom: 4px;
}

.directory-cta .subtitle,
.hunt-cta .subtitle {
    margin-bottom: 0;
}

.directory-page,
.share-pending-page {
    max-width: 560px;
    margin: 0 auto;
}

.directory-page .card {
    margin-bottom: 20px;
    text-align: left;
}

.nearby-map {
    width: 100%;
    height: 280px;
    border-radius: var(--radius);
    margin-bottom: 8px;
    z-index: 0;
}

.leaflet-div-icon.map-marker-icon {
    background: transparent;
    border: none;
}

.map-marker-thumb {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    overflow: hidden;
    border: 3px solid var(--accent-red);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
    background: var(--bg-card);
    cursor: pointer;
}

.map-marker-thumb img,
.map-marker-thumb video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.map-marker-placeholder {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
}

.directory-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
}

.directory-tile {
    position: relative;
    background: var(--bg-card);
    border-radius: var(--radius);
    overflow: hidden;
    box-shadow: var(--shadow);
}

.directory-tile-link {
    display: block;
    color: inherit;
    text-decoration: none;
}

.directory-tile-link img,
.directory-tile-link video {
    width: 100%;
    aspect-ratio: 1;
    object-fit: cover;
    display: block;
    background: var(--bg-secondary);
}

.directory-tile-placeholder {
    width: 100%;
    aspect-ratio: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 40px;
    background: var(--bg-secondary);
}

.directory-tile-name {
    display: block;
    padding: 8px 10px;
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.age-gated {
    filter: blur(20px);
    pointer-events: none;
    user-select: none;
}

.age-gate-overlay {
    position: fixed;
    inset: 0;
    z-index: 50;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: rgba(0, 0, 0, 0.6);
}

.age-gate-overlay.hidden {
    display: none;
}

.age-gate-card {
    max-width: 360px;
    text-align: center;
}

.age-gate-card .btn {
    margin-top: 10px;
}

.raccoon-avatar-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 8px;
    max-height: 320px;
    overflow-y: auto;
    padding: 2px;
}

.raccoon-avatar-option {
    /* Safari can otherwise render an unstyled <button> using its native
       widget box, ignoring the grid track size entirely and collapsing
       every item to the same spot — appearance:none opts it out of that
       so it lays out as a plain grid item like everywhere else. */
    appearance: none;
    -webkit-appearance: none;
    display: block;
    width: 100%;
    min-width: 0;
    min-height: 0;
    margin: 0;
    padding: 0;
    border: 2px solid transparent;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--bg-secondary);
    cursor: pointer;
    aspect-ratio: 1;
}

.raccoon-avatar-option img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.raccoon-avatar-option.selected {
    border-color: var(--accent-red-hover, #c0392b);
}

.hunt-targets {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12px;
}

.hunt-target-tile {
    position: relative;
    background: var(--bg-card);
    border-radius: var(--radius);
    overflow: hidden;
    box-shadow: var(--shadow);
    opacity: 0.55;
    filter: grayscale(0.6);
}

.hunt-target-tile.hunt-target-found {
    opacity: 1;
    filter: none;
    outline: 2px solid var(--accent-red-hover, #c0392b);
}

.hunt-target-tile img,
.hunt-target-tile video {
    width: 100%;
    aspect-ratio: 1;
    object-fit: cover;
    display: block;
    background: var(--bg-secondary);
}

.hunt-target-name {
    display: block;
    padding: 6px 8px 2px;
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.hunt-target-check {
    display: block;
    padding: 0 8px 8px;
    font-size: 12px;
    color: var(--accent-red-hover, #c0392b);
}

.directory-remove-btn {
    position: absolute;
    top: 6px;
    right: 6px;
    z-index: 2;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: none;
    background: rgba(0, 0, 0, 0.6);
    color: white;
    font-size: 13px;
    line-height: 1;
    cursor: pointer;
}

.directory-remove-btn:hover { background: var(--accent-red); }

.profile-page-icon {
    display: block;
    width: 40px;
    height: 40px;
    margin: 0 auto 12px;
}

.profile-name {
    text-align: center;
    font-size: 20px;
    font-weight: 700;
    color: var(--text-primary);
    margin-bottom: 12px;
}
.logo-area h1 {
    font-size: 28px;
    background: linear-gradient(135deg, var(--accent-red), #e67e22);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

.card {
    background: var(--bg-card);
    border-radius: 16px;
    padding: 32px 24px;
    width: 100%;
    box-shadow: var(--shadow);
}

.card h2 { font-size: 22px; margin-bottom: 8px; }
.subtitle { color: var(--text-secondary); font-size: 14px; margin-bottom: 24px; }

.form-group {
    margin-bottom: 16px;
    text-align: left;
}
.form-group label {
    display: block;
    font-size: 13px;
    color: var(--text-secondary);
    margin-bottom: 6px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.form-group input {
    width: 100%;
    padding: 14px 16px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius);
    color: var(--text-primary);
    font-size: 20px;
    letter-spacing: 4px;
    text-align: center;
    outline: none;
}
.form-group input:focus { border-color: var(--accent-red); }

.result-area { margin-top: 16px; min-height: 40px; }
.success { padding: 16px; background: rgba(39, 174, 96, 0.1); border-radius: var(--radius); }
.success h3 { color: var(--success); margin-bottom: 8px; }
.error { color: var(--error); padding: 12px; }

.tag-id {
    margin-top: 24px;
    font-size: 12px;
    color: var(--text-secondary);
    opacity: 0.6;
}

.tap-counter {
    margin-top: 16px;
    text-align: center;
    font-size: 13px;
    color: var(--text-secondary);
}

.stink-chart-link-wrap {
    text-align: center;
    margin-top: 6px;
}

.stink-chart-link {
    font-size: 13px;
    color: var(--accent-red-hover);
    text-decoration: none;
}

/* ── Stink Chart (stick figure) ──────────────────────── */
.stink-chart-card {
    text-align: center;
}

.stink-figure {
    width: 100%;
    max-width: 320px;
    height: auto;
    color: var(--text-secondary);
    margin: 0 auto 12px;
    display: block;
}

.stink-figure-outline {
    fill: none;
    stroke: currentColor;
    stroke-width: 4;
    stroke-linecap: round;
}

.stink-leader {
    stroke: var(--border-color);
    stroke-width: 1.5;
}

.stink-leader-arrowhead {
    fill: var(--border-color);
}

.stink-dot {
    fill: var(--accent-red);
    stroke: var(--bg-card);
    stroke-width: 2;
}

.stink-dot-unset {
    fill: var(--text-secondary);
    opacity: 0.5;
}

/* Tap-to-rate mode (add-sheet flow) — bigger, pulsing, obviously-
   tappable dots with a pointer cursor, like tapping a pain-scale body
   chart. The pulse itself is the "invite touching" cue. */
.stink-figure.stink-editable .stink-dot {
    cursor: pointer;
    transform-box: fill-box;
    transform-origin: center;
    animation: stink-dot-pulse 0.9s ease-in-out infinite;
}

@keyframes stink-dot-pulse {
    0%, 100% { transform: scale(2); filter: drop-shadow(0 0 0 rgba(231, 76, 60, 0)); }
    50% { transform: scale(2.9); filter: drop-shadow(0 0 8px rgba(231, 76, 60, 0.9)); }
}

.stink-add-hint {
    text-align: center;
    font-weight: 600;
}

/* Scent wafts — view mode only (edit mode pulses the dots instead).
   The group's own scale (from --stink-intensity, set in JS to
   value/10) sizes the whole cloud per rating; the puffs inside
   independently drift up and fade on a loop regardless of intensity. */
.stink-scent {
    transform-box: fill-box;
    transform-origin: center;
    transform: scale(var(--stink-intensity, 0));
    transition: transform 0.4s ease;
    pointer-events: none;
}

.stink-figure.stink-editable .stink-scent {
    display: none;
}

.stink-scent-puff {
    fill: gold;
    opacity: 0;
    transform-box: fill-box;
    transform-origin: center;
    animation: stink-waft 3.4s ease-out infinite;
}

.stink-scent-puff:nth-child(2) { animation-delay: 0.85s; }
.stink-scent-puff:nth-child(3) { animation-delay: 1.7s; }
.stink-scent-puff:nth-child(4) { animation-delay: 2.55s; }

@keyframes stink-waft {
    0% { transform: translate(0, 0) scale(0.5); opacity: 0.75; }
    30% { transform: translate(8px, -22px) scale(0.9); opacity: 0.65; }
    60% { transform: translate(-10px, -48px) scale(1.4); opacity: 0.4; }
    100% { transform: translate(6px, -80px) scale(2.1); opacity: 0; }
}

/* Junk and butt sit close together, so their clouds drift apart to the
   sides (instead of both wafting straight up) to keep it obvious which
   is which. */
.stink-scent[data-part="junk"] .stink-scent-puff { animation-name: stink-waft-left; }
.stink-scent[data-part="butt"] .stink-scent-puff { animation-name: stink-waft-right; }

@keyframes stink-waft-left {
    0% { transform: translate(0, 0) scale(0.5); opacity: 0.75; }
    30% { transform: translate(-14px, -18px) scale(0.9); opacity: 0.65; }
    60% { transform: translate(-30px, -38px) scale(1.4); opacity: 0.4; }
    100% { transform: translate(-48px, -60px) scale(2.1); opacity: 0; }
}

@keyframes stink-waft-right {
    0% { transform: translate(0, 0) scale(0.5); opacity: 0.75; }
    30% { transform: translate(14px, -18px) scale(0.9); opacity: 0.65; }
    60% { transform: translate(30px, -38px) scale(1.4); opacity: 0.4; }
    100% { transform: translate(48px, -60px) scale(2.1); opacity: 0; }
}

.stink-label {
    fill: var(--text-primary);
    font-size: 15px;
    font-weight: 600;
}

.stink-sheet-meta {
    font-size: 14px;
    color: var(--text-secondary);
    margin-top: 8px;
}

.stink-sheet-meta strong {
    color: var(--text-primary);
}

.stink-sheet-note {
    font-size: 13px;
    color: var(--text-secondary);
    font-style: italic;
    margin-top: 6px;
}

#stink-edit-section {
    margin-top: 20px;
    padding-top: 20px;
    border-top: 1px solid var(--border-color);
}

#stink-edit-controls {
    margin-top: 12px;
}

#stink-draft-note-input {
    margin-top: 12px;
    margin-bottom: 12px;
    resize: vertical;
}

/* ── Tap-to-rate slider modal ────────────────────────── */
.stink-slider-value {
    font-size: 48px;
    font-weight: 700;
    text-align: center;
    color: var(--accent-red-hover);
    margin: 8px 0;
}

#stink-slider-input {
    width: 100%;
    accent-color: var(--accent-red);
    margin-bottom: 8px;
}

.stink-slider-scale-labels {
    display: flex;
    justify-content: space-between;
    font-size: 13px;
    color: var(--text-secondary);
    margin-bottom: 20px;
}

/* ── Stink sheet comments ────────────────────────────── */
.stink-comments-section {
    margin-top: 20px;
    padding-top: 20px;
    border-top: 1px solid var(--border-color);
    text-align: left;
}

.stink-comments-section h3 {
    font-size: 14px;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 10px;
}

.stink-comment-item {
    position: relative;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius);
    padding: 10px 36px 10px 12px;
    margin-bottom: 8px;
}

.stink-comment-meta {
    font-size: 13px;
    margin-bottom: 4px;
}

.stink-comment-meta strong {
    color: var(--text-primary);
}

.stink-comment-info-btn {
    opacity: 0.7;
}

.stink-comment-text {
    font-size: 14px;
    color: var(--text-primary);
    white-space: pre-wrap;
    word-break: break-word;
}

.stink-comment-snapshot {
    font-size: 12px;
    color: var(--text-secondary);
    background: var(--bg-card);
    border-radius: 8px;
    padding: 6px 8px;
    margin-top: 6px;
}

.stink-comment-delete-btn {
    position: absolute;
    top: 8px;
    right: 8px;
}

#stink-comment-form {
    margin-top: 12px;
}

#stink-comment-input {
    margin-bottom: 8px;
    resize: vertical;
}

.stink-chart-card > .btn-ghost {
    margin-top: 20px;
}

.tap-counter-milestone {
    color: var(--accent-red-hover);
    font-weight: 600;
    animation: milestone-pop 0.5s ease;
}

@keyframes milestone-pop {
    0% { transform: scale(0.8); opacity: 0; }
    60% { transform: scale(1.1); }
    100% { transform: scale(1); opacity: 1; }
}

/* ── Reveal Effect ──────────────────────────
   A soft ripple carries the reveal — it alone reads as an intentional
   "unlock" pulse. The sparkle particles are a light accent on top: each
   starts already spread a little from the tap point (not stacked on it)
   so there's no instant of them clumped into one tiny dot before they
   fan out. */
.reveal-ripple {
    position: fixed;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    pointer-events: none;
    z-index: 999;
    background: radial-gradient(circle, rgba(255, 255, 255, 0.85) 0%, rgba(255, 255, 255, 0.25) 45%, transparent 72%);
    animation: reveal-ripple-burst 0.6s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

@keyframes reveal-ripple-burst {
    0% { transform: translate(-50%, -50%) scale(0.4); opacity: 0.9; }
    100% { transform: translate(-50%, -50%) scale(9); opacity: 0; }
}

.confetti-particle {
    position: fixed;
    pointer-events: none;
    font-size: 18px;
    z-index: 1000;
    opacity: 0;
    animation: confetti-burst 0.75s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

@keyframes confetti-burst {
    0% { transform: translate(calc(-50% + var(--sx)), calc(-50% + var(--sy))) scale(0.5); opacity: 0; }
    25% { opacity: 1; }
    100% { transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(0.85); opacity: 0; }
}


/* ── Profile / Gallery Page ───────────────── */
.profile-page {
    display: flex;
    flex-direction: column;
    min-height: 100dvh;
}

/* Plain flex:1 used to grow this to fill all remaining vertical space
   regardless of width, so on a tall/wide desktop window the box ended up
   extremely tall-and-narrow (width capped at 480px by .container, height
   2-3x that); object-fit:cover on a landscape photo then crops it down to
   an unrecognizable vertical sliver to fill that shape. A fixed aspect
   ratio keeps the frame reasonable regardless of viewport height, on
   every page that uses this class (profile_view.html, private_gallery.html). */
.gallery-viewer {
    flex: 0 1 auto;
    position: relative;
    overflow: hidden;
    border-radius: var(--radius);
    background: var(--bg-secondary);
    min-height: 0;
    aspect-ratio: 4 / 5;
    max-height: 70dvh;
}

/* Widen the page specifically for a shared-gallery view (the only content
   on the page is the viewer itself, so there's no body text whose line
   length would suffer) — every other page keeps .container's normal
   480px mobile-first cap. Scoped with :has() rather than a body/page
   class so it lives entirely in CSS, no template plumbing needed. */
.container:has(.gallery-viewer-standalone) {
    max-width: 720px;
}

.gallery-track {
    display: flex;
    height: 100%;
    transition: transform 0.3s ease;
}

.gallery-slide {
    display: flex;
    align-items: center;
    justify-content: center;
    position: absolute;
    inset: 0;
    opacity: 0;
    z-index: 0;
    pointer-events: none;
    transition: opacity 0.3s ease;
}

.gallery-slide.active {
    opacity: 1;
    z-index: 1;
    pointer-events: auto;
}

.gallery-image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: var(--radius);
    filter: blur(24px) brightness(0.7);
    transform: scale(1.03);
    transition: filter 0.5s ease, transform 0.5s cubic-bezier(0.34, 1.15, 0.64, 1);
}

.gallery-audio-card {
    width: 100%;
    height: 100%;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-secondary);
    border-radius: var(--radius);
    cursor: pointer;
    overflow: hidden;
}

.gallery-audio-card > canvas.audio-waveform-canvas {
    position: absolute;
    inset: 20px;
    display: block;
    width: calc(100% - 40px);
    height: calc(100% - 40px);
    max-width: none;
    filter: opacity(0.55);
    transition: filter 0.3s ease;
}

.gallery-audio-card:active > canvas.audio-waveform-canvas { filter: opacity(0.85); }

.audio-tap-hint {
    position: relative;
    z-index: 1;
    color: var(--text-primary);
    font-size: 14px;
    background: rgba(0, 0, 0, 0.55);
    padding: 8px 16px;
    border-radius: 999px;
    pointer-events: none;
    white-space: nowrap;
}

.gallery-audio-card.revealed {
    cursor: pointer;
}

.gallery-audio-card.revealed > canvas.audio-waveform-canvas {
    filter: none;
}

.audio-play-btn {
    position: absolute;
    z-index: 2;
    bottom: 20px;
    left: 20px;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    border: none;
    background: var(--accent-red);
    color: white;
    font-size: 17px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.4);
    transition: transform 0.15s ease, background 0.15s ease;
}

.audio-play-btn:active { transform: scale(0.9); }
.audio-play-btn:hover { background: var(--accent-red-hover); }

.audio-time {
    position: absolute;
    z-index: 2;
    top: 16px;
    right: 16px;
    font-size: 12px;
    color: var(--text-primary);
    background: rgba(0, 0, 0, 0.55);
    padding: 4px 10px;
    border-radius: 999px;
    font-variant-numeric: tabular-nums;
    pointer-events: none;
}

.audio-time {
    flex: 0 0 auto;
    font-size: 12px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    min-width: 32px;
    text-align: right;
}

.gallery-image.blurred {
    filter: blur(24px) brightness(0.7);
    transform: scale(1.03);
}

.gallery-image:not(.blurred) {
    filter: blur(0) brightness(1);
    transform: scale(1);
}

.heart-btn {
    position: absolute;
    bottom: 12px;
    right: 12px;
    z-index: 2;
    display: flex;
    align-items: center;
    gap: 4px;
    background: rgba(0, 0, 0, 0.5);
    backdrop-filter: blur(4px);
    border: none;
    border-radius: 999px;
    padding: 6px 12px;
    color: white;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    transition: transform 0.15s ease;
}

.heart-btn:active { transform: scale(0.92); }
.heart-btn.hearted { background: rgba(192, 57, 43, 0.6); cursor: default; }
.heart-btn .heart-icon { font-size: 16px; display: inline-block; }
.heart-btn.hearted .heart-icon { animation: heart-icon-pop 0.4s ease; }

@keyframes heart-icon-pop {
    0% { transform: scale(1); }
    40% { transform: scale(1.6); }
    100% { transform: scale(1); }
}

.heart-burst-main {
    position: fixed;
    pointer-events: none;
    font-size: 64px;
    z-index: 1001;
    transform: translate(-50%, -50%);
    animation: heart-pop 0.7s cubic-bezier(0.17, 0.89, 0.32, 1.49) forwards;
}

@keyframes heart-pop {
    0% { transform: translate(-50%, -50%) scale(0); opacity: 0; }
    40% { transform: translate(-50%, -50%) scale(1.4); opacity: 1; }
    100% { transform: translate(-50%, -50%) scale(1); opacity: 0; }
}

.heart-burst-mini {
    position: fixed;
    pointer-events: none;
    font-size: 20px;
    z-index: 1000;
    transform: translate(-50%, -50%);
    animation: heart-float 0.9s ease-out forwards;
}

@keyframes heart-float {
    0% { transform: translate(-50%, -50%) scale(0.5); opacity: 1; }
    100% { transform: translate(calc(-50% + var(--dx)), -140px) scale(1); opacity: 0; }
}

.gallery-nav {
    position: absolute;
    bottom: 12px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    gap: 8px;
    z-index: 2;
}

.nav-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.4);
    border: none;
    cursor: pointer;
    transition: all 0.2s;
}

.nav-dot.active {
    background: white;
    transform: scale(1.3);
}

.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100%;
    color: var(--text-secondary);
    text-align: center;
    padding: 32px;
}

.empty-state .hint {
    font-size: 13px;
    margin-top: 8px;
    opacity: 0.7;
}

/* ── Controls Bar ─────────────────────────── */
.controls-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 16px;
    background: var(--bg-card);
    border-radius: var(--radius);
    margin-top: 12px;
}

/* ── Modals ───────────────────────────────── */
/* z-index is assigned dynamically per modal at open time (see
   initModalStacking() in app.js) rather than hand-maintained per-id
   tiers here — a modal opened from inside another already-open modal
   (crop from conversation from manage, etc.) always lands above it
   automatically, for any modal present now or added later. This base
   value is just the floor everything starts from and the fallback
   z-index if JS hasn't run yet. Stays well under the toast (200) and
   confetti/heart-burst (999-1001) layers, which must always stay on
   top of every modal. */
.modal {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: center;
}

.modal-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.7);
    backdrop-filter: blur(4px);
}

.nfc-write-illustration {
    display: flex;
    justify-content: center;
    margin: 4px 0 20px;
    color: var(--text-secondary);
}

.nfc-write-illustration svg {
    animation: nfc-phone-nudge 1.6s ease-in-out infinite;
}

@keyframes nfc-phone-nudge {
    0%, 100% { transform: translateX(0); }
    50% { transform: translateX(8px); }
}

.nfc-wave {
    opacity: 0;
    animation: nfc-wave-pulse 1.6s ease-in-out infinite;
}

.nfc-wave-1 { animation-delay: 0s; }
.nfc-wave-2 { animation-delay: 0.2s; }
.nfc-wave-3 { animation-delay: 0.4s; }

@keyframes nfc-wave-pulse {
    0%, 25% { opacity: 0; }
    45%, 65% { opacity: 1; }
    90%, 100% { opacity: 0; }
}

.modal-content {
    position: relative;
    background: var(--bg-card);
    border-radius: 16px;
    padding: 32px 24px;
    width: 90%;
    max-width: 400px;
    max-height: 85dvh;
    overflow-y: auto;
    box-shadow: var(--shadow);
    text-align: center;
}

.modal-content h2 {
    font-size: 20px;
    margin-bottom: 8px;
}

.media-lightbox-content {
    background: transparent;
    box-shadow: none;
    padding: 0;
    width: 92vw;
    height: 75dvh;
    overflow: visible;
}

#media-lightbox-body {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* A fixed frame with object-fit: cover, same as the main gallery's own
   slides — a portrait phone video/photo otherwise renders as a narrow
   letterboxed sliver (width shrinks to match its tall aspect ratio under
   plain max-width/max-height), which reads as broken rather than just
   "a portrait photo, correctly not cropped". */
.media-lightbox-content img,
.media-lightbox-content video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    border-radius: 8px;
}

.media-lightbox-content audio {
    width: 100%;
    max-width: 420px;
    display: block;
}

.media-lightbox-close {
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 1;
    background: rgba(0, 0, 0, 0.55);
    border: none;
    border-radius: 50%;
    color: #fff;
    font-size: 22px;
    cursor: pointer;
    line-height: 1;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.modal-hint {
    font-size: 13px;
    color: var(--text-secondary);
    margin-bottom: 20px;
}

.trim-waveform-wrap {
    position: relative;
    width: 100%;
    height: 80px;
    background: var(--bg-secondary);
    border-radius: var(--radius);
    overflow: hidden;
    margin-bottom: 16px;
}

.trim-waveform-wrap canvas {
    display: block;
    width: 100%;
    height: 100%;
}

.trim-mask {
    position: absolute;
    top: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.65);
    pointer-events: none;
}

.trim-mask-left { left: 0; width: 0; }
.trim-mask-right { right: 0; width: 0; }

.trim-range-row {
    text-align: left;
    margin-bottom: 12px;
}

.trim-range-row label {
    display: flex;
    justify-content: space-between;
    font-size: 12px;
    color: var(--text-secondary);
    margin-bottom: 4px;
}

.trim-range-row input[type="range"] {
    width: 100%;
}

/* PIN digit inputs */
.pin-inputs {
    display: flex;
    gap: 8px;
    justify-content: center;
    margin-bottom: 20px;
}

.pin-digit {
    width: 44px;
    height: 52px;
    text-align: center;
    font-size: 22px;
    font-weight: 700;
    background: var(--bg-secondary);
    border: 2px solid var(--border-color);
    border-radius: 10px;
    color: var(--text-primary);
    outline: none;
    caret-color: var(--accent-red);
}
.pin-digit:focus { border-color: var(--accent-red); }

.modal-error {
    color: var(--error);
    font-size: 13px;
    margin-top: 12px;
}

/* ── Manage Panel ─────────────────────────── */
.manage-panel {
    text-align: left;
}

.manage-panel h2 { text-align: center; margin-bottom: 20px; }

.manage-tabs {
    display: flex;
    margin-bottom: 18px;
    border-bottom: 1px solid var(--border-color);
    overflow-x: auto;
    scrollbar-width: none;
}

.manage-tabs::-webkit-scrollbar { display: none; }

.manage-tab {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    background: none;
    border: none;
    padding: 8px 2px;
    color: var(--text-secondary);
    cursor: pointer;
    border-bottom: 2px solid transparent;
}

.manage-tab .tab-icon {
    font-size: 16px;
    line-height: 1;
}

.manage-tab .tab-label {
    font-size: 10px;
    line-height: 1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}

.manage-tab.active {
    color: var(--text-primary);
    border-bottom-color: var(--accent-red);
    font-weight: 600;
}

.manage-tab-panel { display: none; }
.manage-tab-panel.active { display: block; }

.toggle-label {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 14px;
    color: var(--text-primary);
    margin-bottom: 14px;
    cursor: pointer;
}

.toggle-label input[type="checkbox"] {
    width: 18px;
    height: 18px;
    accent-color: var(--accent-red);
    cursor: pointer;
}

/* Generic rather than a per-class-name list — that list approach has
   silently missed newly-added sections twice now (dob/stink-score/
   raccoon-avatar, then stink-chart/stink-history), since every new
   section needs remembering to add it here too. Any <section> inside a
   manage-tab-panel gets this treatment automatically instead. */
.manage-tab-panel section {
    margin-bottom: 20px;
}

.manage-tab-panel section > h3 {
    font-size: 14px;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 10px;
}

/* A divider before every section that follows another one, rather than
   a manually maintained list of class names per section — the previous
   per-class approach is exactly how dob/stink-score/raccoon-avatar
   ended up missing this treatment above until now. Naturally skips the
   first section in each tab (nothing above it to separate from) and
   keeps working as new sections get added. */
.manage-tab-panel section + section {
    padding-top: 20px;
    border-top: 1px solid var(--border-color);
}

.photo-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
    margin-bottom: 12px;
}

.gallery-section {
    border-radius: var(--radius);
    transition: background 0.15s, box-shadow 0.15s;
    padding: 8px;
    margin-left: -8px;
    margin-right: -8px;
}

.gallery-section.drag-over,
.tag-row-details.drag-over {
    background: rgba(192, 57, 43, 0.08);
    outline: 2px dashed var(--accent-red);
    outline-offset: -2px;
}

.manage-photo-card {
    position: relative;
    aspect-ratio: 1;
    border-radius: 8px;
    overflow: hidden;
}

.manage-photo-card img, .manage-photo-card video {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.manage-audio-thumb {
    display: block;
    width: 100%;
    height: 100%;
    background: var(--bg-secondary);
}

.manage-photo-card .btn-delete {
    position: absolute;
    top: 4px;
    right: 4px;
}

.manage-photo-card-audio {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 24px;
    background: var(--bg-secondary);
}

.gallery-create-row {
    display: flex;
    gap: 8px;
    margin-bottom: 12px;
}

.gallery-create-row .input {
    flex: 1;
}

.gallery-detail-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 8px;
}

.upload-actions {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.upload-btn {
    display: block;
    text-align: center;
    padding: 12px;
    background: var(--bg-secondary);
    border: 2px dashed var(--border-color);
    border-radius: var(--radius);
    color: var(--text-secondary);
    cursor: pointer;
    font-size: 14px;
}

.crop-container {
    max-height: 60vh;
    overflow: hidden;
    margin-bottom: 16px;
    background: var(--bg-primary);
    border-radius: var(--radius);
}

.crop-container img {
    display: block;
    max-width: 100%;
}

.crop-panel {
    max-width: 90vw;
    width: 420px;
}

.link-section .input, .pin-section .input, .name-section .input, .bio-section .input { margin-bottom: 8px; }

.manage-tab-panel section .subtitle { margin-bottom: 12px; }

.stink-chart-field-label {
    display: block;
    font-size: 13px;
    color: var(--text-secondary);
    margin-bottom: 4px;
}

.stink-chart-field-label:not(:first-of-type) {
    margin-top: 12px;
}

#view-stink-chart-link {
    margin-top: 12px;
    display: inline-flex;
}

.directory-tags-checklist {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.tag-checkbox-label {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 12px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 999px;
    font-size: 13px;
    cursor: pointer;
}

.tag-checkbox-label input[type="checkbox"] {
    accent-color: var(--accent-red);
    cursor: pointer;
}

.nfc-unsupported-section {
    background: rgba(230, 126, 34, 0.12);
    border: 1px solid rgba(230, 126, 34, 0.4);
    border-radius: var(--radius);
    padding: 14px 16px;
}

.nfc-unsupported-title {
    color: #e67e22;
    font-weight: 700;
    font-size: 14px;
    margin-bottom: 6px;
}

.nfc-unsupported-text {
    color: var(--text-secondary);
    font-size: 13px;
    line-height: 1.5;
}

.nfc-unsupported-section.flash {
    animation: nfc-warning-flash 0.6s ease-in-out 2;
}

@keyframes nfc-warning-flash {
    0%, 100% { background: rgba(230, 126, 34, 0.12); }
    50% { background: rgba(230, 126, 34, 0.3); }
}

#reset-tag-result, #factory-reset-result {
    text-align: left;
}

#message-list {
    max-height: 260px;
    overflow-y: auto;
    text-align: left;
}

.message-card {
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    padding: 10px 12px;
    margin-bottom: 8px;
}

.message-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 13px;
}

.message-sender-link,
.message-sender-link:visited {
    color: var(--text-primary);
    font-weight: 700;
    text-decoration: none;
}

.message-sender-link:hover {
    text-decoration: underline;
}

.message-thread-card {
    text-align: left;
}

.message-image {
    display: block;
    width: 100%;
    max-height: 240px;
    object-fit: cover;
    border-radius: 8px;
    margin: 6px 0 4px;
}

/* Conversation thread modal */
.conversation-panel {
    max-width: 440px;
    text-align: left;
    display: flex;
    flex-direction: column;
    max-height: 85dvh;
}

.conversation-header {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 0 40px;
}

.conversation-header h2 {
    margin-bottom: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.conversation-header .btn-icon-inline {
    position: absolute;
    right: 32px;
    margin-left: 0;
}

.conversation-header .conversation-close-x {
    right: 0;
}

/* Given its own corner (mirroring the close X) instead of being squeezed
   next to it, and sized/backed as an actual button rather than a bare
   low-contrast glyph — the old right:32px placement made it easy to miss
   or misclick as part of the close button. */
.conversation-header #conversation-refresh-btn {
    left: 0;
    right: auto;
    width: 32px;
    height: 32px;
    font-size: 16px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 50%;
    opacity: 1;
}

.conversation-header #conversation-refresh-btn:hover {
    background: var(--border-color);
}

.conversation-header #conversation-refresh-btn:active {
    transform: scale(0.92);
}

.conversation-header .btn-icon-inline.spinning {
    animation: spin 0.6s linear;
}

@keyframes spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

.call-panel {
    margin: 10px 0;
}

#mic-choice-modal .btn-full {
    margin-bottom: 10px;
}

/* Calling/incoming/connected: a bigger, clearly-labeled status plus
   large circular controls — sized well past the usual minimum touch
   target since these get tapped in a hurry. */
.call-active {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    padding: 18px 14px;
    background: var(--bg-secondary);
    border-radius: var(--radius);
}

.call-panel-status {
    font-size: 17px;
    font-weight: 700;
    text-align: center;
}

.call-panel-hint {
    font-size: 13px;
    color: var(--text-secondary);
    text-align: center;
    margin: 0;
}

.call-video-wrap {
    position: relative;
    width: 100%;
    aspect-ratio: 4 / 3;
    background: #000;
    border-radius: var(--radius);
    overflow: hidden;
}

#remote-call-video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

#local-call-video {
    position: absolute;
    bottom: 8px;
    right: 8px;
    width: 84px;
    height: 112px;
    object-fit: cover;
    border-radius: 8px;
    border: 2px solid var(--bg-card);
    background: #000;
    transform: scaleX(-1); /* mirror, like a selfie camera preview */
}

.call-panel-actions {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 20px;
    align-self: stretch;
}

.call-panel-actions .btn {
    flex-direction: column;
    gap: 4px;
    width: 84px;
    height: 84px;
    padding: 0;
    border-radius: 50%;
    font-size: 15px;
    font-weight: 700;
    line-height: 1.2;
    white-space: normal;
}

.btn-call-answer {
    background: var(--success);
    color: #fff;
}

.btn-call-decline,
.btn-call-hangup {
    background: var(--accent-red);
    color: #fff;
}

.call-panel-actions .btn-call-hangup {
    border-radius: var(--radius);
}

/* Solo (while calling, before Mute joins it once connected): fill the
   row like a normal full-width button instead of sitting as a small
   square by itself. */
.call-panel-actions .btn-call-hangup.solo {
    flex: 1;
    flex-direction: row;
    width: auto;
    height: 52px;
    border-radius: var(--radius);
    font-size: 16px;
}

.btn-call-decline:hover,
.btn-call-hangup:hover {
    background: var(--accent-red-hover);
}

.btn-call-mute {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 64px;
    height: 64px;
    font-size: 26px;
    background: var(--bg-primary);
    border: 2px solid var(--border-color);
    border-radius: 50%;
    cursor: pointer;
}

.btn-call-mute.call-muted {
    background: var(--accent-red);
    border-color: var(--accent-red);
    color: #fff;
}

.conversation-thread {
    flex: 1;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 16px; /* extra room for the heart badge peeking below a bubble's corner */
    margin: 12px 0;
    padding-right: 4px;
}

.conversation-bubble {
    position: relative;
    max-width: 85%;
    border-radius: 12px;
    padding: 8px 12px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    user-select: none; /* double-tap-to-heart shouldn't also select the text */
}

.conversation-bubble-mine {
    align-self: flex-end;
    background: var(--accent-red);
    border-color: var(--accent-red);
    color: #fff;
}

.conversation-bubble-theirs {
    align-self: flex-start;
}

.conversation-bubble .message-text {
    margin: 0 0 2px;
}

.conversation-bubble .hint {
    margin: 0;
    opacity: 0.75;
}

/* Small badge in the bubble's corner, toggled by double-tapping the
   bubble — not a button, since there's nothing to click, just tap. */
.conversation-heart-indicator {
    position: absolute;
    bottom: -8px;
    right: -6px;
    font-size: 15px;
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: 999px;
    padding: 1px 5px;
    line-height: 1.3;
}

.conversation-heart-indicator.heart-pop {
    animation: heart-pop 0.3s ease-out;
}

@keyframes heart-pop {
    0% { transform: scale(0.4); }
    60% { transform: scale(1.3); }
    100% { transform: scale(1); }
}

/* Opposite corner from the heart badge — a real button (not a tap
   gesture), so it stays low-key until hovered/tapped. */
.conversation-report-btn {
    position: absolute;
    bottom: -8px;
    left: -6px;
    font-size: 12px;
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: 999px;
    padding: 1px 5px;
    line-height: 1.3;
    opacity: 0.4;
    cursor: pointer;
}

.conversation-report-btn:hover,
.conversation-report-btn:focus-visible {
    opacity: 1;
}

.conversation-reply {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.conversation-reply-actions {
    display: flex;
    align-items: center;
    gap: 8px;
}

.attach-preview {
    display: flex;
    align-items: center;
    gap: 8px;
}

.attach-thumbnail {
    width: 56px;
    height: 56px;
    object-fit: cover;
    border-radius: var(--radius);
}

.attach-gallery-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    flex: 1;
}

.attach-gallery-chip {
    display: inline-flex;
    align-items: center;
    font-size: 13px;
    font-weight: 600;
    background: var(--bg-secondary);
    border-radius: var(--radius);
    padding: 8px 12px;
}

.shared-gallery-card {
    display: block;
    margin: 6px 0 4px;
    border-radius: 8px;
    overflow: hidden;
    background: var(--bg-secondary);
    color: inherit;
    text-decoration: none;
}

.shared-gallery-thumb {
    display: block;
    width: 100%;
    max-height: 200px;
    object-fit: cover;
}

.shared-gallery-thumb-audio {
    height: 80px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 28px;
    background: var(--bg-primary);
}

.shared-gallery-card-label {
    display: block;
    padding: 8px 12px;
    font-size: 13px;
    font-weight: 600;
}

.conversation-reply-actions .btn-primary {
    flex: 1;
}

.message-text {
    font-size: 14px;
    margin: 6px 0 4px;
    white-space: pre-wrap;
    word-break: break-word;
}

.message-audio {
    width: 100%;
    height: 32px;
    margin: 6px 0 4px;
}

.btn-delete-message {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 13px;
    opacity: 0.7;
}
.btn-delete-message:hover { opacity: 1; }

#location-status, #reset-tag-result, #factory-reset-result {
    margin-top: 10px;
}

.location-status-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 6px;
}

.location-status-actions .btn {
    flex: 1 1 auto;
    min-width: 110px;
    text-align: center;
}

.location-status-actions .btn-icon {
    flex: 0 0 auto;
    min-width: 0;
}

textarea.input {
    width: 100%;
    resize: vertical;
    font-family: inherit;
}

.profile-bio {
    color: var(--text-primary);
    font-size: 14px;
    line-height: 1.5;
    text-align: center;
    max-width: 90%;
    margin: 8px auto;
    white-space: pre-wrap;
    word-break: break-word;
}

.profile-tags {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px;
    max-width: 90%;
    margin: 8px auto;
}

.profile-tag-pill {
    padding: 5px 12px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 999px;
    font-size: 12px;
    color: var(--text-secondary);
}

.location-caption {
    text-align: center;
    margin-top: 8px;
}

.controls-bar .location-caption {
    flex-basis: 100%;
    margin: 8px 0 0;
    padding-top: 12px;
    border-top: 1px solid var(--border-color);
}

.btn-icon-inline {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    vertical-align: middle;
    margin-left: 4px;
    width: 22px;
    height: 22px;
    padding: 0;
    background: none;
    border: none;
    font-size: 14px;
    line-height: 1;
    color: inherit;
    cursor: pointer;
    opacity: 0.85;
}

.btn-icon-inline:hover {
    opacity: 1;
}

/* ── Toast Notifications ──────────────────── */
#toast-container {
    position: fixed;
    top: 16px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 200;
    display: flex;
    flex-direction: column;
    gap: 8px;
    pointer-events: none;
}

.toast {
    padding: 12px 20px;
    border-radius: 8px;
    font-size: 14px;
    font-weight: 500;
    animation: toastIn 0.3s ease, toastOut 0.3s ease 2.7s forwards;
    pointer-events: auto;
}

.toast-success {
    background: var(--success);
    color: white;
}

.toast-error {
    background: var(--error);
    color: white;
}

@keyframes toastIn {
    from { opacity: 0; transform: translateY(-16px); }
    to { opacity: 1; transform: translateY(0); }
}

@keyframes toastOut {
    from { opacity: 1; }
    to { opacity: 0; transform: translateY(-16px); }
}

/* ── Responsive ───────────────────────────── */
@media (min-width: 481px) {
    .container { padding: 24px; }
    .card { padding: 40px 32px; }
}

/* ── Admin Page ───────────────────────────── */
.admin-page {
    max-width: 560px;
    margin: 0 auto;
}

.admin-page .card {
    text-align: left;
    margin-bottom: 16px;
}

.admin-page h2 {
    font-size: 18px;
    margin-bottom: 6px;
}

.subtitle {
    font-size: 13px;
    color: var(--text-secondary);
    margin-bottom: 16px;
}

.form-group {
    margin-bottom: 14px;
}

.form-group label {
    display: block;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-secondary);
    margin-bottom: 4px;
}

.result-box {
    margin-top: 16px;
    padding: 16px;
    background: var(--bg-secondary);
    border-radius: var(--radius);
    border: 1px solid var(--border-color);
}

.result-item {
    font-size: 14px;
    margin-bottom: 8px;
    word-break: break-all;
}

.result-item code {
    display: block;
    background: var(--bg-primary);
    padding: 6px 10px;
    border-radius: 6px;
    margin-top: 4px;
    font-size: 13px;
    word-break: break-all;
}

.result-item a {
    color: var(--accent-red);
    text-decoration: underline;
}

.write-nfc-btn {
    display: block;
    width: 100%;
    margin: 12px 0 8px;
}

.tag-row {
    margin-top: 10px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius);
    overflow: hidden;
}

.tag-row-header {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 12px;
    background: none;
    border: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

/* .gallery-picker-item reuses .tag-row-header's resets (button chrome
   stripped, full-width, left-aligned) but stacks its own content —
   name/count on top, a preview strip of what's actually in the
   gallery below, so picking one to share isn't a guess. */
.gallery-picker-item {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    border: 2px solid transparent;
}

.gallery-picker-item.selected {
    border-color: var(--accent-red-hover, #c0392b);
    background: var(--bg-secondary);
}

.gallery-picker-item-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.gallery-picker-checkbox {
    flex-shrink: 0;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 2px solid var(--border-color);
    background: var(--bg-primary);
}

.gallery-picker-item.selected .gallery-picker-checkbox {
    border-color: var(--accent-red-hover, #c0392b);
    background: var(--accent-red-hover, #c0392b);
    position: relative;
}

.gallery-picker-item.selected .gallery-picker-checkbox::after {
    content: "✓";
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: 13px;
    font-weight: 700;
}

.gallery-picker-actions {
    display: flex;
    gap: 8px;
    margin-top: 12px;
}

.gallery-picker-actions .btn {
    flex: 1;
}

.gallery-picker-thumbs {
    display: flex;
    gap: 6px;
    overflow-x: auto;
}

.gallery-picker-thumbs img,
.gallery-picker-thumbs video,
.gallery-picker-thumbs .manage-photo-card-audio {
    flex-shrink: 0;
    width: 56px;
    height: 56px;
    border-radius: 6px;
    object-fit: cover;
    background: var(--bg-primary);
}

.gallery-picker-thumb-more {
    flex-shrink: 0;
    width: 56px;
    height: 56px;
    border-radius: 6px;
    background: var(--bg-primary);
    color: var(--text-secondary);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    font-weight: 600;
}

.tag-row-thumb {
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    border-radius: 8px;
    object-fit: cover;
    background: var(--bg-primary);
}

.tag-row-thumb-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 16px;
}

.tag-row-summary {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

.tag-row-summary-line {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
}

.tag-row-chevron {
    flex-shrink: 0;
    color: var(--text-secondary);
    transition: transform 0.2s ease;
}

.tag-row-expanded .tag-row-chevron {
    transform: rotate(180deg);
}

.tag-row-details {
    padding: 0 12px 12px;
    border-top: 1px solid var(--border-color);
}

.tag-row-info {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
    padding-top: 12px;
}

.tag-row-info code {
    font-size: 12px;
    word-break: break-all;
}

.tag-row-info a {
    color: var(--accent-red-hover);
    text-decoration: underline;
}

.tag-row-info strong {
    font-size: 15px;
}

.admin-label-tag {
    display: inline-block;
    font-size: 12px;
    font-style: italic;
    color: var(--text-secondary);
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: 6px;
    padding: 2px 6px;
    width: fit-content;
}

.test-account-tag {
    color: #f0ad4e;
    border-color: #f0ad4e;
    background: rgba(240, 173, 78, 0.12);
}

.recognized-owner-banner {
    align-self: center;
    margin-bottom: 8px;
    font-size: 12px;
    color: var(--success);
    background: rgba(39, 174, 96, 0.12);
    border: 1px solid var(--success);
    border-radius: 6px;
    padding: 3px 8px;
}

.hunt-found-banner {
    align-self: center;
    margin-bottom: 8px;
    text-align: center;
    font-size: 13px;
    font-weight: 600;
    color: var(--accent-red-hover, #c0392b);
    background: rgba(192, 57, 43, 0.12);
    border: 1px solid var(--accent-red-hover, #c0392b);
    border-radius: 6px;
    padding: 6px 10px;
}

.tag-row-pending {
    border-style: dashed;
    opacity: 0.8;
}

.audit-log {
    max-height: 320px;
    overflow-y: auto;
    margin-top: 10px;
}

.audit-row {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 0;
    border-bottom: 1px solid var(--border-color);
    font-size: 13px;
}

.audit-row:last-child { border-bottom: none; }

.audit-row .audit-action {
    font-weight: 600;
}

.audit-row .audit-action.action-login_failed,
.audit-row .audit-action.action-reset_tag,
.audit-row .audit-action.action-delete_tag {
    color: var(--error);
}

.audit-row .audit-meta {
    color: var(--text-secondary);
    text-align: right;
    white-space: nowrap;
}

.directory-tag-row {
    margin-top: 6px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    overflow: hidden;
}

.directory-tag-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 7px 10px;
}

.directory-tag-expand {
    background: none;
    border: none;
    color: var(--text-primary);
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    text-align: left;
    padding: 0;
    flex: 1;
    min-width: 0;
}

.directory-tag-expand .tag-count {
    color: var(--text-secondary);
    font-weight: 400;
    font-size: 12px;
}

.directory-tag-profiles {
    padding: 0 10px 10px;
    border-top: 1px solid var(--border-color);
}

.directory-tag-profiles .directory-grid {
    margin-top: 10px;
}

.directory-tag-profiles .directory-tile-link {
    cursor: pointer;
}

#tags-search {
    margin-bottom: 10px;
}

.tags-toolbar {
    display: flex;
    gap: 10px;
    align-items: center;
}

.tags-toolbar select,
.tags-toolbar input {
    width: auto;
    flex: 1;
}

.tags-pagination {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 12px;
    margin-top: 12px;
}

.site-menu {
    position: fixed;
    top: 8px;
    right: 8px;
    z-index: 100;
}

.site-menu-btn {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    color: var(--text-primary);
    border-radius: 8px;
    padding: 6px 12px;
    font-size: 16px;
    line-height: 1.3;
    cursor: pointer;
}

.site-menu-dropdown {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    display: flex;
    flex-direction: column;
    min-width: 170px;
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    padding: 4px;
    box-shadow: var(--shadow);
}

.site-menu-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 9px 10px;
    border-radius: 6px;
    background: none;
    border: none;
    color: var(--text-primary);
    font-size: 14px;
    font-family: inherit;
    text-decoration: none;
    cursor: pointer;
}

.site-menu-item:visited {
    color: var(--text-primary);
}

.site-menu-item:hover {
    background: var(--bg-secondary);
}

.logout-top {
    display: flex;
    justify-content: flex-end;
    margin-bottom: 12px;
}

.btn-small {
    padding: 6px 10px;
    font-size: 12px;
    background: var(--bg-card);
    border: 1px solid var(--border-color);
}

.tag-row .btn {
    flex-shrink: 0;
}

.tag-row-actions {
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex-shrink: 0;
}

/* ── Blocked Profiles ─────────────────────── */
.block-add-row {
    display: flex;
    gap: 8px;
    margin-top: 4px;
}

.block-add-row .input {
    flex: 1;
    min-width: 0;
}

.blocked-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-top: 8px;
    padding: 8px 12px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 8px;
}

.blocked-row-name {
    font-size: 14px;
    min-width: 0;
    word-break: break-all;
}

.conversation-footer-actions {
    display: flex;
    gap: 8px;
    margin-top: 8px;
}
