/* Character Profile Page Styles - Instagram-like Design */

:root {
    --ig-bg: var(--bg-primary, #f0f0f0);
    --ig-surface: var(--bg-secondary, #e5e5e5);
    --ig-border: var(--border-color, #d9d9d9);
    --ig-text: var(--text-primary, #050505);
    --ig-text-secondary: var(--text-secondary, #575757);
    --ig-accent: linear-gradient(135deg, #575757 0%, #6c6c6c 40%, #797979 100%);
    --ig-blue: #777777;
    --ig-purple: #777777;
    --ig-pink: var(--ink-muted);
}

/* Override body for character page */
body:has(.ig-profile-header) {
    background: var(--bg-primary);
}

.profile-container {
    max-width: 100vw;
    margin: 0;
    padding-top: 0;
    background: var(--bg-primary);
    min-height: 100vh;
}

/* Profile Header */
.ig-profile-header {
    background: var(--ig-bg);
}

.ig-profile-info {
    display: flex;
    align-items: center;
    padding: 16px;
    gap: 20px;
}

.ig-avatar-section {
    flex-shrink: 0;
}

.ig-locked-preview-card {
    position: relative;
    width: 96px;
    height: 138px;
    border-radius: 18px;
    overflow: hidden;
    border: 1px solid rgba(54, 54, 54, 0.65);
    box-shadow: 0 14px 34px rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.06) inset;
    cursor: pointer;
    transform: translateZ(0);
}

.ig-locked-preview-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: top;
    filter: blur(16px) saturate(0.88) brightness(0.78);
    transform: scale(1.14);
}

.ig-locked-preview-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 10px 8px;
    background:
        radial-gradient(ellipse 90% 50% at 50% 12%, rgba(35, 35, 35, 0.2), transparent 58%),
        linear-gradient(170deg, rgba(237, 237, 237, 0.52) 0%, rgba(240, 240, 240, 0.9) 100%);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
}

.ig-locked-preview-icon {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(145deg, #5e5e5e 0%, #7a7a7a 100%);
    color: var(--brand-ink);
    font-size: 0.95rem;
    box-shadow: 0 8px 18px rgba(0, 0, 0, 0.06);
}

.ig-locked-preview-label {
    color: var(--ink);
    font-size: 0.78rem;
    font-weight: 800;
    line-height: 1.2;
    text-align: center;
    text-shadow: 0 2px 8px rgba(0, 0, 0, 0.16);
}

.ig-locked-preview-cta {
    border: none;
    border-radius: 999px;
    background: linear-gradient(135deg, #6c6c6c 0%, #7b7b7b 100%);
    color: var(--ink);
    font-size: 0.62rem;
    font-weight: 700;
    line-height: 1;
    padding: 7px 12px;
    box-shadow: 0 6px 14px rgba(0, 0, 0, 0.16);
    pointer-events: none;
}

.ig-avatar-ring {
    width: 86px;
    height: 86px;
    border-radius: 50%;
    padding: 3px;
    background: var(--ig-accent);
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
}

/* Owner/admin: change-profile-photo badge on the avatar (revealed by JS) */
.ig-avatar-edit-btn {
    position: absolute;
    right: -2px;
    bottom: -2px;
    width: 28px;
    height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 2px solid var(--ig-bg, #ededed);
    border-radius: 50%;
    background: var(--ig-accent, #6c6c6c);
    color: var(--brand-ink);
    cursor: pointer;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.16);
    transition: transform 0.16s ease, filter 0.16s ease;
    z-index: 3;
}
.ig-avatar-edit-btn:hover { transform: scale(1.1); filter: brightness(1.12); }
.ig-avatar-edit-btn:active { transform: scale(0.94); }
.ig-avatar-edit-btn i { font-size: 13px; line-height: 1; }
.ig-avatar-edit-btn[hidden] { display: none !important; }

.ig-avatar {
    width: 78px;
    height: 78px;
    border-radius: 50%;
    border: 3px solid var(--ig-bg);
    object-fit: cover;
    object-position: top;
}

.character-nsfw-overlay.premium-overlay {
    background:
        radial-gradient(ellipse 70% 40% at 50% 16%, rgba(35, 35, 35, 0.22), transparent 62%),
        radial-gradient(circle at 50% 50%, rgba(174, 174, 174, 0.18), transparent 70%),
        linear-gradient(170deg, rgba(237, 237, 237, 0.55) 0%, rgba(240, 240, 240, 0.88) 100%);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    flex-direction: column;
    gap: 16px;
    padding: 24px;
    text-align: center;
}

/* no card box — elements float directly on the overlay */
.character-lock-card {
    display: contents;
}

.character-lock-icon-wrap {
    width: 52px;
    height: 52px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--brand-ink);
    font-size: 1.35rem;
    background: linear-gradient(145deg, #5e5e5e 0%, #7a7a7a 100%);
    box-shadow: 0 10px 24px rgba(0, 0, 0, 0.06);
}

.character-lock-label {
    color: var(--ink);
    font-size: 1.55rem;
    font-weight: 800;
    line-height: 1.15;
    letter-spacing: -0.01em;
    text-align: center;
    text-shadow: 0 2px 14px rgba(0, 0, 0, 0.16);
}

.character-lock-subtitle {
    color: var(--ink-soft);
    font-size: 0.88rem;
    line-height: 1.45;
    text-align: center;
    max-width: 240px;
}

.character-lock-cta,
.ig-lock-cta-btn {
    border: none;
    border-radius: 999px;
    background: linear-gradient(135deg, #6c6c6c 0%, #7b7b7b 100%);
    color: var(--ink) !important;
    font-size: 1rem;
    font-weight: 700;
    line-height: 1;
    padding: 14px 36px;
    box-shadow: 0 10px 22px rgba(0, 0, 0, 0.16);
    transition: transform 0.2s ease, box-shadow 0.2s ease, filter 0.2s ease;
    min-width: 0;
    max-width: 100%;
}

.character-lock-cta:hover,
.ig-lock-cta-btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 14px 28px rgba(0, 0, 0, 0.16);
    filter: brightness(1.06);
}

/* Paid unlock overlay elements */
.character-overlay-lock-icon {
    font-size: 1.4rem;
    color: var(--ink);
    opacity: 0.9;
    margin-bottom: 4px;
}

.character-nsfw-unlock-cost {
    color: var(--ink) !important;
    font-size: 0.82rem;
    font-weight: 700;
    margin-bottom: 6px;
    text-align: center;
}

.character-nsfw-unlock-btn {
    background: linear-gradient(90.9deg, #232323 2.74%, #777777 102.92%);
    color: var(--brand-ink) !important;
    border: none;
    border-radius: 8px;
    font-weight: 700;
    padding: 0.5rem 0.9rem;
    font-size: 0.82rem;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 4px;
    white-space: nowrap;
}

/* Responsive overlay: compact version inside small gallery cells */
@media (max-width: 480px) {
    .character-nsfw-overlay.premium-overlay {
        gap: 6px;
        padding: 8px 4px;
    }
    .character-lock-icon-wrap {
        width: 28px;
        height: 28px;
        font-size: 0.8rem;
    }
    .character-lock-label {
        font-size: 0.75rem;
    }
    .character-lock-subtitle {
        font-size: 0.65rem;
        max-width: 100%;
    }
    .character-lock-cta,
    .ig-lock-cta-btn {
        font-size: 0.65rem;
        padding: 6px 10px;
    }
    /* Paid unlock overlay compact */
    .character-overlay-lock-icon {
        font-size: 0.9rem;
        margin-bottom: 2px;
    }
    .character-nsfw-unlock-cost {
        font-size: 0.6rem;
        margin-bottom: 3px;
    }
    .character-nsfw-unlock-btn {
        font-size: 0.6rem;
        padding: 4px 6px;
    }
}

.ig-stats-row {
    display: flex;
    flex: 1;
    justify-content: space-around;
}

.ig-stat {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}

.ig-stat-number {
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--ig-text);
    line-height: 1.2;
}

.ig-stat-label {
    font-size: 0.75rem;
    color: var(--ig-text-secondary);
    margin-top: 2px;
}

/* Bio Section */
.ig-bio-section {
    padding: 0 16px 12px;
}

/* Name + primary Follow button on one line */
.ig-name-row {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.ig-display-name {
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--ig-text);
    margin: 0;
    letter-spacing: -0.01em;
}

.ig-name-follow-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 14px;
    border-radius: 999px;
    border: 1px solid transparent;
    /* Fill and ink are ONE pair — if the token layer is missing (a stale
       theme.css in a browser cache, a page that forgot the <link>), each half
       must fall back to the other half's partner. A mid-grey fill next to an
       ink that falls back to `inherit` is how this pill once rendered as dark
       text on grey at 2.5:1. The fallbacks below mirror --brand-fill /
       --brand-ink so the unthemed path is still 19:1.
       The fill is the brand token, not --ig-blue: --ig-blue is the page's
       accent, a mid grey until the glass layer remaps it, and a mid grey
       carries 12.5px/600 ink at 4.3:1 either way — under AA. */
    background: var(--brand-fill, #000000);
    color: var(--brand-ink, #f6f6f6);
    font-size: 0.78rem;
    font-weight: 600;
    line-height: 1.2;
    cursor: pointer;
    white-space: nowrap;
    transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease, transform 0.12s ease;
}

.ig-name-follow-btn i {
    font-size: 0.85em;
}

/* The pill's ink lives on the button and changes with state (brand ink when
   not following, white on the grey followed fill, --status-ink on the red
   unfollow hover). Its children must FOLLOW that ink, not pin one of their
   own — so `inherit`, not a fixed colour. The `!important` exists only to beat
   `#characterProfilePage p, span, small { color: var(--ig-text-secondary) }`
   further down this file, which was repainting `.ig-follow-label` near-black
   on the black pill (same trap already documented on `.ig-btn-label`). */
.ig-name-follow-btn i,
.ig-name-follow-btn span,
.ig-follow-label {
    color: inherit !important;
}

/* Gated on a real pointer: a tap latches :hover, so on a phone the pill kept
   the lift long after the finger was gone. */
@media (hover: hover) {
    .ig-name-follow-btn:hover {
        filter: brightness(1.08);
        transform: translateY(-1px);
    }
}

/* Followed: a quieter fill than the black "Follow" pill, but still a fill, so
   the label keeps the same white ink. See .igp-follow in ig-post.css — the two
   pills are the same control on different surfaces and must not diverge. */
.ig-name-follow-btn.following {
    background: var(--fill-mid-strong, #5c5c62);
    border-color: transparent;
    color: var(--brand-ink, #f6f6f6);
}

/* Only on a real pointer: on touch, :hover latches after the tap and left the
   pill sitting in its red unfollow paint. */
@media (hover: hover) {
    .ig-name-follow-btn.following:hover {
        background: var(--status-danger, #c62828);
        border-color: var(--status-danger, #c62828);
        color: var(--status-ink, #ffffff);
        filter: none;
    }
}

/* Unique @handle under the display name */
.ig-handle-row {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 2px 0 6px;
}

.ig-handle {
    font-size: 0.82rem;
    font-weight: 500;
    color: var(--ig-text-secondary);
    letter-spacing: 0.01em;
}

.ig-handle-copy {
    background: none;
    border: none;
    padding: 0 2px;
    color: var(--ig-text-secondary);
    opacity: 0.6;
    font-size: 0.72rem;
    line-height: 1;
    cursor: pointer;
    transition: opacity 0.18s ease, color 0.18s ease;
}

.ig-handle-copy:hover {
    opacity: 1;
    color: var(--ig-text);
}

.ig-bio {
    font-size: 0.85rem;
    color: var(--ig-text);
    margin: 0;
    line-height: 1.4;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* Online / last-active dot next to the name */
.ig-presence {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--ig-text-secondary);
    white-space: nowrap;
}

.ig-presence-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: currentColor;
    flex-shrink: 0;
}

.ig-presence-online {
    color: #22c55e;
}

.ig-presence-online .ig-presence-dot {
    box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.16);
    animation: ig-presence-pulse 2.4s ease-out infinite;
}

.ig-presence-recent {
    color: #986206;
}

.ig-presence-away .ig-presence-dot {
    opacity: 0.5;
}

@keyframes ig-presence-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.16); }
    70%  { box-shadow: 0 0 0 6px rgba(0, 0, 0, 0); }
    100% { box-shadow: 0 0 0 0 rgba(0, 0, 0, 0); }
}

@media (prefers-reduced-motion: reduce) {
    .ig-presence-online .ig-presence-dot { animation: none; }
}

/* One-line status ("in your bed") — sits next to the @handle */
.ig-tagline {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-left: 6px;
    padding: 0;
    background: none;
    border: none;
    font-size: 0.78rem;
    color: var(--ig-text-secondary);
    line-height: 1.3;
    min-width: 0;
}

.ig-tagline i {
    font-size: 0.85em;
    opacity: 0.75;
    flex-shrink: 0;
}

.ig-tagline-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ig-tagline-editable {
    cursor: pointer;
    border-radius: 6px;
    transition: color 0.18s ease;
}

.ig-tagline-editable:hover {
    color: var(--ig-text);
}

.ig-tagline-add {
    opacity: 0.7;
    font-style: italic;
}

.ig-tagline-add:hover {
    opacity: 1;
}

/* Action Buttons Row */
.ig-action-row {
    display: flex;
    padding: 12px 16px;
    gap: 8px;
}

/* Button label text — visible on desktop, hidden icon-only on mobile.
   INHERIT, never a fixed ink. The `!important` here exists only to beat the
   page-wide `#characterProfilePage p, span, small { color: var(--ig-text-secondary) }`
   rule, which would otherwise grey out every button label. Pinning it to
   `--ink` did beat that rule — and then painted the label BLACK on the black
   --brand-gradient of .ig-chat-btn, so "Start chatting now" was an unreadable
   slab. The button already declares its own ink (--brand-ink on a brand fill,
   --ink on a light one); inheriting is what makes the label follow it. */
.ig-btn-label {
    color: inherit !important;
}

/* Every node inside a brand-filled CTA carries the brand ink, not the page's
   secondary grey. `.ig-btn-label` inherits, which only works if nothing between
   it and the button re-colours — and `#characterProfilePage span` (further down
   this file) does exactly that to the `.ig-btn-stack` wrapper, so the Subscribe
   pill's label was inheriting mid-grey onto black. Colour the whole subtree. */
.ig-chat-btn,
.ig-chat-btn *,
.character-subscribe-btn,
.character-subscribe-btn * {
    color: var(--brand-ink) !important;
}

/* Subscribe CTA: price on line 1, what you get on line 2. Two short lines keep
   the pill compact instead of wrapping one long sentence across the phone. */
.ig-btn-stack {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    line-height: 1.15;
    min-width: 0;
}

.ig-btn-stack .ig-btn-label {
    white-space: nowrap;
}

/* Second line of the Subscribe pill. Same trap as .ig-btn-label: a fixed
   --ink-soft went black-on-black. It dims by opacity off the inherited ink
   instead, so it stays a step quieter on a light button AND a dark one. */
.ig-btn-sub {
    color: inherit !important;
    /* A step quieter than the price above it, but still white enough to read on
       the black pill — 0.75 sat at a dull grey against that fill. */
    opacity: 0.88;
    font-size: 0.68rem;
    font-weight: 500;
    letter-spacing: 0.01em;
    white-space: nowrap;
}

.character-subscribe-btn {
    padding: 8px 16px;
    font-size: 0.85rem;
}

.ig-chat-btn {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 10px 20px;
    /* Brand fill -> brand ink. The old --ink label sat on the dark brand
       gradient the glass layer paints over this, so the CTA read as a black
       slab with no visible text. */
    background: var(--brand-gradient);
    color: var(--brand-ink) !important;
    border: none;
    border-radius: 10px;
    font-weight: 600;
    font-size: 0.9rem;
    cursor: pointer;
    text-decoration: none;
    transition: all 0.2s ease;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.06);
}

.ig-chat-btn:hover {
    background: var(--brand-gradient-hover);
    color: var(--brand-ink) !important;
    transform: scale(1.02);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.06);
}

.ig-chat-btn:active {
    transform: scale(0.98);
}

.ig-chat-btn i {
    font-size: 1.1rem;
}

.ig-secondary-btn {
    width: 44px;
    height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    color: var(--ig-text);
    border: 1px solid var(--ig-border);
    border-radius: 10px;
    font-size: 1.1rem;
    cursor: pointer;
    text-decoration: none;
    transition: all 0.2s;
    flex: 0 0 auto;
}

.ig-secondary-btn:hover {
    background: var(--glass);
    border-color: var(--ig-text);
    color: var(--ig-text);
}

.ig-secondary-btn:active {
    background: var(--glass-strong);
}

/* "Photo with me" — the one secondary action that sells THIS character, so it
   keeps a violet tint instead of being another anonymous icon square. The label
   is redundant (the button already carries title + aria-label), so it renders
   as a round camera icon and the text is left to assistive tech only. */
.ig-photo-btn {
    position: relative;
    width: 44px;
    padding: 0;
    border-radius: 50%;
    background: var(--scrim-soft);
    border-color: var(--line-strong);
    color: var(--ink);
}

.ig-photo-btn:hover {
    background: var(--scrim-soft);
    border-color: var(--line-strong);
    color: var(--ink);
}

.ig-photo-btn i {
    font-size: 1.1rem;
}

/* Kept in the DOM for screen readers / SEO, never painted. */
.ig-photo-label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* "free" corner badge — the first photo a visitor makes on the platform costs
   nothing, and this button is icon-only, so the offer needs its own mark to be
   visible at all. Server-rendered only while the free photo is still unspent
   (sceneFirstFree); it never appears again afterwards. */
.ig-photo-free {
    position: absolute;
    top: -6px;
    right: -8px;
    padding: 1px 6px;
    border-radius: 999px;
    background: linear-gradient(135deg, #1d8660, #16a34a);
    color: var(--ink);
    font-size: 9px;
    font-weight: 800;
    line-height: 1.6;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.16);
    pointer-events: none;
}

/* No .ig-photo-btn.is-locked variant: the button always goes to the studio,
   on paid characters too ("with me" is charged in coins, not by subscription),
   so it always keeps its violet "go" tint. */

/* "More actions" dropdown menu */
.ig-menu {
    position: relative;
    flex: 0 0 auto;
}

.ig-menu.open .ig-menu-toggle {
    background: var(--glass-strong);
    border-color: var(--ig-text);
}

.ig-menu-dropdown {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    min-width: 220px;
    max-height: 320px;
    overflow-y: auto;
    overflow-x: hidden;
    background: var(--ig-card, #e5e5e5);
    border: 1px solid var(--ig-border);
    border-radius: 12px;
    padding: 6px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.16);
    z-index: 1050;
    display: none;
    -webkit-overflow-scrolling: touch;
}

.ig-menu.open .ig-menu-dropdown {
    display: block;
}

.ig-menu-item {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 11px 12px;
    background: transparent;
    color: var(--ig-text);
    border: none;
    border-radius: 8px;
    font-size: 0.9rem;
    font-weight: 500;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
    transition: background 0.15s;
}

.ig-menu-item:hover {
    background: var(--glass-strong);
    color: var(--ig-text);
}

.ig-menu-item:active {
    background: var(--glass-strong);
}

.ig-menu-item i {
    font-size: 1.15rem;
    width: 22px;
    flex: 0 0 22px;
    text-align: center;
}

.ig-menu-item.favorited {
    color: #FFD700;
}

/* Character favorite button - special styling */
.character-favorite-btn {
    position: relative;
}

.character-favorite-btn.favorited {
    background: linear-gradient(135deg, rgba(255, 215, 0, 0.15) 0%, rgba(162, 122, 0, 0.15) 100%);
    border-color: rgba(255, 215, 0, 0.5);
    color: #FFD700;
}

.character-favorite-btn.favorited i {
    animation: starPulse 0.5s ease;
}

.character-favorite-btn:hover {
    background: var(--glass);
    border-color: var(--ig-text);
}

.character-favorite-btn.favorited:hover {
    background: linear-gradient(135deg, rgba(255, 215, 0, 0.25) 0%, rgba(162, 122, 0, 0.25) 100%);
    border-color: #FFD700;
}

/* Character follow button - special styling */
.character-follow-btn {
    position: relative;
}

.character-follow-btn.following {
    background: linear-gradient(135deg, rgba(76, 175, 80, 0.15) 0%, rgba(56, 142, 60, 0.15) 100%);
    border-color: rgba(76, 175, 80, 0.5);
    color: #4CAF50;
}

.character-follow-btn.following i {
    animation: bellRing 0.5s ease;
}

.character-follow-btn:hover {
    background: var(--glass);
    border-color: var(--ig-text);
}

.character-follow-btn.following:hover {
    background: linear-gradient(135deg, rgba(76, 175, 80, 0.25) 0%, rgba(56, 142, 60, 0.25) 100%);
    border-color: #4CAF50;
}

@keyframes bellRing {
    0%, 100% {
        transform: rotate(0deg);
    }
    25% {
        transform: rotate(-10deg);
    }
    50% {
        transform: rotate(10deg);
    }
    75% {
        transform: rotate(-10deg);
    }
}

@keyframes starPulse {
    0%, 100% {
        transform: scale(1);
    }
    50% {
        transform: scale(1.2);
    }
}

/* The admin floating action button used to live here. It was removed so the
   profile page carries exactly ONE floating control — the owner's "Add a new
   image / video" button (`.cpm-fab`, further down). The admin sheet below is
   now opened from "Admin actions" in the ⋮ menu. */

/* Admin Bottom Sheet */
.admin-sheet-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: var(--veil);
    z-index: 9998;
}
.admin-sheet-overlay.open {
    display: block;
}
.admin-sheet {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background: var(--surface-overlay);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    border-top-left-radius: 16px;
    border-top-right-radius: 16px;
    padding: 8px 16px 24px;
    z-index: 9999;
    transform: translateY(100%);
    transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1);
}
.admin-sheet.open {
    transform: translateY(0);
}
.admin-sheet-handle {
    width: 36px;
    height: 4px;
    border-radius: 2px;
    background: var(--scrim-soft);
    margin: 0 auto 12px;
}
.admin-sheet-title {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--ink-muted);
    padding: 0 4px 8px;
}
.admin-sheet-items {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.admin-sheet-item {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 14px 12px;
    border: none;
    background: transparent;
    color: var(--ink);
    font-size: 0.95rem;
    border-radius: 10px;
    cursor: pointer;
    transition: background 0.15s;
}
.admin-sheet-item:active {
    background: var(--glass-strong);
}
.admin-sheet-item i {
    font-size: 1.1rem;
    width: 24px;
    text-align: center;
}

/* "Character info" sheet — the admin provenance panel. Reuses the .admin-sheet
   shell (position, backdrop, slide-in) and only adds the definition-list rows. */
.admin-info-sheet {
    max-height: 80vh;
    overflow-y: auto;
}
.admin-info-list {
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.admin-info-row {
    display: flex;
    align-items: baseline;
    gap: 12px;
    padding: 10px 12px;
    border-radius: 10px;
}
.admin-info-row:nth-child(odd) {
    background: var(--glass-strong);
}
.admin-info-row dt {
    flex: 0 0 8.5rem;
    font-size: 0.8rem;
    font-weight: 500;
    color: var(--ink-muted);
}
.admin-info-row dd {
    margin: 0;
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.9rem;
    color: var(--ink);
    overflow-wrap: anywhere;
}
.admin-info-row code {
    font-size: 0.8rem;
    color: var(--ink-muted);
}
.admin-info-empty {
    color: var(--ink-muted);
    font-style: italic;
}
.admin-info-creator {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: inherit;
    text-decoration: none;
}
.admin-info-creator img {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    object-fit: cover;
    flex: 0 0 auto;
}
.admin-info-creator:hover span,
.admin-info-link:hover {
    text-decoration: underline;
}
.admin-info-creator i,
.admin-info-link i {
    font-size: 0.75rem;
    opacity: 0.6;
}
.admin-info-link {
    color: inherit;
    text-decoration: none;
}
.admin-info-badge {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--glass-strong);
    color: var(--ink-muted);
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

/* Tab Navigation */
.ig-tab-nav {
    display: flex;
    border-top: 1px solid var(--ig-border);
    background: var(--ig-bg);
}

.ig-tab {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Compact by default. The glass sheet turns this row into a full-bleed
       segmented rail (character-glass.css §4); these values keep the plain
       version the same height so the two never disagree. */
    padding: 10px 0;
    background: none;
    border: none;
    color: var(--ig-text-secondary);
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    position: relative;
    transition: color 0.2s;
}

.ig-tab.active {
    color: var(--ig-text);
}

.ig-tab.active::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 1px;
    background: var(--ig-text);
}

.ig-tab:active {
    opacity: 0.7;
}

/* Tab Content Areas */
.tab-content {
    background: var(--ig-bg);
    min-height: 200px;
}

.tab-pane {
    background: var(--ig-bg);
}

/* Keep old styles but update for dark theme compatibility */
/* Profile Header - Legacy (hidden) */
.profile-header {
    display: none;
}

.profile-cover {
    display: none;
}

.profile-actions {
    display: none;
}

.profile-stats {
    display: none;
}

.content-tabs {
    display: none;
}

/* Loading State for Count Displays */
.ig-stat-number.count-loading,
#imagesCount.count-loading,
#videosCount.count-loading,
#messagesCount.count-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 1.5rem;
}

.ig-stat-number.count-loading .spinner-border,
#imagesCount.count-loading .spinner-border,
#videosCount.count-loading .spinner-border,
#messagesCount.count-loading .spinner-border {
    width: 1rem;
    height: 1rem;
    border-width: 0.15em;
    color: var(--ig-text);
}

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

.spinner-border {
    display: inline-block;
    width: 1rem;
    height: 1rem;
    vertical-align: text-bottom;
    border: 0.2em solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: spin 0.75s linear infinite;
}

/* Initial Grid */
.character-grid-initial .gallery-card{
    display: inline-block;
}

/* Media Grid - Instagram Dark Theme */
.media-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 2px;
    padding: 0;
    background: var(--ig-bg);
}

/* Images tab stays default */

/* Unlock pill — floats over the gallery (sticky, bounded to the gallery area,
   not the full viewport) as a rounded glass pill matching the app design. */
.gallery-unlock-banner {
    position: sticky;
    bottom: 16px;
    z-index: 6;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    width: max-content;
    max-width: calc(100% - 24px);
    margin: 20px auto 10px;
    background: var(--veil-strong);
    -webkit-backdrop-filter: blur(16px) saturate(140%);
    backdrop-filter: blur(16px) saturate(140%);
    border: 1px solid rgba(114, 114, 114, 0.35);
    border-radius: 999px;
    padding: 8px 8px 8px 20px;
    box-shadow: 0 12px 34px rgba(0, 0, 0, 0.16);
    cursor: pointer;
    box-sizing: border-box;
}

.gallery-unlock-banner-text {
    color: var(--ink);
    font-size: 0.9rem;
    font-weight: 600;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.gallery-unlock-banner-btn {
    flex-shrink: 0;
    background: linear-gradient(135deg, #6c6c6c, #888888);
    color: var(--ink);
    border: none;
    border-radius: 999px;
    padding: 8px 18px;
    font-size: 0.85rem;
    font-weight: 700;
    cursor: pointer;
    white-space: nowrap;
    transition: filter 0.2s ease;
}

.gallery-unlock-banner-btn:hover {
    filter: brightness(1.1);
}

/* Premium character: the gallery is sold by the subscription, so the pill says
   so in full. The sentence is too long for the guest pill's single nowrap line
   on a phone, hence the wrapping, stacked variant. */
.gallery-unlock-banner.is-premium {
    flex-direction: column;
    gap: 10px;
    width: min(100%, 420px);
    border-radius: 20px;
    padding: 14px 18px;
    border-color: rgba(215, 137, 0, 0.45);
    background: var(--veil-strong);
    text-align: center;
}

.gallery-unlock-banner.is-premium .gallery-unlock-banner-btn {
    background: linear-gradient(135deg, #cc7400, #c42d00);
    padding: 12px 22px;
    width: 100%;
    white-space: normal;
    line-height: 1.35;
}

.ig-tier-access-section {
    margin: 0 16px 16px;
    padding: 18px;
    border-radius: 18px;
    background: linear-gradient(180deg, rgba(230, 230, 230, 0.96), rgba(237, 237, 237, 0.96));
    border: 1px solid rgba(0, 0, 0, 0.08);
}

.ig-tier-access-header {
    margin-bottom: 14px;
}

.ig-tier-access-title {
    margin: 0 0 6px;
    color: var(--ink);
    font-size: 1.1rem;
}

.ig-tier-access-copy,
.ig-tier-access-description {
    color: var(--ink-soft);
}

.ig-tier-access-state {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--ink-soft);
}

.ig-tier-access-grid {
    display: grid;
    gap: 12px;
}

.ig-tier-access-card {
    border-radius: 16px;
    padding: 16px;
    background: var(--glass);
    border: 1px solid rgba(0, 0, 0, 0.08);
}

.ig-tier-access-card.current {
    border-color: rgba(34, 197, 94, 0.45);
}

.ig-tier-access-card.highlight {
    border-color: rgba(175, 127, 3, 0.55);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.06);
}

.ig-tier-access-name-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.ig-tier-access-name-row h3 {
    margin: 0;
    font-size: 1rem;
    color: var(--ink);
}

.ig-tier-access-price {
    margin: 6px 0 0;
    color: var(--ink-soft);
    font-weight: 700;
}

.ig-tier-access-pill {
    display: inline-flex;
    align-items: center;
    padding: 4px 10px;
    border-radius: 999px;
    background: rgba(175, 127, 3, 0.14);
    color: #c99a03;
    font-size: 0.72rem;
    font-weight: 700;
}

.ig-tier-card-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin-top: 6px;
    border: none;
    border-radius: 12px;
    padding: 10px 14px;
    background: linear-gradient(135deg, #777777, #727272);
    color: var(--ink);
    text-decoration: none;
    font-weight: 700;
}

.ig-tier-card-btn.secondary {
    background: var(--glass-strong);
}

.ig-tier-card-btn:hover {
    color: var(--ink);
    text-decoration: none;
}

/* ─────────────────────────────────────────────────────────────
   Character albums — compact row + Albums tab
   The profile shows only the NEWEST album, as one row; the whole
   catalogue lives in #albums-tab using the very same row markup.
   Row height is fixed (~90px) so the module no longer grows with
   the creator's catalogue. See docs/CHARACTER_PROFILE_ALBUMS.md.
   ───────────────────────────────────────────────────────────── */
.char-album-section {
    margin: 0 16px 16px;
}

.char-album-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 4px 0 10px;
}

.char-album-h {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    color: var(--ink);
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
}

.char-album-h .bi-lock-fill {
    color: var(--ig-purple, #777777);
    font-size: 0.85rem;
}

.char-album-count {
    padding: 1px 8px;
    border-radius: 20px;
    background: var(--glass-strong);
    border: 1px solid var(--ig-border, #d9d9d9);
    color: var(--ink-soft);
    font-size: 0.7rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.char-album-more {
    margin-left: auto;
    padding: 4px 0;
    border: 0;
    background: none;
    color: var(--ig-purple, #777777);
    font-size: 0.79rem;
    font-weight: 600;
    cursor: pointer;
}

.char-album-more:hover {
    color: var(--ink-soft);
}

.char-album-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.char-album-row {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 9px;
    border: 1px solid var(--ig-border, #d9d9d9);
    border-radius: 14px;
    background: var(--ig-surface, #e5e5e5);
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: border-color 0.18s ease, background 0.18s ease;
}

.char-album-row:hover {
    border-color: var(--line-strong);
    background: var(--surface-sunken);
}

/* Square cover — the whole point of the redesign: a 16:10 hero
   became a 66px thumbnail. */
.char-album-cover {
    position: relative;
    display: block;
    flex: none;
    width: 66px;
    aspect-ratio: 1;
    border-radius: 10px;
    overflow: hidden;
    background: linear-gradient(135deg, rgba(119, 119, 119, 0.32), rgba(210, 210, 210, 0.92));
}

.char-album-cover.is-fallback::before {
    content: '\F2A9';
    font-family: bootstrap-icons;
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.4rem;
    color: var(--ink-disabled);
}

.char-album-cover-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.char-album-cover-lock {
    position: absolute;
    top: 5px;
    left: 5px;
    width: 20px;
    height: 20px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--veil-strong);
    border: 1px solid rgba(0, 0, 0, 0.22);
    color: var(--ink);
    font-size: 0.58rem;
}

.char-album-cover-n {
    position: absolute;
    right: 5px;
    bottom: 4px;
    padding: 1px 5px;
    border-radius: 5px;
    background: var(--veil-strong);
    color: var(--ink);
    font-size: 0.62rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.char-album-body {
    display: flex;
    flex: 1;
    min-width: 0;
    flex-direction: column;
    gap: 2px;
}

.char-album-title {
    display: flex;
    align-items: center;
    gap: 6px;
    color: var(--ink);
    font-size: 0.9rem;
    font-weight: 600;
    line-height: 1.25;
}

.char-album-title > span:first-child {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.char-album-nsfw {
    flex: none;
    padding: 0 4px;
    border: 1px solid rgba(244, 0, 59, 0.4);
    border-radius: 4px;
    background: rgba(244, 0, 59, 0.1);
    color: #f4003b;
    font-size: 0.58rem;
    font-weight: 800;
    letter-spacing: 0.05em;
}

.char-album-desc {
    color: var(--ink-soft);
    font-size: 0.775rem;
    line-height: 1.35;
    display: -webkit-box;
    -webkit-line-clamp: 1;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.char-album-foot {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 3px;
    font-variant-numeric: tabular-nums;
}

/* Albums are cash only — the card price IS the price, so it carries the
   prominent treatment the old coin chip used to have. `.char-album-coins` was
   removed with the coin purchase path. */
.char-album-usd {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--ink);
    font-size: 0.8rem;
    font-weight: 700;
}

.char-album-usd.is-unpriced {
    color: var(--ink-muted);
    font-size: 0.76rem;
    font-weight: 600;
}

.char-album-n {
    color: var(--ink-muted);
    font-size: 0.73rem;
}

/* Already bought: the row stops selling and starts opening. */
.char-album-owned {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    color: #288458;
    font-size: 0.78rem;
    font-weight: 700;
}

.char-album-row.is-owned {
    border-color: rgba(40, 132, 88, 0.32);
}

.char-album-row.is-owned .char-album-cover-lock {
    color: #288458;
}

.char-album-row.is-owned .char-album-unlock {
    border-color: rgba(40, 132, 88, 0.42);
    background: rgba(40, 132, 88, 0.14);
    color: #2aaf72;
}

/* Mobile keeps the chevron; desktop has room for a real button. */
.char-album-unlock {
    display: none;
    flex: none;
    padding: 6px 11px;
    border: 1px solid rgba(119, 119, 119, 0.42);
    border-radius: 8px;
    background: var(--scrim-soft);
    color: var(--ink-soft);
    font-size: 0.76rem;
    font-weight: 700;
}

.char-album-go {
    flex: none;
    padding-right: 4px;
    color: var(--ink-disabled);
    font-size: 0.95rem;
}

.char-album-note {
    margin: 9px 0 0;
    color: var(--ink-muted);
    font-size: 0.76rem;
}

.char-album-link {
    padding: 0;
    border: 0;
    background: none;
    color: var(--ink-muted);
    font: inherit;
    font-size: 0.76rem;
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 2px;
    cursor: pointer;
}

.char-album-link:hover {
    color: var(--ink-soft);
}

/* Albums tab pane */
.char-album-pane {
    padding: 16px;
}

.char-album-lead {
    margin: 0 0 14px;
    max-width: 56ch;
    color: var(--ink-soft);
    font-size: 0.83rem;
}

/* The tab button only appears when the character has albums; the dot
   marks it as the paid shelf without shouting. */
.ig-tab-albums .ig-tab-dot {
    position: absolute;
    top: 9px;
    left: 50%;
    margin-left: 9px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--ig-purple, #777777);
}

@media (min-width: 768px) {
    .char-album-list {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 10px;
    }

    .char-album-section .char-album-list {
        grid-template-columns: 1fr; /* the teaser is always a single album */
    }

    .char-album-cover {
        width: 76px;
    }

    .char-album-desc {
        -webkit-line-clamp: 2;
    }

    .char-album-unlock {
        display: block;
    }

    .char-album-go {
        display: none;
    }

    .char-album-pane {
        padding: 20px 24px;
    }
}

@media (max-width: 480px) {
    .char-album-section {
        margin: 0 12px 12px;
    }
}

/* ── Paid workspace offers (docs/PAID_WORKSPACE_OFFERS.md) ─────────────────
   Deliberately the SAME row component as an album: from the visitor's side
   both are "a thing this character sells", and giving them two layouts on one
   profile would read as two unrelated products rather than one shelf. Only
   what actually differs is restyled — an icon tile instead of a cover photo,
   and a price that can legitimately read "Free".
   `.char-album-section .char-album-list` is overridden back to the multi-column
   grid because, unlike the album teaser, EVERY offer is listed here (a creator
   with three workspaces wants all three seen). */
.char-offer-list.char-album-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.char-offer-cover {
    background: linear-gradient(135deg, rgba(109, 94, 252, 0.34), rgba(233, 84, 196, 0.30));
}

.char-offer-cover::before {
    content: '\F44B'; /* bootstrap-icons briefcase-fill */
    font-family: bootstrap-icons;
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.5rem;
    color: var(--ink);
    opacity: 0.75;
}

.char-album-usd.is-free {
    color: #22c55e;
}

@media (min-width: 768px) {
    .char-offer-list.char-album-list {
        display: grid;
        grid-template-columns: 1fr 1fr;
    }
}

.character-image-manage-note {
    color: var(--ink-soft);
    font-size: 0.82rem;
    margin-top: 6px;
}

.character-image-manage-section + .character-image-manage-section {
    margin-top: 18px;
    padding-top: 18px;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
}

.character-image-manage-actions {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
}

.character-image-manage-actions .btn {
    min-width: 140px;
}

.character-tier-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 14px;
    background: var(--veil-strong);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    z-index: 12;
    text-align: center;
}

.character-tier-overlay-title {
    color: var(--ink);
    font-weight: 700;
}

.character-tier-overlay-copy {
    color: var(--ink-soft);
    font-size: 0.82rem;
}

.character-tier-overlay-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    border: none;
    border-radius: 999px;
    padding: 8px 14px;
    background: linear-gradient(135deg, #777777, #727272);
    color: var(--ink);
    font-weight: 700;
}

@media (max-width: 400px) {
    /* Stay a rounded pill on narrow screens — just tighten spacing. */
    .gallery-unlock-banner {
        gap: 8px;
        padding: 6px 6px 6px 16px;
        max-width: calc(100% - 16px);
    }
    .gallery-unlock-banner-text {
        font-size: 0.82rem;
    }
    .gallery-unlock-banner-btn {
        padding: 7px 14px;
        font-size: 0.8rem;
    }

    .ig-tier-access-section {
        margin: 0 12px 12px;
        padding: 16px;
    }
}

/* PORTRAIT tiles, not square. Nearly everything generated here is 3:4 or
   taller, so a square cell cropped the subject out of its own thumbnail — the
   grid was a wall of chins and foreheads. A 3:4 cell shows a 3:4 generation
   whole and still covers (never letterboxes) anything wider.
   Keep .media-item, its img/video and .loading-item on the SAME ratio or the
   skeleton jumps when the real tile lands. */
.media-item {
    position: relative;
    overflow: hidden;
    background: var(--ig-surface);
    cursor: pointer;
    transition: opacity 0.2s ease;
    aspect-ratio: 3 / 4;
}

.media-item:active {
    opacity: 0.7;
}

.media-item img,
.media-item video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: top;
    aspect-ratio: 3 / 4;
}

/* Locked tile (logged-out visitor) — must fill the cell exactly like an
   unlocked one. The blurred poster arrives as a blob from /blur-image or
   /blur-video-preview, so there is nothing to reveal by stripping the filter. */
.locked-media-tile {
    position: absolute;
    inset: 0;
    overflow: hidden;
    background: var(--surface-sunken);
    cursor: pointer;
}

.locked-media-tile-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    filter: blur(16px);
    transform: scale(1.08);
}

.locked-media-tile-lock {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
    font-size: 1.5rem;
    color: var(--ink-soft);
    filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.16));
}

/* `.media-item-overlay` / `.media-item-info` lived here: a dark scrim + "🎞 n"
   counter that faded in on `:hover` over a video tile. Removed with the markup
   (renderPlayableVideoTile) — hover is a desktop gesture that a phone fires on
   the first tap, so it covered the clip instead of opening it, and the Images
   tab had already dropped its own hover chrome. Nothing renders these classes
   any more. */

.media-item-actions {
    position: absolute;
    top: 8px;
    right: 8px;
    display: flex;
    gap: 4px;
    opacity: 0;
    transition: opacity 0.2s ease;
    pointer-events: auto;
    z-index: 20;
}

.media-item:hover .media-item-actions {
    opacity: 1;
}

/* Gift badge — pinned to the top-left corner of gallery thumbnails */
.media-gift-badge {
    position: absolute;
    top: 7px;
    left: 7px;
    z-index: 15;
    background: var(--veil-strong);
    color: #e30036;
    border-radius: 50%;
    width: 26px;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.72rem;
    pointer-events: none;
    backdrop-filter: blur(4px);
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.16);
}

.media-action-btn {
    background: var(--veil-strong);
    border: none;
    border-radius: 50%;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.2s ease;
    color: var(--ink);
    font-weight: 600;
    pointer-events: auto;
    flex-shrink: 0;
    z-index: 30;
    backdrop-filter: blur(4px);
}

.media-action-btn:hover {
    background: var(--veil-strong);
}

.media-action-btn.liked,
.media-action-btn.image-fav.liked {
    color: #af111e;
}

.media-action-btn.admin-delete-image {
    color: #c80000;
}

.media-action-btn.admin-delete-image:hover {
    background: rgba(200, 0, 0, 0.8);
    color: var(--status-ink);
}

/* Admin toggle button within media actions */
.media-action-btn.gallery-admin-toggle {
    color: #af7f03;
    background: var(--veil);
}

.media-action-btn.gallery-admin-toggle:hover {
    background: var(--veil-strong);
    color: #c99a03;
}

/* The base .gallery-admin-toggle rule sets opacity:0 and only restores it for
   .gallery-card-item (dashboard) hover. On the character profile page the toggle
   lives inside .media-item, so restore its visibility on media-item hover too,
   otherwise the three-dots button stays invisible even though it's in the DOM. */
.media-item:hover .media-action-btn.gallery-admin-toggle,
.media-item:focus-within .media-action-btn.gallery-admin-toggle,
.media-item .gallery-admin-menu.open .media-action-btn.gallery-admin-toggle {
    opacity: 1;
}

/* Admin menu positioning within media-item.
   The toggle button lives inside this wrapper while the like button is a bare
   .media-action-btn sibling. Size the wrapper to exactly the 32×32 toggle and
   center its contents so the three-dots lines up flush with the like icon
   (no stray horizontal gap / offset) in the actions row/column. */
.media-item .gallery-admin-menu {
    position: relative;
    /* Reset the top/right offsets inherited from the base .gallery-admin-menu
       rule — on a position:relative element they'd shift the menu 8px left and
       8px down, knocking the three-dots button out of line with the Like button. */
    top: auto;
    right: auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    flex-shrink: 0;
}

/* Admin trash bin button — top-left corner, admin-only */
.gallery-admin-trash-btn {
    position: absolute;
    top: 8px;
    left: 8px;
    z-index: 20;
    width: 32px;
    height: 32px;
    border: none;
    border-radius: 50%;
    background: rgba(144, 25, 36, 0.82);
    color: var(--status-ink);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    cursor: pointer;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease, transform 0.15s ease, background 0.15s ease;
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.16);
}

.media-item:hover .gallery-admin-trash-btn {
    opacity: 1;
    pointer-events: auto;
}

.gallery-admin-trash-btn:hover {
    background: rgba(185, 28, 28, 0.95);
    transform: scale(1.1);
}

.gallery-admin-trash-btn:active {
    transform: scale(0.95);
}


.video-indicator {
    position: absolute;
    top: 8px;
    right: 8px;
    color: var(--ink);
    font-size: 1.2rem;
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.16));
}

/* Multiple images indicator */
.media-item .multi-indicator {
    position: absolute;
    top: 8px;
    right: 8px;
    color: var(--ink);
    font-size: 1rem;
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.16));
}

/* View count overlay on hover */
.media-item .view-count {
    display: flex;
    align-items: center;
    gap: 6px;
    color: var(--ink);
    font-size: 0.9rem;
    font-weight: 600;
}

.media-item video {
    display: block;
    background: var(--surface-page);
}

/* Similar Characters - Instagram Dark Theme */
.similar-section {
    padding: 20px 16px;
    border-top: 1px solid var(--ig-border);
    background: var(--ig-bg);
}

.similar-section h5 {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--ig-text);
    margin-bottom: 4px;
}

.similar-section .text-muted {
    font-size: 0.8rem;
    margin-bottom: 16px;
    color: var(--ig-text-secondary) !important;
}

.similar-grid {
    display: flex;
    gap: 16px;
    overflow-x: auto;
    padding-bottom: 8px;
    scrollbar-width: none;
    -ms-overflow-style: none;
}

.similar-grid::-webkit-scrollbar {
    display: none;
}

.similar-card {
    flex-shrink: 0;
    text-align: center;
    text-decoration: none;
    color: inherit;
    width: 70px;
}

.similar-avatar {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    object-fit: cover;
    margin: 0 auto 8px;
    display: block;
    border: 2px solid var(--ig-border);
    transition: all 0.2s ease;
}

.similar-card:active .similar-avatar {
    opacity: 0.7;
}

.similar-name {
    font-size: 0.7rem;
    font-weight: 500;
    color: var(--ig-text);
    line-height: 1.2;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Loading States - Dark Theme */
.loading-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 2px;
    padding: 0;
    width: 100%;
    grid-column: 1 / -1;
}

.loading-item {
    /* Same ratio as .media-item, or the skeleton resizes when the tile lands. */
    aspect-ratio: 3 / 4;
    background: linear-gradient(90deg, #e5e5e5 25%, #d5d5d5 50%, #e5e5e5 75%);
    background-size: 200% 100%;
    animation: shimmer 1.5s infinite;
}

@keyframes shimmer {
    0% { background-position: -200% 0; }
    100% { background-position: 200% 0; }
}

/* Character Details - Dark Theme */
.character-details {
    padding: 20px 16px;
    background: var(--ig-bg);
}

.character-details h5 {
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--ig-text);
    margin-bottom: 10px;
    margin-top: 16px;
}

.character-details h5:first-child {
    margin-top: 0;
}

.character-details p {
    color: var(--ig-text-secondary);
    line-height: 1.5;
    margin-bottom: 12px;
    font-size: 0.85rem;
}

/* Instagram-style About Container */
.ig-about-container {
    padding: 16px;
    background: var(--ig-bg);
}

.ig-attributes-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 12px;
    margin-bottom: 20px;
}

.ig-attribute-card {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px;
    background: var(--ig-surface);
    border-radius: 12px;
    border: 1px solid var(--ig-border);
}

.ig-attribute-icon {
    width: 40px;
    height: 40px;
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--ink);
    font-size: 1.1rem;
    flex-shrink: 0;
}

.ig-attribute-content {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.ig-attribute-label {
    font-size: 0.7rem;
    color: var(--ig-text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 2px;
}

.ig-attribute-value {
    font-size: 0.85rem;
    color: var(--ig-text);
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ig-nsfw-badge {
    color: #986206;
}

.ig-section-card {
    background: var(--ig-surface);
    border-radius: 12px;
    border: 1px solid var(--ig-border);
    padding: 16px;
    margin-bottom: 16px;
}

.ig-section-header {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 12px;
    color: var(--ig-text);
    font-weight: 600;
    font-size: 0.9rem;
}

.ig-section-header i {
    color: var(--ig-blue);
    font-size: 1.1rem;
}

.ig-section-text {
    color: var(--ig-text-secondary);
    font-size: 0.85rem;
    line-height: 1.6;
    margin: 0;
}

/* Owner-only "what the character remembers about itself" panel */
.char-memories-hint {
    color: var(--ig-text-secondary);
    font-size: 0.8rem;
    line-height: 1.5;
    margin: 0 0 12px;
}

.char-memories-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.char-mem-item {
    background: var(--ig-bg, rgba(255, 255, 255, 0.02));
    border: 1px solid var(--ig-border);
    border-radius: 10px;
    padding: 10px 12px;
}

.char-mem-item.is-pinned {
    border-color: var(--ig-blue);
}

.char-mem-title {
    display: flex;
    align-items: center;
    gap: 6px;
    color: var(--ig-text);
    font-weight: 600;
    font-size: 0.85rem;
    margin-bottom: 4px;
}

.char-mem-pin {
    color: var(--ig-blue);
    font-size: 0.8rem;
}

.char-mem-summary {
    color: var(--ig-text-secondary);
    font-size: 0.82rem;
    line-height: 1.5;
}

.char-mem-full {
    color: var(--ig-text-secondary);
    font-size: 0.82rem;
    line-height: 1.5;
    margin-top: 6px;
    white-space: pre-wrap;
}

.char-mem-more {
    background: none;
    border: none;
    padding: 2px 0;
    margin-top: 4px;
    color: var(--ig-blue);
    font-size: 0.78rem;
    font-weight: 600;
    cursor: pointer;
}

.char-mem-kws {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-top: 8px;
}

.char-mem-kw {
    background: var(--ig-border);
    color: var(--ig-text-secondary);
    border-radius: 6px;
    padding: 1px 7px;
    font-size: 0.72rem;
}

.ig-about-hero {
    margin-bottom: 18px;
}

.ig-about-name {
    color: var(--ig-text);
    font-size: 1.4rem;
    font-weight: 700;
    margin: 0 0 4px;
}

.ig-about-tagline {
    color: var(--ig-text-secondary);
    font-size: 0.9rem;
    line-height: 1.55;
    margin: 0;
}

.ig-first-message {
    margin-top: 14px;
    padding: 12px 14px;
    background: var(--ig-bg, #ffffff);
    border: 1px solid var(--ig-border);
    border-left: 3px solid var(--ig-blue);
    border-radius: 10px;
}

.ig-first-message-label {
    display: block;
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--ig-text-secondary);
    margin-bottom: 6px;
}

.ig-first-message-text {
    color: var(--ig-text);
    font-size: 0.88rem;
    line-height: 1.6;
    font-style: italic;
    margin: 0;
}

.ig-first-message-text::before { content: '\201C'; }
.ig-first-message-text::after { content: '\201D'; }

.ig-charsheet-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 12px;
}

.ig-charsheet-item {
    display: flex;
    flex-direction: column;
    gap: 6px;
    text-decoration: none;
    border-radius: 10px;
    overflow: hidden;
    background: var(--ig-bg, #ffffff);
    border: 1px solid var(--ig-border);
    transition: transform 0.15s ease;
}

.ig-charsheet-item:hover {
    transform: translateY(-2px);
}

.ig-charsheet-item img {
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    display: block;
}

.ig-charsheet-label {
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--ig-text-secondary);
    text-align: center;
    padding: 0 6px 8px;
}

.ig-charsheet-item {
    cursor: zoom-in;
}

/* Character sheet on-page previewer (lightbox) */
.charsheet-previewer {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: none;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 24px;
    background: var(--surface-overlay);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

.charsheet-previewer.open {
    display: flex;
}

body.charsheet-previewer-lock {
    overflow: hidden;
}

.charsheet-previewer-stage {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    max-width: 100%;
    max-height: 100%;
}

.charsheet-previewer-img {
    max-width: min(92vw, 1100px);
    max-height: 86vh;
    width: auto;
    height: auto;
    object-fit: contain;
    border-radius: 10px;
    box-shadow: 0 12px 48px rgba(0, 0, 0, 0.16);
}

.charsheet-previewer-caption {
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--ink-soft);
    text-align: center;
}

.charsheet-previewer-close,
.charsheet-previewer-nav {
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--glass-strong);
    border: 1px solid rgba(0, 0, 0, 0.18);
    color: var(--ink);
    border-radius: 999px;
    cursor: pointer;
    transition: background 0.15s ease;
}

.charsheet-previewer-close:hover,
.charsheet-previewer-nav:hover {
    background: var(--scrim-soft);
}

.charsheet-previewer-close {
    position: absolute;
    top: 18px;
    right: 18px;
    width: 40px;
    height: 40px;
    font-size: 1.1rem;
}

.charsheet-previewer-nav {
    flex: 0 0 auto;
    width: 44px;
    height: 44px;
    font-size: 1.3rem;
}

@media (max-width: 640px) {
    .charsheet-previewer {
        padding: 12px;
    }
    .charsheet-previewer-nav {
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
    }
    .charsheet-previewer-prev {
        left: 10px;
    }
    .charsheet-previewer-next {
        right: 10px;
    }
    .charsheet-previewer-img {
        max-width: 96vw;
        max-height: 80vh;
    }
}

.ig-tags-section {
    margin-top: 16px;
}

.ig-tags-title {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--ig-text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 12px;
}

.ig-tags-list {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.ig-tag {
    display: inline-flex;
    align-items: center;
    padding: 8px 14px;
    background: var(--ig-surface);
    border: 1px solid var(--ig-border);
    border-radius: 20px;
    color: var(--ig-blue);
    font-size: 0.8rem;
    font-weight: 500;
    text-decoration: none;
    transition: all 0.2s;
}

.ig-tag:active {
    background: var(--glass-strong);
}

.ig-tag i {
    font-size: 0.9rem;
    margin-right: 2px;
}

.character-personality-details {
    background-color: var(--ig-surface);
    border-radius: 12px;
    padding: 16px;
    margin-bottom: 16px;
    border: 1px solid var(--ig-border);
}

.personality-section {
    border: none !important;
    border-radius: 8px;
    overflow: hidden;
    background: var(--ig-surface);
}

.accordion-button {
    background: var(--ig-surface);
    color: var(--ig-text);
    font-weight: 600;
    border: none;
}

.accordion-button:not(.collapsed) {
    background: var(--ig-surface);
    color: var(--ig-blue);
}

.accordion-button:focus {
    box-shadow: none;
    border-color: var(--ig-border);
}

.section-title {
    color: var(--ig-text);
    padding: 12px 15px;
}

.accordion-body {
    padding: 15px;
    background-color: var(--ig-surface);
    color: var(--ig-text-secondary);
}

.tags-container {
    display: flex;
    flex-wrap: wrap;
}

.character-tag {
    background-color: var(--ig-surface);
    color: var(--ig-blue);
    border: 1px solid var(--ig-border);
    transition: all 0.2s ease;
    text-decoration: none;
    display: inline-block;
}

.character-tag:hover {
    background: var(--ig-blue);
    color: var(--brand-ink) !important;
}

.content-container {
    background: var(--ig-surface);
    border-radius: 6px;
    padding: 5px;
}

.btn.custom-gradient-bg {
    background: linear-gradient(90.9deg, #232323 2.74%, #777777 102.92%);
    border: none;
    color: var(--brand-ink);
    transition: all 0.3s ease;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.06);
}

.btn.custom-gradient-bg:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 12px rgba(0, 0, 0, 0.06);
}

/* Responsive adjustments for Instagram-style design */
@media (max-width: 1024px) {
    .media-grid {
        grid-template-columns: repeat(3, 1fr);
    }

    .loading-grid {
        grid-template-columns: repeat(3, 1fr);
    }
}

@media (max-width: 768px) {
    .ig-profile-info {
        padding: 12px 16px;
        gap: 16px;
    }

    .ig-avatar-ring {
        width: 77px;
        height: 77px;
    }

    .ig-avatar {
        width: 70px;
        height: 70px;
    }

    .ig-stat-number {
        font-size: 1rem;
    }

    .ig-stat-label {
        font-size: 0.7rem;
    }

    .ig-display-name {
        font-size: 0.95rem;
    }

    .ig-name-follow-btn {
        padding: 4px 11px;
        font-size: 0.72rem;
    }

    .ig-handle {
        font-size: 0.78rem;
    }

    .ig-bio {
        font-size: 0.8rem;
    }

    .ig-chat-btn {
        padding: 9px 16px;
        font-size: 0.85rem;
    }

    /* Phone: the subscribe pill shrinks a notch further so the price line, the
       feature line and the two round buttons all fit on one row. */
    .character-subscribe-btn {
        padding: 7px 12px;
        font-size: 0.8rem;
    }

    .ig-btn-sub {
        font-size: 0.63rem;
    }

    .media-grid {
        grid-template-columns: repeat(3, 1fr);
        gap: 2px;
        padding: 0;
    }

    .loading-grid {
        grid-template-columns: repeat(3, 1fr);
        gap: 2px;
        padding: 0;
    }

    .ig-tab {
        padding: 10px 0;
        font-size: 1.1rem;
    }

    .container-fluid.px-0 {
        margin-top: 0 !important;
        padding-top: 0 !important;
    }

    /* Hide legacy elements */
    .profile-header,
    .profile-cover,
    .profile-actions,
    .profile-stats,
    .content-tabs {
        display: none !important;
    }
}

@media (max-width: 480px) {
    .ig-top-bar {
        padding: 10px 12px;
    }

    .ig-username {
        font-size: 0.95rem;
    }

    .ig-profile-info {
        padding: 12px;
        gap: 12px;
    }

    .ig-avatar-ring {
        width: 70px;
        height: 70px;
    }

    .ig-avatar {
        width: 64px;
        height: 64px;
        border-width: 2px;
    }

    .ig-stats-row {
        gap: 4px;
    }

    .ig-stat-number {
        font-size: 0.95rem;
    }

    .ig-stat-label {
        font-size: 0.65rem;
    }

    .ig-bio-section {
        padding: 0 12px 10px;
    }

    .ig-display-name {
        font-size: 0.95rem;
    }

    .ig-name-follow-btn {
        padding: 4px 11px;
        font-size: 0.72rem;
    }

    .ig-handle {
        font-size: 0.78rem;
    }

    .ig-bio {
        font-size: 0.8rem;
        -webkit-line-clamp: 2;
    }

    .ig-presence {
        font-size: 0.68rem;
    }

    .ig-tagline {
        font-size: 0.72rem;
    }

    .ig-action-row {
        padding: 10px 12px;
        gap: 6px;
    }

    /* Keep the primary "Start chatting" button full-width with its label;
       secondary actions stay icon-only squares. */
    .ig-action-row .ig-chat-btn {
        flex: 1;
        border-radius: 8px;
    }

    .ig-secondary-btn {
        width: 38px;
        height: 38px;
        border-radius: 8px;
        font-size: 1rem;
    }

    /* Round camera icon, matched to the smaller phone-sized secondary buttons. */
    .ig-photo-btn {
        width: 38px;
        padding: 0;
        border-radius: 50%;
    }

    .ig-photo-btn i {
        font-size: 1rem;
    }

    .ig-tab {
        padding: 10px 0;
        font-size: 1.1rem;
    }

    .media-grid {
        grid-template-columns: repeat(3, 1fr);
        gap: 1px;
    }

    .loading-grid {
        grid-template-columns: repeat(3, 1fr);
        gap: 1px;
    }

    .ig-attributes-grid {
        grid-template-columns: 1fr;
        gap: 10px;
    }

    .ig-attribute-card {
        padding: 12px;
    }

    .ig-attribute-icon {
        width: 36px;
        height: 36px;
        font-size: 1rem;
    }

    .similar-section {
        padding: 16px 12px;
    }

    .similar-grid {
        gap: 12px;
    }

    .similar-avatar {
        width: 56px;
        height: 56px;
    }

    .similar-card {
        width: 60px;
    }

    .similar-name {
        font-size: 0.65rem;
    }
}

/* Gallery Section */
.gallery-section {
    padding: 20px 0;
    background: var(--ig-bg);
}

.gallery-section h3 {
    text-align: center;
    margin-bottom: 20px;
    color: var(--text-primary);
}

.gallery-section .text-muted {
    text-align: center;
    margin-bottom: 20px;
}

/* Character Gallery for non-specific character pages */
.character-gallery {
    padding: 40px 20px;
    background: var(--bg-secondary);
}

.character-gallery h2 {
    text-align: center;
    margin-bottom: 30px;
    background: var(--primary-gradient);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

.category-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 20px;
    margin-bottom: 40px;
}

.category-card {
    background: var(--bg-primary);
    border-radius: 12px;
    padding: 20px;
    text-align: center;
    box-shadow: var(--shadow-md);
    transition: transform 0.3s ease, box-shadow 0.3s ease;
    cursor: pointer;
}

.category-card:hover {
    transform: translateY(-5px);
    box-shadow: var(--shadow-lg);
}

.category-card h4 {
    color: var(--primary-color);
    margin-bottom: 10px;
}

.character-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 20px;
}

.character-card {
    background: var(--bg-primary);
    border-radius: 12px;
    padding: 15px;
    text-align: center;
    box-shadow: var(--shadow-sm);
    transition: all 0.3s ease;
    text-decoration: none;
    color: inherit;
}

.character-card:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-md);
    text-decoration: none;
    color: inherit;
}

.character-card img {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    object-fit: cover;
    margin-bottom: 10px;
}

.character-card h5 {
    margin-bottom: 5px;
    color: var(--text-primary);
}

.character-card p {
    color: var(--text-secondary);
    font-size: 0.9rem;
    margin: 0;
}

.sticky-bottom, .grid-control {
    display: none;
}

/* Load More Button Styling */
.load-more-container {
    display: flex;
    justify-content: center;
    padding: 24px 12px;
    grid-column: 1 / -1;
}

.load-more-btn {
    padding: 12px 32px;
    font-size: 0.95rem;
    font-weight: 600;
    border-radius: 28px;
    border: none;
    background: linear-gradient(135deg, #6e6e6e, #6f6f6f);
    color: var(--brand-ink);
    cursor: pointer;
    transition: all 0.3s ease;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.06);
    display: flex;
    align-items: center;
    gap: 8px;
}

.load-more-btn:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.06);
}

.load-more-btn:active {
    transform: translateY(-1px);
}

.load-more-btn:disabled {
    opacity: 0.7;
    cursor: not-allowed;
    transform: none;
}

/* Spinner styling for load more button */
.load-more-btn .spinner-border {
    width: 1rem;
    height: 1rem;
    border-width: 0.2em;
    color: var(--brand-ink);
}

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

.spinner-border {
    display: inline-block;
    width: 1rem;
    height: 1rem;
    vertical-align: text-bottom;
    border: 0.25em solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: spin 0.75s linear infinite;
}

/* Image Modal Styles - Full-Screen with Overlay Footer */

/* Override Bootstrap modal dialog for full-screen */
.modal.fade .modal-dialog.image-modal-dialog {
    margin: 0;
    width: 100%;
    height: calc(var(--vh, 1vh) * 100);
    height: 100dvh;
    max-width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}

.image-modal-content {
    background: var(--surface-page);
    border: none;
    border-radius: 0;
    box-shadow: none;
    overflow: hidden;
    width: 100%;
    height: calc(var(--vh, 1vh) * 100);
    height: 100dvh;
    max-height: calc(var(--vh, 1vh) * 100);
    max-height: 100dvh;
    display: flex;
    flex-direction: column;
    position: relative;
}

/* Image Body - Full viewport */
.image-modal-body {
    padding: 0;
    background: var(--surface-page);
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 1;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 100%;
    overflow: hidden;
}

.image-modal-img {
    width: 100%;
    height: 100%;
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    border-radius: 0;
    display: block;
    background: var(--surface-page);
}

/* Modal Header - Close Button Only */
.image-modal-header {
    background: none;
    color: inherit;
    padding: 0;
    border-bottom: none;
    display: flex;
    justify-content: flex-end;
    align-items: flex-start;
    position: fixed;
    top: 16px;
    right: 24px;
    z-index: 1055;
    width: auto;
    pointer-events: auto;
}

.image-modal-header .btn-close {
    background: linear-gradient(135deg, #232323 0%, #777777 100%);
    border: none;
    border-radius: 50%;
    width: 48px;
    height: 48px;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0.95;
    transition: all 0.3s ease;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.06);
    flex-shrink: 0;
    cursor: pointer;
}

.image-modal-header .btn-close::after {
    content: '✕';
    position: absolute;
    font-size: 1.5rem;
    color: var(--brand-ink);
    font-weight: 300;
    letter-spacing: 2px;
}

.image-modal-header .btn-close:hover {
    opacity: 1;
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.06);
    transform: scale(1.1);
}

.image-modal-header .btn-close:active {
    transform: scale(0.95);
}

/* Info Section - White Footer */
.image-modal-footer {
    background: var(--scrim-strong);
    border-top: 1px solid var(--line-strong);
    padding: 5px 24px 5px 24px;
    display: flex;
    flex-direction: column;
    gap: 16px;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 1050;
    width: 100%;
    max-height: auto;
    overflow-y: auto;
    overflow-x: hidden;
}

.image-modal-info {
    display: flex;
    flex-direction: column;
    gap: 12px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
    padding-bottom: 16px;
}

.image-modal-title-section {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.image-modal-title {
    margin: 0;
    font-size: 1.1rem;
    font-weight: 800;
    color: var(--ink-inverse);
    word-break: break-word;
    line-height: 1.5;
    letter-spacing: -0.3px;
    cursor: pointer;
    user-select: text;
    transition: all 0.3s ease;
}

.image-modal-title .title-toggle {
    font-size: 0.8rem;
    color: var(--ink-muted);
    font-weight: 500;
    margin-left: 4px;
    display: inline;
}

.image-modal-date {
    margin: 0;
    font-size: 0.8rem;
    color: var(--ink-muted);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

/* Action Buttons - Icon Only, Smaller */
.image-modal-actions {
    display: flex;
    gap: 12px;
    justify-content: flex-start;
    flex-wrap: wrap;
    align-items: center;
    width: 100%;
    margin-bottom: 4px;
}

.image-modal-action-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 8px 8px;
    border: none;
    background: transparent;
    color: var(--ink-muted);
    border-radius: 6px;
    font-weight: 600;
    font-size: 0.9rem;
    cursor: pointer;
    transition: all 0.3s ease;
    box-shadow: none;
    width: 36px;
    height: 36px;
    flex: 0 0 auto;
}

.image-modal-action-btn i {
    font-size: 1.4rem;
    transition: all 0.3s ease;
    margin: 0;
}

.image-modal-action-btn:hover {
    background: var(--brand-fill);
    color: var(--ink-inverse);
    transform: scale(1.1);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

.image-modal-action-btn:active {
    transform: scale(0.95);
}

/* Like button - Simple Gray */
.image-modal-like-btn {
    background: transparent;
    color: var(--ink-soft);
}

.image-modal-like-btn:hover {
    background: #f83232;
    color: #350505;
}

.image-modal-like-btn.liked {
    background: transparent;
    color: #af0f0f;
}

.image-modal-like-btn.liked i {
    animation: heartBeat 0.6s ease-in-out;
}


/* Responsive design for full-width modals */
@media (max-width: 1024px) {
    .image-modal-content {
        height: calc(var(--vh, 1vh) * 100);
    height: 100dvh;
        border-radius: 0;
    }
    
    .modal.fade .modal-dialog.image-modal-dialog {
        height: calc(var(--vh, 1vh) * 100);
    height: 100dvh;
    }
    
    .image-modal-body {
        flex: 1;
        min-height: 55vh;
    }
    
    .image-modal-footer {
        padding: 24px 20px;
        gap: 20px;
    }
    
    .image-modal-title {
        font-size: 1rem;
    }
    
    .image-modal-action-btn {
        padding: 11px 20px;
        font-size: 0.85rem;
        min-width: 110px;
    }
}

@media (max-width: 1024px) {
    .image-modal-header .btn-close {
        width: 44px;
        height: 44px;
    }
    
    .image-modal-footer {
        padding: 50px 24px 24px 24px;
    }
    
    .image-modal-title {
        font-size: 1rem;
    }
    
    .image-modal-action-btn {
        padding: 11px 20px;
        font-size: 0.85rem;
        min-width: 110px;
    }
}

@media (max-width: 768px) {
    .image-modal-header {
        padding: 12px 16px;
    }
    
    .image-modal-header .btn-close {
        width: 40px;
        height: 40px;
        box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
    }
    
    .image-modal-footer {
        padding: 40px 20px 20px 20px;
        gap: 16px;
    }
    
    .image-modal-title {
        font-size: 0.95rem;
    }
    
    .image-modal-date {
        font-size: 0.75rem;
    }
    
    .image-modal-action-btn {
        padding: 10px 18px;
        font-size: 0.8rem;
        min-width: 100px;
        gap: 8px;
    }
    
    .image-modal-action-btn i {
        font-size: 1.1rem;
    }
    
    .image-modal-actions {
        gap: 10px;
    }
}

@media (max-width: 480px) {
    .image-modal-header {
        padding: 10px 12px;
    }
    
    .image-modal-header .btn-close {
        width: 36px;
        height: 36px;
        box-shadow: 0 3px 12px rgba(0, 0, 0, 0.06);
    }
    
    .image-modal-footer {
        padding: 5px 16px 0px 16px;
        gap: 12px;
    }

    .image-modal-info {
        gap: 10px;
        padding-bottom: 12px;
    }
    
    .image-modal-title {
        font-size: 0.9rem;
        line-height: 1.4;
    }
    
    .image-modal-date {
        font-size: 0.7rem;
    }
    
    .image-modal-action-btn {
        padding: 8px 8px;
        font-size: 0.75rem;
        flex: 0 0 auto;
        min-width: auto;
        width: 32px;
        height: 32px;
    }
    
    .image-modal-action-btn i {
        font-size: 1.2rem;
    }
    
    .image-modal-actions {
        gap: 8px;
        flex-direction: row;
        margin-bottom: 2px;
    }
}

/* Empty State Styling for Dark Theme */
.empty-state,
.no-content {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 40px 20px;
    text-align: center;
    color: var(--ig-text-secondary);
    grid-column: 1 / -1;
}

.empty-state i,
.no-content i {
    font-size: 3rem;
    margin-bottom: 16px;
    color: var(--ig-text-secondary);
    opacity: 0.5;
}

.empty-state p,
.no-content p {
    font-size: 0.9rem;
    color: var(--ig-text-secondary);
    margin: 0;
}

/* Ensure text colors in character profile */
#characterProfilePage h1,
#characterProfilePage h2,
#characterProfilePage h3,
#characterProfilePage h4,
#characterProfilePage h5,
#characterProfilePage h6 {
    color: var(--ig-text);
}

#characterProfilePage p,
#characterProfilePage span,
#characterProfilePage small {
    color: var(--ig-text-secondary);
}

/* Override Bootstrap text utilities for dark theme */
#characterProfilePage .text-muted {
    color: var(--ig-text-secondary) !important;
}

#characterProfilePage .text-dark {
    color: var(--ig-text) !important;
}

/* Hide footer toolbar on character page */
#characterProfilePage ~ #footer-toolbar,
body:has(.ig-profile-header) #footer-toolbar {
    display: none !important;
}

/* Character Page Header Navigation Styling */
body:has(.ig-profile-header) #mainNav {
    background: transparent !important;
    backdrop-filter: none;
}

body:has(.ig-profile-header) .brand-logo i {
    color: var(--text-primary) !important;
}

body:has(.ig-profile-header) #avatarMenuBtn {
    width: 32px !important;
    height: 32px !important;
    border: 2px solid var(--primary-color) !important;
    box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.06) !important;
}

body:has(.ig-profile-header) .nav-icon-btn {
    background: var(--bg-secondary) !important;
    border: 1px solid var(--border-color) !important;
    color: var(--text-primary) !important;
    width: 36px;
    height: 36px;
    border-radius: 50% !important;
}

body:has(.ig-profile-header) .nav-icon-btn:hover {
    background: var(--scrim-soft) !important;
    border-color: var(--primary-color) !important;
    color: var(--primary-light) !important;
}

body:has(.ig-profile-header) .dropdown-toggle {
    background: var(--bg-secondary) !important;
    border: 1px solid var(--border-color) !important;
    color: var(--text-primary) !important;
    border-radius: 50% !important;
    width: 36px;
    height: 36px;
    padding: 0 !important;
    display: flex;
    align-items: center;
    justify-content: center;
}

body:has(.ig-profile-header) .dropdown-toggle::after {
    display: none;
}

body:has(.ig-profile-header) .dropdown-toggle:hover {
    background: var(--scrim-soft) !important;
    border-color: var(--primary-color) !important;
}

/* ===== Image Preview Modal - TikTok-style Action Buttons ===== */
#characterImagePreviewModal .character-preview-actions {
    position: absolute;
    right: 16px;
    bottom: 100px;
    display: flex;
    flex-direction: column;
    gap: 16px;
    z-index: 1000;
}

#characterImagePreviewModal .character-preview-actions .tiktok-action-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    background: var(--scrim-soft);
    backdrop-filter: blur(10px);
    border: 1px solid rgba(0, 0, 0, 0.2);
    border-radius: 50%;
    width: 50px;
    height: 50px;
    color: var(--ink);
    cursor: pointer;
    transition: all 0.3s ease;
    flex-shrink: 0;
}

#characterImagePreviewModal .character-preview-actions .tiktok-action-btn .action-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 24px;
}

#characterImagePreviewModal .character-preview-actions .tiktok-action-btn:hover {
    background: var(--scrim-soft);
    transform: scale(1.1);
}

#characterImagePreviewModal .character-preview-actions .tiktok-action-btn:active {
    transform: scale(0.95);
}

/* Heart button specific styling */
#characterImagePreviewModal .character-preview-actions .heart-btn {
    background: var(--scrim-soft);
    border-color: var(--line-strong);
}

#characterImagePreviewModal .character-preview-actions .heart-btn:hover {
    background: var(--scrim-soft);
}

#characterImagePreviewModal .character-preview-actions .heart-btn.liked .action-icon i {
    color: var(--ink-muted);
}

#characterImagePreviewModal .character-preview-actions .heart-btn.liked {
    background: var(--scrim-soft);
}

/* Chat button */
#characterImagePreviewModal .character-preview-actions .chat-btn {
    background: var(--scrim-soft);
    border-color: var(--line-strong);
}

#characterImagePreviewModal .character-preview-actions .chat-btn:hover {
    background: var(--scrim-soft);
}

/* ===== Image Preview Modal Full Screen on Mobile ===== */
@media (max-width: 768px) {
    #characterImagePreviewModal .modal-dialog {
        max-width: 100%;
        height: 100vh;
        margin: 0;
    }
    
    #characterImagePreviewModal .modal-content {
        height: 100vh;
        border-radius: 0;
    }
    
    #characterImagePreviewModal .modal-body {
        height: 100vh !important;
        padding: 0 !important;
    }
    
    /* Hide pagination on small screens */
    #characterImagePreviewModal .swiper-pagination {
        display: none !important;
    }
    
    /* Adjust close button for mobile */
    #characterImagePreviewModal .modal-header {
        top: 0 !important;
    }
    
    #characterImagePreviewModal .btn-close {
        background-color: var(--veil);
    }
}

/* SFW/NSFW Content Type Toggle */
.content-type-toggle {
    display: flex;
    justify-content: center;
    gap: 8px;
    padding: 12px 16px;
    background: var(--ig-bg);
    border-bottom: 1px solid var(--ig-border);
}

/* Toggle Switch (match profile/posts) */
.ig-toggle {
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
}

.ig-toggle input {
    display: none;
}

.ig-toggle-slider {
    width: 36px;
    height: 20px;
    background: var(--fill-mid-soft);
    border-radius: 20px;
    position: relative;
    transition: background 0.2s ease;
}

.ig-toggle-slider::after {
    content: '';
    position: absolute;
    top: 2px;
    left: 2px;
    width: 16px;
    height: 16px;
    background: var(--on-media-ink);
    border-radius: 50%;
    transition: transform 0.2s ease;
}

/* One switch look app-wide: green track, white knob (docs/DESIGN_SYSTEM.md #9). */
.ig-toggle input:checked + .ig-toggle-slider {
    background: var(--status-success);
}

.ig-toggle input:checked + .ig-toggle-slider::after {
    transform: translateX(16px);
}

.ig-toggle-label {
    font-size: 0.85rem;
    color: var(--ig-text-secondary);
}

.content-type-btn {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 16px;
    background: transparent;
    border: 1px solid var(--ig-border);
    border-radius: 8px;
    color: var(--ig-text-secondary);
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.2s ease;
}

.content-type-btn i {
    font-size: 16px;
}

.content-type-btn:hover {
    background: var(--ig-surface);
    border-color: var(--ig-text-secondary);
}

.content-type-btn.active {
    background: var(--ig-purple);
    border-color: var(--ig-purple);
    color: var(--brand-ink);
}

.content-type-btn.active:hover {
    background: var(--ig-purple);
    opacity: 0.9;
}

@media (max-width: 480px) {
    .content-type-toggle {
        padding: 10px 12px;
    }
    
    .content-type-btn {
        padding: 6px 12px;
        font-size: 13px;
    }
    
    .content-type-btn i {
        font-size: 14px;
    }
    
    .content-type-btn span {
        display: inline;
    }
}

@media (max-width: 480px) {
    #characterImagePreviewModal .character-preview-actions {
        right: 12px;
        bottom: 80px;
        gap: 12px;
    }
    
    #characterImagePreviewModal .character-preview-actions .tiktok-action-btn {
        width: 44px;
        height: 44px;
    }
    
    #characterImagePreviewModal .character-preview-actions .tiktok-action-btn .action-icon {
        font-size: 20px;
    }
}

/* ==========================================
   Image Gallery Grid - Masonry Layout
   ========================================== */
.image-gallery-grid {
    position: relative;
    width: 100%;
    padding: 4px;
    background: var(--ig-bg, #ffffff);
    min-height: 200px;
}

/* Gallery Card Item */
.gallery-card-item {
    position: absolute;
    overflow: hidden;
    border-radius: 6px;
    background: var(--ig-surface, #dbdbdb);
    transition: transform 0.3s ease, opacity 0.3s ease;
}

@media (max-width: 479px) {
    .gallery-card-item {
        border-radius: 12px;
    }
}

.gallery-card-inner {
    position: relative;
    width: 100%;
}

/* Image container */
.gallery-card-image {
    position: relative;
    width: 100%;
    overflow: hidden;
    cursor: pointer;
}

.gallery-card-image img {
    width: 100%;
    height: auto;
    object-fit: cover;
    object-position: center top;
    transition: transform 0.35s cubic-bezier(0.23, 1, 0.32, 1),
                filter 0.3s ease;
    display: block;
}

.gallery-card-item:hover .gallery-card-image img:not(.img-blur) {
    transform: scale(1.04);
    filter: brightness(1.05);
}

.gallery-card-image img.img-blur {
    filter: blur(18px) brightness(0.7);
    transform: scale(1.1);
}

/* NSFW Blur Wrapper with Premium Unlock CTA */
.gallery-nsfw-blur-wrapper {
    position: relative;
    cursor: pointer;
    overflow: hidden;
}

.gallery-premium-unlock-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    z-index: 5;
    pointer-events: none;
}

.gallery-premium-unlock-overlay i {
    font-size: 1.5rem;
    color: var(--ink);
    opacity: 0.9;
    margin-bottom: 6px;
    text-shadow: 0 2px 8px rgba(0, 0, 0, 0.16);
}

.gallery-premium-unlock-text {
    color: var(--ink);
    font-size: 0.65rem;
    font-weight: 600;
    text-align: center;
    line-height: 1.3;
    padding: 0 8px;
    text-shadow: 0 1px 4px rgba(0, 0, 0, 0.16);
}

/* Overlay Actions Container */
.gallery-card-actions {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    padding: 8px;
    background: linear-gradient(to top, rgba(255, 255, 255, 0.55) 0%, rgba(255, 255, 255, 0) 100%);
    opacity: 0;
    transition: opacity 0.25s ease;
    z-index: 10;
    pointer-events: none;
}

.gallery-card-item:hover .gallery-card-actions,
.gallery-card-item:focus-within .gallery-card-actions {
    opacity: 1;
}

/* On mobile, always show actions */
@media (hover: none) {
    .gallery-card-actions {
        opacity: 1;
        background: linear-gradient(to top, rgba(255, 255, 255, 0.45) 0%, rgba(255, 255, 255, 0) 100%);
    }
}

.gallery-actions-left,
.gallery-actions-right {
    display: flex;
    align-items: center;
    gap: 6px;
    pointer-events: auto;
}

/* Overlay Buttons - Shared */
.gallery-overlay-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    border: none;
    background: var(--veil);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    color: var(--ink);
    font-size: 1rem;
    cursor: pointer;
    transition: all 0.2s ease;
    flex-shrink: 0;
    padding: 0;
    outline: none;
}

.gallery-overlay-btn:hover {
    background: var(--veil-strong);
    transform: scale(1.1);
}

.gallery-overlay-btn:active {
    transform: scale(0.95);
}

/* Like Button */
.gallery-like-btn.liked {
    color: #c30021;
    background: rgba(195, 0, 33, 0.2);
}

.gallery-like-btn.liked:hover {
    background: rgba(195, 0, 33, 0.35);
}

.gallery-like-btn.liked i {
    animation: likePopIn 0.35s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

@keyframes likePopIn {
    0% { transform: scale(0.5); }
    50% { transform: scale(1.3); }
    100% { transform: scale(1); }
}

/* Add to Chat Button */
.gallery-addchat-btn {
    background: var(--scrim);
}

.gallery-addchat-btn:hover {
    background: var(--scrim-strong);
}

/* ==========================================
   Admin Dropdown Menu (on images)
   ========================================== */
.gallery-admin-menu {
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 11;
    pointer-events: auto;
}

.gallery-admin-toggle {
    background: var(--veil);
    color: var(--ink-soft);
    opacity: 0;
    transition: opacity 0.25s ease, background 0.2s ease, transform 0.2s ease;
}

.gallery-card-item:hover .gallery-admin-toggle,
.gallery-card-item:focus-within .gallery-admin-toggle,
.gallery-admin-menu.open .gallery-admin-toggle {
    opacity: 1;
    color: var(--ink);
}

@media (hover: none) {
    .gallery-admin-toggle {
        opacity: 1;
    }
}

.gallery-admin-toggle:hover {
    background: var(--veil-strong);
}

/* Portal dropdown rendered in document.body — styled here for specificity */
#gallery-dropdown-portal,
.gallery-admin-dropdown {
    min-width: 190px;
    background: var(--surface-overlay);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border-radius: 10px;
    border: 1px solid rgba(0, 0, 0, 0.12);
    padding: 4px;
    display: none;
    z-index: 99999;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.16);
    animation: adminDropdownIn 0.18s ease;
}

#gallery-dropdown-portal {
    display: block; /* portal is always shown when present */
    position: fixed;
}

@keyframes adminDropdownIn {
    from {
        opacity: 0;
        transform: translateY(6px) scale(0.96);
    }
    to {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
}

/* Source dropdown hidden — only the portal clone is shown */
.gallery-admin-menu.open .gallery-admin-dropdown {
    display: none;
}

.gallery-admin-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 8px 12px;
    border: none;
    background: transparent;
    color: var(--ink-soft);
    font-size: 0.8rem;
    border-radius: 6px;
    cursor: pointer;
    transition: background 0.15s ease;
    white-space: nowrap;
}

.gallery-admin-item:hover {
    background: var(--glass-strong);
}

.gallery-admin-item i {
    font-size: 0.9rem;
    width: 18px;
    text-align: center;
    flex-shrink: 0;
}

.gallery-admin-item.nsfw i {
    color: #d50b0b;
}

.gallery-admin-item.sfw i {
    color: #1d8660;
}

/* Like state in dropdown */
.gallery-admin-item.image-fav.liked {
    color: #c30021;
}

.gallery-admin-item.image-fav.liked i {
    color: #c30021;
}

.gallery-admin-item.image-fav.liked:hover {
    background: rgba(195, 0, 33, 0.15);
}

/* Close admin dropdown when clicking outside */
.gallery-card-item .gallery-admin-menu.open::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: -1;
}

/* ========================================
   GALLERY IMAGE PREVIEW MODAL (Instagram-style with comments)
   ======================================== */

.gallery-preview-dialog {
    max-width: 1100px;
    width: 95vw;
    margin: 1rem auto;
}

.gallery-preview-content {
    background: var(--surface-sunken);
    border: 1px solid rgba(0, 0, 0, 0.1);
    border-radius: 12px;
    overflow: hidden;
    position: relative;
    max-height: 90vh;
}

.gallery-preview-close {
    position: absolute;
    top: 12px;
    right: 12px;
    z-index: 10;
    opacity: 0.8;
    filter: invert(1);
    transition: opacity 0.2s;
}

.gallery-preview-close:hover {
    opacity: 1;
}

.gallery-preview-layout {
    display: flex;
    flex-direction: row;
    height: 85vh;
    max-height: 85vh;
}

/* Media side */
.gallery-preview-media {
    flex: 1 1 55%;
    min-width: 0;
    background: var(--surface-page);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    position: relative;
}

/* Character link overlay */
.gallery-preview-character-link {
    position: absolute;
    bottom: 12px;
    left: 12px;
    display: flex;
    align-items: center;
    gap: 8px;
    background: var(--veil-strong);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    padding: 6px 12px 6px 6px;
    border-radius: 24px;
    text-decoration: none;
    color: var(--ink);
    transition: background 0.2s ease, transform 0.15s ease;
    z-index: 5;
}

.gallery-preview-character-link:hover {
    background: var(--veil-strong);
    transform: scale(1.03);
    color: var(--ink);
    text-decoration: none;
}

.gallery-preview-character-thumb {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    object-fit: cover;
    border: 1.5px solid rgba(0, 0, 0, 0.3);
}

.gallery-preview-character-name {
    font-size: 13px;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 150px;
}

.gallery-preview-media-inner {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}

.gallery-preview-media-inner img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

/* Details side */
.gallery-preview-details {
    flex: 0 0 380px;
    display: flex;
    flex-direction: column;
    border-left: 1px solid rgba(0, 0, 0, 0.1);
    background: var(--surface-sunken);
    overflow: hidden;
}

.gallery-preview-header {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
    flex-shrink: 0;
}

.gallery-preview-avatar {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    object-fit: cover;
    border: 2px solid rgba(119, 119, 119, 0.4);
}

.gallery-preview-author-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.gallery-preview-author-name {
    color: var(--ink);
    font-weight: 600;
    font-size: 14px;
}

.gallery-preview-date {
    color: var(--ink-muted);
    font-size: 12px;
}

.gallery-preview-caption-area {
    padding: 16px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
    flex-shrink: 0;
    max-height: 100px;
    overflow-y: auto;
}

/* Gift attribution banner — shown above the caption in the preview modal */
.gallery-preview-gift-banner {
    padding: 10px 16px;
    background: linear-gradient(90deg, rgba(227, 0, 54, 0.18) 0%, rgba(227, 0, 54, 0.08) 100%);
    border-left: 3px solid #e30036;
    color: var(--ink);
    font-size: 0.82rem;
    line-height: 1.4;
    flex-shrink: 0;
}

.gallery-preview-caption {
    color: var(--ink-soft);
    font-size: 14px;
    line-height: 1.5;
    margin: 0;
    word-break: break-word;
}

.gallery-preview-caption:empty {
    display: none;
}

.gallery-preview-caption-area:has(.gallery-preview-caption:empty) {
    display: none;
}

/* Comments */
.gallery-preview-comments {
    flex: 1;
    overflow-y: auto;
    padding: 12px 16px;
    scrollbar-width: thin;
    scrollbar-color: rgba(0, 0, 0, 0.15) transparent;
}

.gallery-preview-comments::-webkit-scrollbar {
    width: 4px;
}

.gallery-preview-comments::-webkit-scrollbar-thumb {
    background: var(--scrim-soft);
    border-radius: 4px;
}

.gallery-preview-comment-item {
    display: flex;
    gap: 10px;
    padding: 8px 0;
    animation: liveCommentFadeIn 0.28s ease both;
}

.gallery-preview-comment-item + .gallery-preview-comment-item {
    border-top: 1px solid rgba(0, 0, 0, 0.04);
}

.gallery-preview-comment-avatar {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
    transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.gallery-preview-comment-body {
    flex: 1;
    min-width: 0;
    padding: 8px 10px;
    border-radius: 14px;
    transition: background 0.25s ease, border-color 0.25s ease, transform 0.25s ease, box-shadow 0.25s ease;
}

.gallery-preview-comment-author {
    color: var(--ink);
    font-weight: 600;
    font-size: 13px;
    margin-right: 6px;
}

.gallery-preview-comment-text {
    color: var(--ink-soft);
    font-size: 13px;
    line-height: 1.4;
    word-break: break-word;
}

.gallery-preview-comment-time {
    color: var(--ink-disabled);
    font-size: 11px;
    margin-top: 4px;
}

.gallery-preview-comment-item.live-generated .gallery-preview-comment-body {
    background: linear-gradient(135deg, rgba(147, 147, 147, 0.14), rgba(110, 110, 110, 0.16));
    border: 1px solid rgba(0, 0, 0, 0.08);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.06);
}

.gallery-preview-comment-item.live-comment-new .gallery-preview-comment-body {
    animation: liveCommentBubbleIn 0.38s cubic-bezier(0.2, 0.9, 0.2, 1) both;
}


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

@keyframes liveCommentBubbleIn {
    0% {
        opacity: 0;
        transform: translateY(10px) scale(0.98);
    }
    70% {
        opacity: 1;
        transform: translateY(-1px) scale(1.01);
    }
    100% {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
}


.comment-reaction-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 8px;
}

.comment-reaction-pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-height: 26px;
    padding: 3px 8px;
    border-radius: 999px;
    border: 1px solid rgba(0, 0, 0, 0.1);
    background: var(--glass-strong);
    color: var(--ink);
    font-size: 12px;
    line-height: 1;
    cursor: pointer;
}

.comment-reaction-pill:hover {
    background: var(--scrim-soft);
}

.comment-reaction-pill.active {
    background: var(--scrim-soft);
    border-color: var(--line-strong);
}

.gallery-preview-no-comments {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100%;
    color: var(--ink-disabled);
    font-size: 14px;
    gap: 8px;
}

.gallery-preview-no-comments i {
    font-size: 28px;
}

/* Actions */
.gallery-preview-actions {
    padding: 12px 16px;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
    flex-shrink: 0;
}

.gallery-preview-action-buttons {
    display: flex;
    gap: 12px;
    margin-bottom: 8px;
}

.gallery-preview-action-btn {
    background: none;
    border: none;
    color: var(--ink);
    font-size: 22px;
    cursor: pointer;
    padding: 0;
    transition: color 0.2s, transform 0.15s;
    line-height: 1;
}

.gallery-preview-action-btn:hover {
    color: var(--ink-muted);
    transform: scale(1.1);
}

.gallery-preview-action-btn.liked {
    color: #af0f0f;
}

.gallery-preview-action-btn.liked:hover {
    color: #8a1616;
}

.gallery-preview-likes-count {
    color: var(--ink);
    font-weight: 600;
    font-size: 14px;
}

/* Add Comment */
.gallery-preview-add-comment {
    display: flex;
    align-items: center;
    padding: 12px 16px;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
    gap: 8px;
    flex-shrink: 0;
}

.gallery-preview-comment-input {
    flex: 1;
    background: transparent;
    border: none;
    color: var(--ink);
    font-size: 14px;
    outline: none;
    padding: 4px 0;
}

.gallery-preview-comment-input::placeholder {
    color: var(--ink-disabled);
}

.gallery-preview-comment-submit {
    background: none;
    border: none;
    color: var(--ink-muted);
    font-weight: 600;
    font-size: 14px;
    cursor: pointer;
    padding: 4px 8px;
    transition: opacity 0.2s;
}

.gallery-preview-comment-submit:disabled {
    opacity: 0.35;
    cursor: default;
}

.gallery-preview-comment-submit:not(:disabled):hover {
    opacity: 0.8;
}

/* Loading state */
.gallery-preview-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    color: var(--ink-muted);
}

.gallery-preview-loading .spinner-border {
    width: 24px;
    height: 24px;
    border-width: 2px;
}

/* ========================================
   GALLERY PREVIEW MODAL - RESPONSIVE
   ======================================== */
@media (max-width: 768px) {
    .gallery-preview-dialog {
        max-width: 100%;
        width: 100%;
        margin: 0;
        height: 100%;
    }

    .gallery-preview-content {
        border-radius: 0;
        height: 100%;
        max-height: 100vh;
    }

    .gallery-preview-layout {
        flex-direction: column;
        height: 100vh;
        max-height: 100vh;
        overflow-y: auto;
    }

    .gallery-preview-media {
        flex: 0 0 auto;
        max-height: 50vh;
        min-height: 250px;
    }

    .gallery-preview-details {
        flex: 1 1 auto;
        border-left: none;
        border-top: 1px solid rgba(0, 0, 0, 0.1);
        overflow: visible;
    }

    .gallery-preview-comments {
        max-height: 200px;
        overflow-y: auto;
    }

    .gallery-preview-close {
        top: 8px;
        right: 8px;
        z-index: 20;
        background: var(--veil-strong);
        border-radius: 50%;
        padding: 8px;
        width: 32px;
        height: 32px;
        display: flex;
        align-items: center;
        justify-content: center;
    }
}

@media (min-width: 769px) and (max-width: 1024px) {
    .gallery-preview-details {
        flex: 0 0 320px;
    }
}

/* ============================================================
   Character Settings Modal (owner) — compact dark UI
   ============================================================ */
.cs-modal-content {
    background: var(--surface-sunken);
    color: var(--ink);
    border: 1px solid rgba(111, 111, 111, 0.25);
    border-radius: 18px;
}
.cs-title {
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--ink);
}
.character-settings-modal .modal-header { padding: 16px 18px 0; }
.character-settings-modal .modal-body { padding: 8px 18px 18px; }
.character-settings-modal .btn-close {
    filter: invert(1) grayscale(1) brightness(1.6);
    opacity: 0.7;
}

.cs-section { margin-top: 16px; }
.cs-section.cs-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}
.cs-label {
    display: block;
    font-size: 0.72rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ink-muted);
    margin-bottom: 6px;
    font-weight: 600;
}
.cs-hint {
    font-size: 0.74rem;
    color: var(--ink-muted);
    margin: 6px 0 0;
}
.cs-textarea, .cs-input {
    width: 100%;
    background: var(--surface-sunken);
    border: 1px solid rgba(0, 0, 0, 0.08);
    border-radius: 10px;
    color: var(--ink);
    padding: 9px 11px;
    font-size: 0.88rem;
    resize: vertical;
}
.cs-textarea:focus, .cs-input:focus {
    outline: none;
    border-color: var(--line);
    box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.06);
}

/* Segmented control */
.cs-segmented {
    display: flex;
    background: var(--surface-sunken);
    border-radius: 10px;
    padding: 3px;
    gap: 3px;
}
.cs-seg {
    flex: 1;
    border: none;
    background: transparent;
    color: var(--ink-soft);
    padding: 8px 10px;
    border-radius: 8px;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.15s ease;
}
.cs-seg.active {
    background: linear-gradient(135deg, #6f6f6f, #727272);
    color: var(--brand-ink);
}

/* Toggle switch */
.cs-switch { position: relative; display: inline-block; width: 46px; height: 26px; flex: 0 0 auto; }
.cs-switch input { opacity: 0; width: 0; height: 0; }
.cs-slider {
    position: absolute; cursor: pointer; inset: 0;
    background: var(--fill-mid-soft); border-radius: 26px; transition: 0.2s;
}
.cs-slider::before {
    content: ""; position: absolute; height: 20px; width: 20px;
    left: 3px; bottom: 3px; background: var(--on-media-ink); border-radius: 50%; transition: 0.2s;
}
.cs-switch input:checked + .cs-slider { background: var(--status-success); }
.cs-switch input:checked + .cs-slider::before { transform: translateX(20px); }
.cs-switch input:disabled + .cs-slider { opacity: 0.45; cursor: not-allowed; }

/* Source photo — read-only, owner's eyes only (docs/CHARACTER_SOURCE_PHOTO.md).
   Deliberately quieter than the editable controls above it: it is a record, not
   a setting, and the lock caption is the whole point of showing it. */
.cs-source-photo-frame {
    margin: 0;
    background: var(--surface-sunken);
    border: 1px solid rgba(0, 0, 0, 0.06);
    border-radius: 12px;
    padding: 10px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
}
.cs-source-photo-frame img {
    max-width: 100%;
    /* Capped rather than fluid: a portrait original would otherwise push the
       Save button off a phone screen. */
    max-height: 260px;
    border-radius: 10px;
    object-fit: contain;
}
.cs-source-photo-frame figcaption {
    font-size: 0.72rem;
    color: var(--ink-muted);
    display: flex;
    align-items: center;
    gap: 5px;
}

/* Additional info entries */
.cs-info-list { display: flex; flex-direction: column; gap: 10px; }
.cs-info-item {
    background: var(--surface-sunken);
    border: 1px solid rgba(0, 0, 0, 0.06);
    border-radius: 12px;
    padding: 10px;
    display: flex;
    flex-direction: column;
    gap: 7px;
}
.cs-info-head {
    display: flex; align-items: center; justify-content: space-between;
}
.cs-info-type {
    font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em;
    color: var(--ink-muted); font-weight: 700;
}
.cs-info-remove {
    background: transparent; border: none; color: var(--ink-muted);
    cursor: pointer; padding: 2px 4px; font-size: 0.85rem;
}
.cs-info-remove:hover { color: #e00000; }
.cs-info-urlrow { display: flex; gap: 6px; align-items: stretch; }
.cs-info-urlrow .cs-input { flex: 1; }
.cs-upload-btn {
    display: flex; align-items: center; justify-content: center;
    background: var(--fill-mid-soft); border: 1px solid rgba(0, 0, 0, 0.08);
    border-radius: 10px; padding: 0 12px; cursor: pointer; color: var(--ink-soft);
}
.cs-upload-btn:hover { border-color: var(--line); color: var(--ink); }

.cs-info-actions { display: flex; gap: 8px; margin-top: 10px; }
.cs-add-btn {
    flex: 1;
    background: var(--surface-sunken);
    border: 1px dashed rgba(111, 111, 111, 0.4);
    color: var(--ink-soft);
    border-radius: 10px;
    padding: 8px 6px;
    font-size: 0.78rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.15s ease;
}
.cs-add-btn:hover { border-color: var(--line); color: var(--ink); background: var(--fill-mid-soft); }

.cs-footer {
    margin-top: 20px;
    position: sticky;
    bottom: -18px; /* cancels .modal-body bottom padding */
    padding: 12px 0 14px;
    background: linear-gradient(180deg, rgba(225, 225, 225, 0) 0%, #e1e1e1 26%);
    z-index: 3;
}

/* ---- Tab strip -------------------------------------------------------- */
.cs-tabs {
    display: flex;
    gap: 6px;
    overflow-x: auto;
    padding: 4px 0 10px;
    margin: 0 -2px 4px;
    position: sticky;
    top: 0;
    z-index: 4;
    background: var(--surface-sunken);
    scrollbar-width: none;
}
.cs-tabs::-webkit-scrollbar { display: none; }
.cs-tab {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    border: 1px solid rgba(0, 0, 0, 0.08);
    background: var(--surface-sunken);
    color: var(--ink-soft);
    border-radius: 999px;
    padding: 7px 13px;
    font-size: 0.8rem;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
    transition: all 0.15s ease;
}
.cs-tab:hover { color: var(--ink); border-color: var(--line-strong); }
.cs-tab.active {
    background: linear-gradient(135deg, #6f6f6f, #727272);
    border-color: transparent;
    color: var(--brand-ink);
}
.cs-tab i { font-size: 0.9rem; }

.cs-pane { display: none; }
.cs-pane.active { display: block; }
.cs-pane > .cs-section:first-child { margin-top: 10px; }

.cs-adv-error {
    margin: 10px 0 0;
    color: #ff0f0f;
}

/* ---- Editor sections slotted into the panes ---------------------------
   These come from the `character-update` fragment. character-update.css is
   NOT loaded here (its `.form-section` rules are unscoped and would leak), so
   everything the sections need is restated scoped to #csContent.            */
.cs-adv-slot:not(:empty) { margin-top: 16px; }
#csContent .form-section {
    display: block;
    border-radius: 14px;
    margin-bottom: 0;
    overflow: hidden;
    box-shadow: none;
    background: var(--surface-sunken);
    border: 1px solid rgba(0, 0, 0, 0.07);
}
/* Sections stack inside a pane, so their headings come back as the
   collapsible sub-section titles. */
#csContent .form-section-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 12px 14px;
    cursor: pointer;
    font-size: 0.74rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ink-soft);
    border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}
#csContent .form-section-header:hover { color: var(--ink); }
#csContent .form-section-content { padding: 14px; }
#csContent .character-update-header,
#csContent .character-update-tabs,
#csContent .modal-title { display: none; }

#csContent .row { --bs-gutter-y: 0.75rem; }
#csContent .form-label {
    display: flex;
    align-items: center;
    font-size: 0.72rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    font-weight: 600;
    color: var(--ink-muted);
    margin-bottom: 6px;
}
#csContent .form-control,
#csContent .form-select {
    background: var(--surface-sunken);
    border: 1px solid rgba(0, 0, 0, 0.08);
    color: var(--ink);
    border-radius: 10px;
    padding: 9px 11px;
    font-size: 0.88rem;
}
#csContent .form-select {
    /* Chevron drawn in, since the native arrow is invisible on dark. */
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%239a9a9e'%3E%3Cpath d='M8 11L3 6h10z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 14px;
}
#csContent .form-control:focus,
#csContent .form-select:focus {
    background: var(--surface-sunken);
    color: var(--ink);
    border-color: var(--line);
    box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.06);
}
#csContent .form-control::placeholder { color: var(--ink-muted); }
#csContent .form-control[readonly] { opacity: 0.6; cursor: not-allowed; }
/* The editor fragment ships rows="8" textareas — far too tall stacked in a
   modal pane. */
#csContent textarea.form-control { height: 110px; min-height: 72px; resize: vertical; }
#csContent .field-description,
#csContent .text-muted { font-size: 0.72rem; color: var(--ink-muted) !important; margin-top: 4px; }
#csContent .model-preview-image { border: 1px solid rgba(0, 0, 0, 0.08); }

/* A pane's first slotted section shouldn't double up on spacing */
.cs-pane > .cs-adv-slot:first-child { margin-top: 10px; }

@media (max-width: 576px) {
    .cs-tab span { display: none; }
    .cs-tab { padding: 8px 12px; }
    .cs-tab.active span { display: inline; }
}

/* ============================================================
   Character Feed tab — layout ONLY.
   The post CARDS are rendered by the shared IG post component
   (public/css/ig-post.css, docs/IG_POST_COMPONENT.md). Do NOT add
   card styles here; there is one post design for the whole platform.
   ============================================================ */
.char-feed {
    max-width: 640px;
    margin: 0 auto;
    padding: 8px 12px 40px;
}
.char-feed-intro {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.82rem;
    color: var(--ig-text-secondary);
    padding: 10px 12px;
    margin-bottom: 12px;
    border: 1px solid var(--ig-border);
    border-radius: 12px;
    background: var(--ig-surface);
}
.char-feed-intro i { color: var(--ig-purple); font-size: 1rem; }
/* Visibility note above the posts: this feed is owner + admin only and never
   renders on the public profile. Amber so it reads as "private", not as chrome. */
.char-feed-private-note {
    align-items: flex-start;
    line-height: 1.45;
    color: #db9613;
    border-color: rgba(183, 116, 10, 0.32);
    background: rgba(183, 116, 10, 0.08);
    margin-top: -4px;
}
.char-feed-private-note i { color: #b7740a; }
.char-feed-status {
    text-align: center;
    color: var(--ig-text-secondary);
    font-size: 0.8rem;
    padding: 18px 0 4px;
}
@media (max-width: 480px) {
    .char-feed { padding: 6px 8px 40px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   OWNER MEDIA MANAGER — floating "add" button + its modal
   (public/js/character-profile-media-manager.js,
    docs/CHARACTER_PROFILE_MEDIA_UPLOAD.md)

   Owner/admin only. The dropzone and the gallery picker live INSIDE the modal
   the FAB opens, so the profile page itself renders identically for the owner
   and for a visitor — the button is the only difference.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Floating "Add a new image / video" button ───────────────────────────── */

.cpm-fab {
    position: fixed;
    right: 16px;
    bottom: 88px; /* clear of the sticky bottom nav */
    z-index: 1200;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    max-width: calc(100vw - 32px);
    padding: 12px 18px;
    border: 1px solid rgba(0, 0, 0, 0.18);
    border-radius: 999px;
    /* Brand fill, so it carries --brand-ink as its label — the old --ink label
       on the dark brand gradient rendered the whole pill as a black blob. */
    background: var(--brand-gradient);
    color: var(--brand-ink);
    font-size: 0.88rem;
    font-weight: 600;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.06);
    transition: transform 0.18s ease, box-shadow 0.18s ease;
}

.cpm-fab[hidden] { display: none; }
.cpm-fab:hover { transform: translateY(-2px); box-shadow: 0 12px 32px rgba(0, 0, 0, 0.06); }
.cpm-fab:active { transform: scale(0.96); }
.cpm-fab i { font-size: 1.05rem; }

@media (max-width: 480px) {
    .cpm-fab { right: 12px; bottom: 78px; padding: 11px 16px; font-size: 0.82rem; }
}

.cpm-panel {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

/* Self-contained sizing. The host page has a global `* { box-sizing:
   border-box }` (style.css), but this panel is injected by JS into a page whose
   stylesheet order we don't control, and a content-box fallback makes the
   padded dropzone overflow the grid width. Declare it locally so the component
   is correct on its own. */
.cpm-panel,
.cpm-panel *,
.cpm-overlay,
.cpm-overlay * {
    box-sizing: border-box;
}

.cpm-dropzone {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 24px 16px;
    border: 1.5px dashed rgba(102, 102, 102, 0.45);
    border-radius: 16px;
    background: var(--glass-strong);
    color: var(--ig-text);
    cursor: pointer;
    text-align: center;
    transition: background 0.18s ease, border-color 0.18s ease, transform 0.18s ease;
}

.cpm-dropzone:hover,
.cpm-dropzone:focus-visible {
    background: var(--glass-strong);
    border-color: var(--line-strong);
    outline: none;
}

.cpm-dropzone.is-over {
    background: var(--scrim-soft);
    border-color: var(--line-strong);
    transform: scale(1.01);
}

.cpm-dropzone > i {
    font-size: 1.6rem;
    color: var(--ink-soft);
    margin-bottom: 2px;
}

.cpm-dropzone-title {
    font-size: 0.92rem;
    font-weight: 600;
}

.cpm-dropzone-hint {
    font-size: 0.78rem;
    color: var(--ig-text-secondary);
}

.cpm-library-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    padding: 11px 16px;
    border: 1px solid var(--ig-border);
    border-radius: 12px;
    background: var(--ig-surface);
    color: var(--ig-text);
    font-size: 0.88rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease;
}

.cpm-library-btn:hover {
    background: var(--scrim-soft);
    border-color: var(--line-strong);
}

.cpm-library-btn i { color: var(--ink-soft); }

.cpm-tray {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.cpm-tile {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 220px;
    padding: 5px 10px;
    border-radius: 999px;
    background: var(--ig-surface);
    border: 1px solid var(--ig-border);
    color: var(--ig-text-secondary);
    font-size: 0.75rem;
}

.cpm-tile-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cpm-tile.is-busy .cpm-tile-icon i { animation: cpm-spin 0.8s linear infinite; color: var(--ink-soft); }
.cpm-tile.is-done { border-color: rgba(28, 155, 75, 0.45); color: #1c9b4b; }
.cpm-tile.is-failed { border-color: rgba(213, 11, 11, 0.5); color: #d50b0b; }

@keyframes cpm-spin { to { transform: rotate(360deg); } }

.cpm-status {
    min-height: 16px;
    font-size: 0.78rem;
    color: var(--ig-text-secondary);
}

/* ── Library picker modal ────────────────────────────────────────────────── */

.cpm-overlay {
    position: fixed;
    inset: 0;
    z-index: 100060;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    background: var(--veil-strong);
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
    opacity: 0;
    transition: opacity 0.16s ease;
}

.cpm-overlay.open { opacity: 1; }

.cpm-modal {
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 620px;
    max-height: 86vh;
    background: var(--veil-strong);
    border: 1px solid rgba(0, 0, 0, 0.12);
    border-radius: 18px;
    overflow: hidden;
    box-shadow: 0 24px 70px rgba(0, 0, 0, 0.16);
    transform: translateY(8px) scale(0.98);
    transition: transform 0.18s ease;
}

.cpm-overlay.open .cpm-modal { transform: none; }

/* The "add media" sheet holds one dropzone + one button, so it stays narrow;
   the library picker keeps the wider grid width. */
.cpm-modal--add { max-width: 460px; }

.cpm-modal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 16px 10px;
}

.cpm-modal-title {
    display: flex;
    align-items: center;
    gap: 9px;
    color: var(--ink);
    font-size: 15px;
    font-weight: 600;
}

.cpm-modal-title i { color: var(--ink-soft); }

.cpm-modal-close {
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: var(--glass-strong);
    color: var(--ink);
    cursor: pointer;
    transition: background 0.15s ease;
}

.cpm-modal-close:hover { background: var(--scrim-soft); }

.cpm-modal-sub {
    margin: 0;
    padding: 0 16px 12px;
    font-size: 0.8rem;
    color: var(--ink-muted);
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}

.cpm-modal-body {
    padding: 14px 16px;
    overflow-y: auto;
}

.cpm-picker-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
    gap: 8px;
}

.cpm-cell {
    position: relative;
    padding: 0;
    aspect-ratio: 1 / 1;
    border: 2px solid transparent;
    border-radius: 12px;
    overflow: hidden;
    background: var(--glass);
    cursor: pointer;
    transition: border-color 0.15s ease, transform 0.15s ease;
}

.cpm-cell img,
.cpm-cell video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    background: var(--surface-page);
}

.cpm-cell:hover { transform: scale(1.03); border-color: var(--line-strong); }
.cpm-cell.is-selected { border-color: var(--line); }

.cpm-cell-check {
    position: absolute;
    inset: 0;
    display: none;
    align-items: center;
    justify-content: center;
    background: var(--scrim);
    color: var(--ink);
    font-size: 24px;
}

.cpm-cell.is-selected .cpm-cell-check { display: flex; }

.cpm-cell-nsfw {
    position: absolute;
    top: 5px;
    left: 5px;
    padding: 2px 5px;
    border-radius: 5px;
    background: rgba(195, 0, 30, 0.9);
    color: var(--status-ink);
    font-size: 9px;
    font-weight: 700;
}

.cpm-cell-live {
    position: absolute;
    bottom: 5px;
    left: 5px;
    right: 5px;
    padding: 2px 5px;
    border-radius: 5px;
    background: rgba(16, 185, 129, 0.85);
    color: var(--ink);
    font-size: 9px;
    font-weight: 700;
    text-align: center;
    text-overflow: ellipsis;
    overflow: hidden;
    white-space: nowrap;
}

.cpm-cell-video {
    position: absolute;
    top: 5px;
    right: 5px;
    width: 20px;
    height: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--veil-strong);
    color: var(--ink);
    font-size: 11px;
}

.cpm-picker-empty {
    padding: 40px 20px;
    text-align: center;
    color: var(--ink-muted);
    font-size: 14px;
}

.cpm-picker-empty i {
    display: block;
    font-size: 28px;
    margin-bottom: 8px;
    opacity: 0.6;
}

.cpm-picker-loading {
    padding: 18px;
    text-align: center;
    color: var(--ink-muted);
}

.cpm-picker-more {
    width: 100%;
    margin-top: 12px;
    padding: 10px;
    border: 1px solid rgba(0, 0, 0, 0.14);
    border-radius: 10px;
    background: var(--glass);
    color: var(--ink);
    font-size: 13px;
    cursor: pointer;
    transition: background 0.15s ease;
}

.cpm-picker-more:hover { background: var(--glass-strong); }

.cpm-modal-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 16px 16px;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
}

.cpm-selected-count {
    font-size: 0.8rem;
    color: var(--ink-muted);
}

.cpm-select-all-btn {
    margin-left: auto;
    padding: 8px 16px;
    border: 1px solid rgba(0, 0, 0, 0.22);
    border-radius: 999px;
    background: transparent;
    color: var(--ink);
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease, opacity 0.15s ease;
}

.cpm-select-all-btn:hover:not(:disabled) { background: var(--glass-strong); }
.cpm-select-all-btn:disabled { opacity: 0.45; cursor: not-allowed; }

.cpm-add-btn {
    padding: 10px 22px;
    border: none;
    border-radius: 999px;
    background: linear-gradient(135deg, #6c6c6c, #797979);
    color: var(--ink);
    font-size: 0.85rem;
    font-weight: 700;
    cursor: pointer;
    transition: filter 0.15s ease, opacity 0.15s ease;
}

.cpm-add-btn:hover:not(:disabled) { filter: brightness(1.1); }
.cpm-add-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.cpm-add-btn.is-busy { opacity: 0.7; cursor: progress; }

@media (max-width: 480px) {
    .cpm-panel { padding: 12px 12px 14px; }
    .cpm-dropzone { padding: 20px 12px; }
    .cpm-modal { max-height: 92vh; border-radius: 16px; }
    .cpm-picker-grid { grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); }
}

/* ── Character Settings: 3D avatar (VRM) section ─────────────────────────────
 * Lives at the top of the Looks tab (#csVrmSection in views/character.hbs),
 * driven by public/js/character-vrm-settings.js. Same palette as the rest of
 * the .cs-* modal — dark violet panel, gradient primary action. */

.cs-vrm-stage {
    position: relative;
    margin-top: 10px;
    height: 260px;
    border-radius: 14px;
    background:
        radial-gradient(110% 80% at 50% 10%, rgba(111, 111, 111, 0.2) 0%, rgba(111, 111, 111, 0) 65%),
        #e0e0e0;
    border: 1px solid rgba(0, 0, 0, 0.08);
    overflow: hidden;
}

.cs-vrm-canvas {
    display: block;
    width: 100%;
    height: 100%;
}

/* Empty + status sit on top of the canvas rather than in the flow, so the
 * stage never changes height and the panel does not jump while a model loads. */
.cs-vrm-empty {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    color: var(--ink-muted);
    font-size: 0.82rem;
    pointer-events: none;
}

.cs-vrm-empty i {
    font-size: 1.9rem;
    opacity: 0.65;
}

.cs-vrm-status {
    position: absolute;
    left: 50%;
    bottom: 10px;
    transform: translateX(-50%);
    max-width: 92%;
    text-align: center;
    background: var(--veil-strong);
    border: 1px solid rgba(0, 0, 0, 0.09);
    border-radius: 8px;
    padding: 6px 10px;
    font-size: 0.75rem;
    color: var(--ink-soft);
}

.cs-vrm-status-error {
    background: rgba(175, 15, 15, 0.16);
    border-color: rgba(175, 15, 15, 0.38);
    color: #f70c0c;
}

.cs-vrm-actions {
    display: flex;
    gap: 8px;
    margin-top: 10px;
}

.cs-vrm-btn {
    flex: 1;
    border: none;
    border-radius: 10px;
    padding: 9px 12px;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--brand-ink);
    background: linear-gradient(135deg, #6f6f6f, #727272);
    cursor: pointer;
    transition: filter 0.15s ease, opacity 0.15s ease;
}

.cs-vrm-btn:hover:not(:disabled) { filter: brightness(1.08); }

.cs-vrm-btn:disabled {
    opacity: 0.55;
    cursor: default;
}

.cs-vrm-btn-danger {
    flex: 0 0 auto;
    background: transparent;
    border: 1px solid rgba(175, 15, 15, 0.42);
    color: #f70c0c;
}

.cs-vrm-btn-danger:hover:not(:disabled) {
    background: rgba(175, 15, 15, 0.12);
    filter: none;
}

.cs-vrm-framing { margin-top: 12px; }

/* Motion slots (.vrma) inside the 3D avatar section. */
.cs-vrm-motion { margin-top: 16px; }

.cs-vrm-slot {
    display: flex;
    align-items: center;
    gap: 8px;
    background: var(--surface-sunken);
    border: 1px solid rgba(0, 0, 0, 0.07);
    border-radius: 10px;
    padding: 8px 10px;
    margin-top: 8px;
}

.cs-vrm-slot-info {
    flex: 1;
    min-width: 0;
}

.cs-vrm-slot-name {
    display: block;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--ink);
}

/* Truncates rather than wraps: a long clip filename must not reflow the row. */
.cs-vrm-slot-file {
    display: block;
    font-size: 0.72rem;
    color: var(--ink-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.cs-vrm-slot-file.is-filled { color: var(--ink-soft); }

.cs-vrm-slot-btn {
    flex: 0 0 auto;
    border: 1px solid rgba(88, 88, 88, 0.4);
    background: transparent;
    color: var(--ink-soft);
    border-radius: 8px;
    padding: 5px 10px;
    font-size: 0.78rem;
    font-weight: 600;
    cursor: pointer;
}

.cs-vrm-slot-btn:hover { background: var(--scrim-soft); }

.cs-vrm-slot-clear {
    border-color: rgba(175, 15, 15, 0.4);
    color: #f70c0c;
}

.cs-vrm-slot-clear:hover { background: rgba(175, 15, 15, 0.12); }

.cs-vrm-preview-talk {
    width: 100%;
    margin-top: 10px;
    border: 1px solid rgba(88, 88, 88, 0.35);
    background: transparent;
    color: var(--ink-soft);
    border-radius: 10px;
    padding: 8px;
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
}

.cs-vrm-preview-talk:hover { background: var(--glass-strong); }
