/* ── UBUNTU FONT (local, latin + latin-ext) ── */
@font-face {
    font-family: 'Ubuntu';
    font-style: normal;
    font-weight: 300;
    font-display: swap;
    src: url('../fonts/ubuntu-300.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Ubuntu';
    font-style: normal;
    font-weight: 300;
    font-display: swap;
    src: url('../fonts/ubuntu-300-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: 'Ubuntu';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/ubuntu-400.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Ubuntu';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/ubuntu-400-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: 'Ubuntu';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/ubuntu-500.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Ubuntu';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/ubuntu-500-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: 'Ubuntu';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('../fonts/ubuntu-700.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Ubuntu';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('../fonts/ubuntu-700-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ── VARS ── */
:root {
    /* color-scheme: dark le dice al browser que TODOS los controles nativos
       (select dropdowns, scrollbars, autofill, date pickers, etc) usen el
       esquema oscuro del sistema. Sin esto, los <option> de <select> aparecen
       con fondo blanco aunque el resto del UI sea oscuro → texto blanco sobre
       blanco = invisible. Override en [data-theme="light"] más abajo. */
    color-scheme: dark;

    /* Brand colors */
    --accent: #00FA9E;
    --purple: #9F47EB;
    --gold: #FFC61A;

    /* Derived shades (hover / border) */
    --accent-hover: #00E089;
    --accent-border: #00C97A;
    --purple-hover: #8A33D6;
    --purple-border: #7B26C2;
    --gold-hover: #E6B017;
    --gold-border: #C99800;

    /* Gradients (reserved) */
    --grad-neon: linear-gradient(135deg, #00FA9E, #00CCCC);
    --grad-viral: linear-gradient(135deg, #9F47EB, #E647C2);
    --grad-gold: linear-gradient(135deg, #FFC61A, #FF9900);

    --bg: #0a0a0a;
    --surface: rgba(255, 255, 255, .08);
    --border-clr: rgba(255, 255, 255, .12);
    --text: #fff;
    --text-muted: rgba(255, 255, 255, .4);
    --text-dim: rgba(255, 255, 255, .65);
    --input-bg: rgba(255, 255, 255, .08);
    --drawer-bg: #1a1a1a;
    --nb-bg: #111;
    --card-bg: #111;
    --pill-bg: rgba(255, 255, 255, .08);
    --pill-border: rgba(255, 255, 255, .1);
    --pill-color: rgba(255, 255, 255, .6);
    --nb-h: 64px;
}

[data-theme="light"] {
    color-scheme: light;   /* controles nativos se vuelven claros en tema light */
    --bg: #f5f5f5;
    --surface: rgba(0, 0, 0, .05);
    --border-clr: rgba(0, 0, 0, .12);
    --text: #1a1a1a;
    --text-muted: rgba(0, 0, 0, .4);
    --text-dim: rgba(0, 0, 0, .65);
    --input-bg: rgba(0, 0, 0, .05);
    --drawer-bg: #fff;
    --nb-bg: #fff;
    --card-bg: #ddd;
    --pill-bg: rgba(0, 0, 0, .06);
    --pill-border: rgba(0, 0, 0, .1);
    --pill-color: rgba(0, 0, 0, .6);
}

/* ── VARIANTES DARK CON ACENTO DE COLOR ──
   Heredan toda la base dark del :root y solo redefinen --accent (+ shades) y
   un tinte sutil de --card-bg / --bg. data-theme="dark" usa el acento neón
   default (verde #00FA9E). Estas variantes son alternativas estéticas. */
[data-theme="dark-red"] {
    --accent: #FF4D4D;
    --accent-hover: #FF6B6B;
    --accent-border: #E63946;
    --bg: #100707;
    --card-bg: #1a0e0e;
    --drawer-bg: #1f1313;
}
[data-theme="dark-green"] {
    --accent: #2ECC71;
    --accent-hover: #28B864;
    --accent-border: #229954;
    --bg: #07100c;
    --card-bg: #0e1a14;
    --drawer-bg: #131f19;
}
[data-theme="dark-pink"] {
    --accent: #FF5FB1;
    --accent-hover: #FF7AC0;
    --accent-border: #E84B9C;
    --bg: #100712;
    --card-bg: #1a0e1e;
    --drawer-bg: #1f1325;
}
[data-theme="dark-blue"] {
    --accent: #4D9FFF;
    --accent-hover: #6BB0FF;
    --accent-border: #2E7DD9;
    --bg: #07101a;
    --card-bg: #0e1a26;
    --drawer-bg: #131f2c;
}
[data-theme="dark-orange"] {
    --accent: #FF8C42;
    --accent-hover: #FFA160;
    --accent-border: #E67230;
    --bg: #120a05;
    --card-bg: #1e120a;
    --drawer-bg: #25170e;
}
[data-theme="dark-yellow"] {
    --accent: #FFD54A;
    --accent-hover: #FFDF70;
    --accent-border: #E0B838;
    --bg: #100e05;
    --card-bg: #1a160a;
    --drawer-bg: #1f1b0e;
}

/* ── SHELL ── */
html,
body {
    height: 100%;
    overflow: hidden;
    font-family: 'Ubuntu', sans-serif;
    color: var(--text);
    background: var(--bg);
}

#app {
    position: fixed;
    inset: 0;
    /* Reservar TANTO el navbar fijo (--nb-h) como la barra de navegación del
       sistema operativo (env(safe-area-inset-bottom)). En celulares con gestos
       safe-area-inset-bottom = 0 y solo descontamos los 64px del navbar; en
       celulares con barra física/virtual (Motorola G56, etc.) sumamos su alto
       para que el slide no quede tapado. */
    bottom: calc(var(--nb-h) + env(safe-area-inset-bottom, 0px));
    overflow: hidden;
}

.view {
    position: absolute;
    inset: 0;
    display: none;
    flex-direction: column;
    background: var(--bg);
}

.view.active {
    display: flex;
}

/* ── SCROLL-SNAP ──
   IMPORTANTE: `scroll-behavior: smooth` afecta TODO set programático de
   scrollTop (no solo el scroll del usuario). Si en JS hacés
   `feed.scrollTop = X` para corregir posición tras insertar/eliminar slides
   (ver _prependSlide y _pdPrependSlide), el browser ANIMA la corrección
   como si fuera un scroll del user → se ve un "salto raro" o auto-scroll
   no deseado.
   Solución usada en JS: setear `style.scrollBehavior = 'auto'` antes del
   set programático y restaurar después. Mantiene smooth para el scroll
   del user, pero hace las correcciones internas instantáneas.
   NO REMOVER esta declaración sin actualizar TODOS los lugares que setean
   scrollTop programáticamente. */
#feed,
#post-detail-feed {
    height: 100%;
    overflow-y: scroll;
    scroll-snap-type: y mandatory;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}

#feed::-webkit-scrollbar,
#post-detail-feed::-webkit-scrollbar {
    display: none;
}

/* ── Back button para vista post-detail ── */
#post-detail-back-btn {
    position: fixed;
    top: 12px;
    left: 12px;
    z-index: 51;
    background: rgba(0, 0, 0, .55);
    color: #fff;
    border: 0;
    border-radius: 999px;
    height: 40px;
    padding: 0 14px 0 10px;
    gap: 8px;
    display: none;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
}

body:has(#view-post-detail.active) #post-detail-back-btn {
    display: flex;
}

/* Botón scope (derecha) — selector de modo (perfil/categoría/feed). */
#post-detail-scope-btn {
    position: fixed;
    top: 12px;
    right: 12px;
    z-index: 51;
    background: rgba(0, 0, 0, .55);
    color: #fff;
    border: 0;
    border-radius: 999px;
    height: 40px;
    padding: 0 14px 0 10px;
    gap: 8px;
    display: none;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
    max-width: 50vw;
    overflow: hidden;
}
#post-detail-scope-btn span {
    overflow: hidden;
    text-overflow: ellipsis;
}
body:has(#view-post-detail.active) #post-detail-scope-btn {
    display: flex;
}

/* En post-detail ocultar el header completo (el back button toma su lugar) */
body:has(#view-post-detail.active) #feed-header {
    display: none !important;
}

.slide {
    position: relative;
    width: 100%;
    height: 100%;
    scroll-snap-align: start;
    scroll-snap-stop: always;
    overflow: hidden;
    background: #000;   /* tema oscuro (default) */
}
[data-theme="light"] .slide { background: #fff; }

.slide-media {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* ── Progress bar (videos) — estilo Reels: barra fina abajo, drag-to-seek ── */
.slide-progress {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 3px;
    background: rgba(255, 255, 255, .15);
    z-index: 5;
    cursor: pointer;
    touch-action: none;          /* evita que el scroll vertical robe el gesto */
    transition: height .12s ease;
}

.slide-progress:hover,
.slide-progress.dragging {
    height: 6px;
}

.slide-progress-bar {
    height: 100%;
    width: 0;
    background: var(--accent);
    transition: width .1s linear;
    pointer-events: none;        /* clicks pasan al contenedor padre */
}

.slide-progress.dragging .slide-progress-bar {
    transition: none;            /* drag = movimiento instantáneo */
}

/* ─── Tooltip de frame preview al scrub del video (tipo YouTube) ───
   Aparece arriba del slide-progress mientras user arrastra el bar.
   Muestra canvas con frame del video al timestamp scrubbed + texto del time.
   Posicionado dinámicamente vía JS (left absoluto sobre el progress bar). */
.slide-scrub-tooltip {
    position: absolute;
    bottom: calc(100% + 8px);    /* arriba del progress bar */
    transform: translateX(-50%); /* center anclado al pointer X */
    background: #000;
    border: 1px solid rgba(255, 255, 255, .15);
    border-radius: 8px;
    padding: 4px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    pointer-events: none;
    box-shadow: 0 4px 12px rgba(0, 0, 0, .5);
    z-index: 5;
}
.slide-scrub-tooltip[hidden] { display: none !important; }
.slide-scrub-tooltip canvas {
    display: block;
    border-radius: 4px;
    background: #111;
}
.slide-scrub-tooltip-time {
    color: #fff;
    font-size: 11px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    padding: 0 4px 2px;
}

.slide-media.fit-contain {
    object-fit: contain;
    object-position: center center;
}

/* ── GRADIENTS ── */
.slide-grad-bottom {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 55%;
    background: linear-gradient(to top, rgba(0, 0, 0, .85), transparent);
    pointer-events: none;
    z-index: 1;
}

.slide-grad-right {
    position: absolute;
    top: 0;
    right: 0;
    width: 90px;
    height: 100%;
    background: linear-gradient(to left, rgba(0, 0, 0, .5), transparent);
    pointer-events: none;
    z-index: 1;
}

[data-theme="light"] .slide-grad-bottom {
    background: linear-gradient(to top, rgba(255, 255, 255, .85), transparent);
}

[data-theme="light"] .slide-grad-right {
    background: linear-gradient(to left, rgba(255, 255, 255, .5), transparent);
}

[data-theme="light"] .slide-caption,
[data-theme="light"] .caption-toggle,
[data-theme="light"] .music-track,
[data-theme="light"] .action-btn {
    color: var(--text-muted);
    color: var(--text);
}

[data-theme="light"] .slide-music {
    background: rgba(0, 0, 0, .08);
    border-color: rgba(0, 0, 0, .12);
}

[data-theme="light"] .action-avatar,
[data-theme="light"] .follow-plus {
    border-color: #1a1a1a;
}

/* ── SLIDE INFO ── */
.slide-info {
    position: absolute;
    bottom: 20px;
    left: 14px;
    right: 90px;
    z-index: 2;
}

/* Meta line: categoría + fecha bajo el username */
.slide-meta {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    font-size: calc(var(--bs-body-font-size) - 3px);
    color: rgba(255, 255, 255, .55);
    margin-top: 2px;
    margin-bottom: 4px;
}

.slide-cat {
    color: var(--accent);
    font-weight: 500;
}

.slide-date {
    color: var(--text);   /* respeta tema: blanco en dark, oscuro en light */
}

.slide-meta-sep {
    opacity: .5;
}

.slide-caption {
    font-size: inherit;
    font-weight: 300;
    color: rgba(255, 255, 255, .9);
    overflow: hidden;
    line-height: 1.5;
}

/* Botón "Comprar a $X" debajo del caption + hashtags. Compartido entre immersive
   y detail. Tratamiento visual = action-btn[data-key="share"].viral-active:
   bg accent translúcido + glow continuo + spark rotateY del ícono. Conserva
   proporciones de botón (no chip) + ancho auto. */
.slide-buy-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
    padding: 9px 16px;
    border: 0;
    border-radius: 20px;
    background: color-mix(in srgb, var(--accent) 8%, transparent);
    color: var(--accent);
    font-weight: 700;
    font-size: 13px;
    text-transform: uppercase;
    letter-spacing: .04em;
    cursor: pointer;
    transition: transform .12s, background .15s;
    max-width: 100%;
    text-align: left;
    line-height: 1.25;
    animation: share-glow 2.2s ease-in-out infinite;
}
.slide-buy-btn:hover {
    background: color-mix(in srgb, var(--accent) 16%, transparent);
}
.slide-buy-btn .slide-buy-label { color: var(--accent); }
.slide-buy-btn:active { transform: scale(.97); }
.slide-buy-btn i { width: 16px; height: 16px; flex-shrink: 0; }
.slide-buy-btn-icon {
    color: var(--accent);
    animation: spark 2.6s linear infinite;
    transform-origin: center;
    transform-style: preserve-3d;
}
@media (prefers-reduced-motion: reduce) {
    .slide-buy-btn,
    .slide-buy-btn-icon { animation: none; }
}

/* Modifier overlay: btn flotando sobre la media en mural/cronología.
   position:absolute bottom-left. z-index debajo del tap overlay (6) pero
   sobre la media. Padre debe ser position:relative (mediaWrap ya lo es). */
.slide-buy-btn--overlay {
    position: absolute;
    left: 12px;
    bottom: 12px;
    z-index: 4;
    margin-top: 0;
}
.slide-buy-label { white-space: normal; }
/* Sub-pieza cashback dentro del label — peso normal + alpha bajo para
   jerarquía visual sobre el CTA principal "Comprar a $X". */
.slide-buy-cashback {
    font-weight: 600;
    opacity: .75;
    font-size: 12px;
}

.slide-caption.expanded {
    max-height: 200px;
}

.caption-toggle {
    font-size: 12px;
    color: rgba(255, 255, 255, .45);
    cursor: pointer;
}

.caption-toggle:hover {
    color: var(--accent);
}

.badge-v {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    vertical-align: middle;
    line-height: 1;
    margin-left: 3px;
    background: var(--accent);
    color: #000;
    font-size: 9px;
    font-weight: 700;
    padding: 2px 5px;
    border-radius: 20px;
}

.slide-tag {
    font-size: calc(var(--bs-body-font-size) - 2px);
    font-weight: 500;
    color: var(--accent);
    cursor: pointer;
}

.slide-music {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 10px;
    background: rgba(255, 255, 255, .08);
    border: 1px solid rgba(255, 255, 255, .12);
    border-radius: 30px;
    padding: 5px 12px;
    overflow: hidden;
    max-width: 280px;
}

.slide-music i {
    font-size: calc(var(--bs-body-font-size) - 2px);
    color: var(--accent);
    flex-shrink: 0;
}

.music-track {
    overflow: hidden;
    flex: 1;
    font-size: calc(var(--bs-body-font-size) - 2px);
    color: rgba(255, 255, 255, .65);
    white-space: nowrap;
}

.music-track span {
    display: inline-block;
    animation: ticker 14s linear infinite;
}

@keyframes ticker {
    0% {
        transform: translateX(0)
    }

    100% {
        transform: translateX(-50%)
    }
}

/* ── SLIDE ACTIONS ── columna derecha (TikTok-style) en immersive Y detail. */
.slide-actions {
    position: absolute;
    right: 12px;
    bottom: 20px;
    z-index: 3;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
}

/* Avatar inline al lado del username (immersive only). Reemplaza el avatar grande
   de la columna derecha que ahora está oculto en immersive. Detail conserva el grande. */
.slide-username-row {
    display: flex;
    align-items: center;
    gap: 8px;
}
.slide-username-avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
    border: 1.5px solid rgba(255,255,255,.85);
    background: #555;
}
.slide-username-avatar-fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-weight: 700;
    font-size: 14px;
}

/* Buy chip en slide-meta (immersive). Badge accent al lado de fecha/cat. */
/* .slide-buy-chip REMOVIDO — immersive ahora usa .slide-buy-btn (igual que detail)
   debajo del caption + hashtags, no chip en slide-meta. */

/* Hashtags chip en slide-meta (immersive). Color accent, peso medio. */
.slide-tag-chip {
    color: var(--accent);
    font-weight: 500;
}

/* Badge de categoría clickeable (slide-cat / card-cat / ig-cat con clase
   .cat-clickable). Click → switchView('explore') + auto-filtrar.
   Cursor pointer + hover sutil para indicar interactividad. */
.cat-clickable {
    cursor: pointer;
    transition: color .15s, opacity .15s;
}
.cat-clickable:hover {
    color: var(--accent);
    opacity: 1;
}

.action-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    background: none;
    border: none;
    color: #fff;
    cursor: pointer;
    border-radius: 12px;
    transition: transform .15s, background .15s;
    width: 52px;
}

.action-btn:hover {
    text-shadow: 0px 0px 10px var(--accent);
    transform: scale(1.08);
}

.action-btn:active {
    transform: scale(.93);
}

.action-btn .action-icon {
    font-size: 23px;
    line-height: 1;
    display: block;
}

.action-btn .action-icon svg {
    width: 1em;
    height: 1em;
    display: block;
}

.action-btn span {
    font-size: calc(var(--bs-body-font-size) - 2px);
    font-weight: 500;
    opacity: .85;
}

.action-btn.liked .action-icon,
.action-btn.liked .action-icon svg,
.action-btn.liked span,
.action-btn.saved .action-icon,
.action-btn.saved .action-icon svg {
    color: var(--accent);
}

.action-btn.liked .action-icon svg,
.action-btn.saved .action-icon svg {
    fill: var(--accent);
}

/* Highlight del share btn SOLO si el post tiene bolsa viral > 0 (clase
   .viral-active aplicada por JS según post.viral_pool_credits). Sin bolsa,
   el btn queda igual que like/comment/save (default style).
   Refleja honestamente al user: bg accent + sparkles = vas a ganar créditos
   compartiendo; sin highlight = solo compartir, sin reward. */
/* Buy btn (immersive + detail + cronología): mismo tratamiento visual que share
   viral-active pero SIEMPRE activo. Ícono wallet glow + spark rotateY. Sin label.
   data-key="buy" se appendea solo si post.price > 0. */
.action-btn[data-key="buy"] .action-icon,
.card-action-btn[data-key="buy"] .action-icon,
.ig-action-btn[data-key="buy"] .action-icon {
    background: color-mix(in srgb, var(--accent) 8%, transparent);
    border-radius: 50%;
    padding: 10px;
    animation: share-glow 2.2s ease-in-out infinite;
}
.action-btn[data-key="buy"] .action-icon svg,
.card-action-btn[data-key="buy"] .action-icon svg,
.ig-action-btn[data-key="buy"] .action-icon svg {
    animation: spark 2.6s linear infinite;
    transform-origin: center;
    transform-style: preserve-3d;
    color: var(--accent);
}
@media (prefers-reduced-motion: reduce) {
    .action-btn[data-key="buy"] .action-icon,
    .action-btn[data-key="buy"] .action-icon svg,
    .card-action-btn[data-key="buy"] .action-icon,
    .card-action-btn[data-key="buy"] .action-icon svg,
    .ig-action-btn[data-key="buy"] .action-icon,
    .ig-action-btn[data-key="buy"] .action-icon svg { animation: none; }
}

.action-btn[data-key="share"].viral-active .action-icon,
.card-action-btn[data-key="share"].viral-active .action-icon,
.ig-action-btn[data-key="share"].viral-active .action-icon {
    background: color-mix(in srgb, var(--accent) 8%, transparent);
    border-radius: 50%;
    padding: 10px;
    animation: share-glow 2.2s ease-in-out infinite;
}

.action-btn[data-key="share"].viral-active .action-icon svg,
.card-action-btn[data-key="share"].viral-active .action-icon svg,
.ig-action-btn[data-key="share"].viral-active .action-icon svg {
    animation: spark 2.6s linear infinite;
    transform-origin: center;
    transform-style: preserve-3d;
    color: var(--accent);
}

/* Spark = trompo visto desde un lado (rotación 3D en eje Y).
   Linear timing + porcentajes controlan la velocidad por fase:
     0→45%   : 4 vueltas rápidas (0° → 1440°).
     45→78%  : 1 vuelta lenta (1440° → 1800°) → desaceleración.
     78→100% : pausa breve antes de reiniciar.
   Termina en 1800° = 5*360° → loop visualmente perfecto (snap a 0 invisible). */
@keyframes spark {
    0%   { transform: rotateY(0deg); }
    45%  { transform: rotateY(1440deg); }
    78%  { transform: rotateY(1800deg); }
    100% { transform: rotateY(1800deg); }
}

/* Share-glow: pulsa box-shadow Y background-color en sincronía.
   En el pico del shadow, el bg sube de .08 a .25 → el efecto se siente
   sólido, no como un halo separado del icono. */
@keyframes share-glow {

    0%,
    100% {
        box-shadow: 0 0 0 0 transparent;
        background-color: color-mix(in srgb, var(--accent) 8%, transparent);
    }

    50% {
        box-shadow: 0 0 16px 2px color-mix(in srgb, var(--accent) 55%, transparent);
        background-color: color-mix(in srgb, var(--accent) 25%, transparent);
    }
}

@media (prefers-reduced-motion: reduce) {
    .action-btn[data-key="share"].viral-active .action-icon,
    .action-btn[data-key="share"].viral-active .action-icon svg,
    .card-action-btn[data-key="share"].viral-active .action-icon,
    .card-action-btn[data-key="share"].viral-active .action-icon svg,
    .ig-action-btn[data-key="share"].viral-active .action-icon,
    .ig-action-btn[data-key="share"].viral-active .action-icon svg {
        animation: none;
    }
}

.action-avatar {
    width: 43px;
    height: 43px;
    border-radius: 50%;
    border: 2px solid #fff;
    background: #555;
    overflow: hidden;
    cursor: pointer;
    margin-bottom: 2px;
    transition: border-color .15s;
}

.action-avatar:hover {
    border-color: var(--accent);
}

.action-avatar img,
.comment-avatar img,
.profile-pic img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.follow-plus {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--accent);
    color: #000;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    font-weight: 700;
    cursor: pointer;
    margin-top: -10px;
    margin-bottom: 6px;
    border: 2px solid #fff;
    transition: transform .15s;
}

.follow-plus:hover {
    transform: scale(1.2);
}

.follow-plus.following {
    background: var(--purple);
    color: #fff;
}

.heart-burst {
    position: absolute;
    z-index: 10;
    font-size: 72px;
    color: var(--accent);
    pointer-events: none;
    animation: heartPop .75s ease-out forwards;
}

@keyframes heartPop {
    0% {
        transform: scale(0);
        opacity: 1
    }

    50% {
        transform: scale(1.3);
        opacity: 1
    }

    100% {
        transform: scale(1.1);
        opacity: 0
    }
}

.pause-overlay {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) scale(0);
    z-index: 5;
    font-size: 60px;
    color: rgba(255, 255, 255, .8);
    pointer-events: none;
    opacity: 0;
    transition: transform .15s, opacity .2s;
}

.pause-overlay.visible {
    transform: translate(-50%, -50%) scale(1);
    opacity: 1;
}

/* Tap overlay (immersive) MIGRADO a js/tap-overlay.js + css/tap-overlay.css.
   Las clases viejas (.slide-tap-overlay, .slide-tap-btn, .slide-tap-btn-corner)
   fueron reemplazadas por .tap-overlay, .tap-overlay-btn, .tap-overlay-btn--tr. */

/* ── BOTTOM SHEET (base shared por todos los drawers) ── */
.bottom-sheet {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    /* max-height escalonado:
       - 80vh   = fallback para browsers viejos (incluye system bar).
       - 80dvh  = altura visible REAL (excluye system bar dinámica/estática en
                  Android moderno). Fix para Samsung A15/S9 donde 80vh dejaba
                  parte inferior detrás de la barra de navegación. */
    max-height: 80vh;
    max-height: 80dvh;
    background: var(--drawer-bg);
    color: var(--text);
    border-top-left-radius: 18px;
    border-top-right-radius: 18px;
    z-index: 999;
    transform: translateY(100%);
    transition: transform .25s cubic-bezier(.4, 0, .2, 1);
    /* Respeta la barra de navegacion software de Android (botones home/back).
       En celulares con gestos = 0. En celulares con barra clasica = ~48-56dp.
       Combinado con dvh, doble protección contra contenido tapado.
       max() garantiza un mínimo de 12px aunque env() retorne 0 (bug conocido
       en Samsung Internet y Chrome Android viejos que no reportan el inset
       correctamente aún con viewport-fit=cover). */
    padding-bottom: max(env(safe-area-inset-bottom, 0px), 0px);
}

.bottom-sheet.open {
    transform: translateY(0);
}

.bottom-sheet--above-nav {
    bottom: var(--nb-h);
    z-index: 100;
}

.bottom-sheet-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, .6);
    z-index: 998;
    opacity: 0;
    pointer-events: none;
    transition: opacity .2s;
}

.bottom-sheet-backdrop.open {
    opacity: 1;
    pointer-events: auto;
}

.bottom-sheet-backdrop--above-nav {
    bottom: var(--nb-h);
    z-index: 99;
}

.bottom-sheet-header {
    cursor: grab;
    user-select: none;
    touch-action: none;
}

.drawer-handle {
    cursor: grab;
    touch-action: none;
}

/* ── COMMENTS DRAWER (overrides especificos) ── */
#comments-drawer {
    max-height: 70vh;
}

.drawer-handle {
    width: 36px;
    height: 4px;
    border-radius: 2px;
    background: rgba(255, 255, 255, .2);
    margin: 10px auto 0;
}

[data-theme="light"] .drawer-handle {
    background: rgba(0, 0, 0, .2);
}

.comments-list::-webkit-scrollbar {
    width: 3px;
}

.comments-list::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, .15);
    border-radius: 2px;
}

.comment-avatar {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: #555;
    overflow: hidden;
    flex-shrink: 0;
}

.comment-like {
    color: var(--text-muted) !important;
    text-decoration: none !important;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.comment-like:hover {
    color: var(--accent) !important;
}

.comment-like.liked {
    color: var(--accent) !important;
}

.comment-like.liked svg {
    fill: var(--accent);
}

/* ── Reply quote (cita inline en comentarios que son respuesta) ──
   Aparece encima del texto del comentario cuando reply_to_id está poblado.
   Borde izquierdo accent + bloque atenuado con @user + snippet truncado 2 líneas.
   Click → scroll suave al comentario padre. */
.comment-reply-quote {
    display: flex;
    gap: 8px;
    background: color-mix(in srgb, var(--accent) 8%, transparent);
    border-left: 3px solid var(--accent);
    padding: 4px 8px;
    border-radius: 6px;
    margin-bottom: 4px;
    cursor: pointer;
    max-width: 100%;
}
.comment-reply-quote-user {
    color: var(--accent);
    font-weight: 700;
    font-size: 11px;
    margin-bottom: 2px;
}
.comment-reply-quote-snippet {
    color: var(--text);
    opacity: .75;
    font-size: 12px;
    line-height: 1.3;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.comment-reply-quote-text {
    flex: 1;
    min-width: 0;   /* permite truncate del snippet */
}
/* Highlight cuando se navega a un comment padre via cita. Pulse breve. */
.comment-item.highlight-target {
    animation: comment-pulse 1.4s ease-out;
}
@keyframes comment-pulse {
    0%   { background: color-mix(in srgb, var(--accent) 25%, transparent); }
    100% { background: transparent; }
}

/* ── Pill "Respondiendo a..." encima del input del drawer ── */
.comment-reply-pill {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    background: var(--card-bg);
    border-top: 1px solid var(--border-clr);
    flex-shrink: 0;
}
.comment-reply-pill[hidden] { display: none; }
.comment-reply-pill-bar {
    width: 3px;
    align-self: stretch;
    background: var(--accent);
    border-radius: 2px;
    flex-shrink: 0;
}
.comment-reply-pill-text {
    flex: 1;
    min-width: 0;
}
.comment-reply-pill-user {
    color: var(--accent);
    font-weight: 700;
    font-size: 12px;
}
.comment-reply-pill-snippet {
    color: var(--text);
    opacity: .7;
    font-size: 12px;
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.comment-reply-pill-close {
    background: transparent;
    border: 0;
    color: var(--text-muted);
    cursor: pointer;
    width: 28px;
    height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    padding: 0;
    flex-shrink: 0;
}
.comment-reply-pill-close:hover {
    background: color-mix(in srgb, var(--text) 10%, transparent);
}
.comment-reply-pill-close i { width: 16px; height: 16px; }

.drawer-input {
    flex: 1;
    background: var(--input-bg);
    border: 1px solid var(--border-clr);
    border-radius: 20px;
    color: var(--text);
    font-family: 'Ubuntu', sans-serif;
    font-size: 13px;
    padding: 8px 14px;
    outline: none;
}

.drawer-input::placeholder {
    color: var(--text-muted);
}

/* ── EXPLORE ── */
.explore-search {
    width: 100%;
    background: var(--input-bg);
    border: 1px solid var(--border-clr);
    border-radius: 12px;
    color: var(--text);
    font-family: 'Ubuntu', sans-serif;
    font-size: 14px;
    padding: 9px 14px 9px 38px;
    outline: none;
}

.explore-search::placeholder {
    color: var(--text-muted);
}

.explore-search:focus {
    border-color: color-mix(in srgb, var(--text) 25%, transparent);
}

.search-icon {
    position: absolute;
    left: 11px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--text-muted);
    font-size: 16px;
    pointer-events: none;
}

/* ─── Barra de progreso de navegación (top loading bar) ──────────────
   Aparece arriba al cambiar de vista (nav inferior). Avanza por hitos
   REALES (fetch resuelto, DOM construido) — ver NavProgress en shorts.js.
   La vista anterior queda visible hasta que la nueva está lista → cero
   pantalla negra. Color = var(--accent) → cambia con el tema/modo elegido. */
#nav-progress-bar {
    position: fixed;
    top: 0;
    left: 0;
    height: 3px;
    width: 0;
    background: var(--accent);
    box-shadow: 0 0 10px var(--accent), 0 0 4px var(--accent);
    border-radius: 0 3px 3px 0;
    z-index: 100000;
    opacity: 0;
    pointer-events: none;
    transition: width .25s ease, opacity .2s ease;
}
#nav-progress-bar.active {
    opacity: 1;
}

#explore-scroll {
    scrollbar-width: thin;
}

#explore-scroll::-webkit-scrollbar {
    width: 3px;
}

#explore-scroll::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, .15);
    border-radius: 2px;
}

#explore-grid {
    padding: 2px 0.5rem 0.5rem;   /* horizontal = px-2 (0.5rem) para alinear con el header */
    display: grid;
    align-content: start;
    gap: 3px;
    grid-template-columns: repeat(3, 1fr);
}

#explore-grid.layout-2 {
    grid-template-columns: repeat(2, 1fr);
    gap: 5px;
}

#explore-grid.layout-1 {
    grid-template-columns: 1fr;
    gap: 8px;
}

/* Modo Explorar→Usuarios: lista vertical (un usuario debajo del otro), NO grid.
   Mayor especificidad (#id.clase) que vence el `display:grid` del #explore-grid. */
/* Selector maestro del modal "Filtrar explorar": NO es un filtro más, define
   de qué dependen los filtros de abajo. Tratado como control segmentado dentro
   de una card tintada para que se lea distinto a las secciones de filtro. */
/* Bolita indicadora de modo en el botón de filtros: icono publicaciones/usuarios. */
.explore-filter-dot {
    position: absolute; top: -6px; right: -6px;
    width: 20px; height: 20px; border-radius: 50%;
    font-size: 10px;
    background: var(--accent); color: #000;
    border: 2px solid #000;
    display: flex; align-items: center; justify-content: center;
}
.explore-filter-dot i { width: 10px; height: 10px; }

/* Tooltip one-shot del botón de filtros (NO es toast): caret apuntando al
   botón, texto normal (sin negrilla). Prefiere arriba; baja solo si el botón
   está pegado al borde superior (flip estándar de tooltip). */
.explore-filter-tip {
    position: absolute; z-index: 1200; max-width: 240px;
    background: var(--accent); color: #000;
    font-size: 12.5px; font-weight: 400; line-height: 1.4;
    padding: 10px 12px; border-radius: 10px;
    box-shadow: 0 6px 24px rgba(0, 0, 0, .4);
}
.explore-filter-tip::after {
    content: ''; position: absolute; right: 16px;
    border-left: 7px solid transparent; border-right: 7px solid transparent;
}
.explore-filter-tip.tip-above::after { bottom: -7px; border-top: 7px solid var(--accent); }
.explore-filter-tip.tip-below::after { top: -7px; border-bottom: 7px solid var(--accent); }

/* Grupo de filtros: título dinámico ata las secciones al toggle (sin borde/inset). */
.explore-filters-group {
    display: flex; flex-direction: column; gap: 12px;
}
.efg-title-row {
    display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
.efg-title {
    display: flex; align-items: center; gap: 6px;
    font-size: 12px; font-weight: 700; color: var(--accent);
}
.efg-title i { width: 14px; height: 14px; }
.efg-reset {
    display: inline-flex; align-items: center; gap: 4px;
    background: transparent; border: none; cursor: pointer;
    color: var(--text-muted); font-size: 12px; font-weight: 600;
}
.efg-reset i { width: 13px; height: 13px; }
.efg-reset:hover { color: var(--accent); }

/* Dos botones (Publicaciones / Usuarios) con "o" en medio. */
.ett-or-row {
    display: flex; align-items: center; gap: 10px;
}
.ett-pill {
    flex: 1; display: flex; align-items: center; justify-content: center; gap: 6px;
    padding: 10px; border-radius: 10px;
    border: 1px solid var(--border-clr);
    font-size: 13px; font-weight: 700; cursor: pointer;
    background: rgba(255, 255, 255, .04); color: var(--text-muted);
    transition: background .15s, color .15s, border-color .15s;
}
.ett-pill i { width: 16px; height: 16px; }
.ett-pill.active { background: var(--accent); border-color: var(--accent); color: #000; box-shadow: 0 1px 4px rgba(0, 0, 0, .25); }
.ett-hint {
    display: flex; align-items: center; gap: 5px;
    font-size: 11px; color: var(--text-muted); margin-top: 8px; line-height: 1.3;
}
.ett-hint i { width: 13px; height: 13px; flex-shrink: 0; }

/* Toggle GPS "Cerca de mí" — compacto, al lado del input de Lugar.
   Excluyente con el texto: activo = usa ubicación real, ignora el campo. */
.euf-gps-toggle {
    flex-shrink: 0; display: inline-flex; align-items: center; gap: 5px;
    padding: 0 12px; border-radius: 10px;
    border: 1px solid var(--border-clr); background: rgba(255, 255, 255, .04);
    color: var(--text-muted); font-size: 13px; font-weight: 700; cursor: pointer;
    transition: background .15s, color .15s, border-color .15s;
}
.euf-gps-toggle i { width: 16px; height: 16px; }
.euf-gps-toggle.active {
    background: var(--accent); border-color: var(--accent); color: #000;
    box-shadow: 0 1px 4px rgba(0, 0, 0, .25);
}
#euf-place:disabled { opacity: .55; cursor: not-allowed; }

/* ── Media picker (GIFs/imágenes/video/stickers) ── */
.mp-tabs { display: flex; gap: 6px; overflow-x: auto; }
.mp-tab {
    flex: 0 0 auto; display: inline-flex; align-items: center; gap: 5px;
    padding: 7px 12px; border-radius: 99px;
    border: 1px solid var(--border-clr); background: rgba(255, 255, 255, .04);
    color: var(--text-muted); font-size: 12px; font-weight: 700; cursor: pointer;
    transition: background .15s, color .15s, border-color .15s;
}
.mp-tab i { width: 14px; height: 14px; }
.mp-tab.active { background: var(--accent); border-color: var(--accent); color: #000; }
#media-picker-grid {
    display: grid; gap: 4px;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    grid-auto-rows: min-content; align-content: start;
}
.mp-item {
    position: relative; padding: 0; border: none; cursor: pointer;
    aspect-ratio: 1 / 1; min-height: 0; border-radius: 8px; overflow: hidden;
    background: rgba(255, 255, 255, .05);
}
/* img absoluto = fuera de flujo → no empuja el alto del item (evita que las
   filas se solapen verticalmente). El alto lo fija aspect-ratio del botón. */
.mp-item img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
/* Item sin poster (p.ej. video sin thumbnail): badge centrado sobre fondo neutro. */
.mp-item-noimg { background: linear-gradient(135deg, rgba(255,255,255,.08), rgba(255,255,255,.03)); }
.mp-item-noimg .mp-badge { inset: 0; bottom: auto; right: auto; margin: auto; width: fit-content; height: fit-content; align-self: center; }
.mp-badge {
    position: absolute; bottom: 4px; right: 4px;
    display: inline-flex; align-items: center; justify-content: center;
    padding: 1px 5px; border-radius: 5px;
    background: rgba(0, 0, 0, .6); color: #fff;
    font-size: 9px; font-weight: 800; letter-spacing: .04em;
}
.mp-badge i { width: 11px; height: 11px; }
/* Crédito Unsplash (ToS): nombre del fotógrafo, clickeable, sobre el tile. */
.mp-credit {
    position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
    padding: 10px 6px 3px; font-size: 10px; line-height: 1.1; color: #fff;
    cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    background: linear-gradient(to top, rgba(0, 0, 0, .65), transparent);
}
.mp-credit:hover { text-decoration: underline; }
.mp-empty {
    grid-column: 1 / -1; text-align: center; padding: 32px 16px;
    color: var(--text-muted); font-size: 13px; line-height: 1.4;
}

/* Chip preview del adjunto elegido (composer de comentarios / chat). */
.media-chip {
    position: relative; display: inline-flex; align-items: center; gap: 8px;
    /* align-self:flex-start → en un parent flex-column NO se estira a full width;
       encoge al contenido (thumb + label + X). width:fit-content refuerza. */
    align-self: flex-start; width: fit-content;
    margin: 6px 0; padding: 5px 8px;
    background: rgba(255, 255, 255, .05); border: 1px solid var(--border-clr);
    border-radius: 10px; max-width: 220px;
}
.media-chip img { width: 42px; height: 42px; object-fit: cover; border-radius: 6px; flex-shrink: 0; }
.media-chip-label { font-size: 12px; color: var(--text-muted); text-transform: capitalize; }
.media-chip-remove {
    display: inline-flex; align-items: center; justify-content: center;
    width: 22px; height: 22px; border-radius: 50%; border: none; cursor: pointer;
    background: rgba(0, 0, 0, .4); color: #fff;
}
.media-chip-remove i { width: 13px; height: 13px; }

/* Media dentro de un comentario renderizado. */
.comment-media {
    margin-top: 6px; border-radius: 10px; overflow: hidden;
    max-width: 200px; cursor: pointer; display: block;
}
.comment-media img, .comment-media video { width: 100%; display: block; border-radius: 10px; }

/* Botón media en el composer de chat. */
.chat-media-btn {
    flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px; border-radius: 50%; border: none; cursor: pointer;
    background: transparent; color: var(--text-muted);
}
.chat-media-btn i { width: 20px; height: 20px; }
.chat-media-btn:hover { color: var(--accent); }
/* Media dentro de una burbuja de chat. */
.chat-bubble-media { display: block; max-width: 220px; border-radius: 10px; margin-top: 4px; }
.chat-bubble.has-media { max-width: 260px; }

#explore-grid.explore-users {
    display: grid;
    grid-template-columns: 1fr;   /* móvil: 1 columna (más ancho → se ven los chips) */
    gap: 10px;
    padding: 10px;
}
/* Diseño elegido en filtros: columnas explícitas (1/2/3). Mayor especificidad
   (id + 2 clases) → gana sobre el default de arriba en cualquier viewport. */
#explore-grid.explore-users.euser-cols-1 { grid-template-columns: 1fr; }
#explore-grid.explore-users.euser-cols-2 { grid-template-columns: repeat(2, 1fr); }
#explore-grid.explore-users.euser-cols-3 { grid-template-columns: repeat(3, 1fr); }

/* En 3 columnas la card es angosta: achicar tipografía del overlay y ocultar
   chips/handle para que no se amontone. */
#explore-grid.euser-cols-3 .euser-card-handle,
#explore-grid.euser-cols-3 .euser-card-chips { display: none; }
#explore-grid.euser-cols-3 .euser-card-name { font-size: 13px; }
#explore-grid.euser-cols-3 .euser-card-meta { font-size: 10px; }
#explore-grid.euser-cols-3 .euser-card-follow { padding: 4px 9px; font-size: 11px; }

/* Card de usuario estilo "dating": foto grande portrait + overlay con info.
   Objetivo: que la foto venda el perfil y de ganas de seguir. */
.euser-card {
    position: relative;
    aspect-ratio: 3 / 4;
    border-radius: 16px;
    overflow: hidden;
    cursor: pointer;
    background:
        linear-gradient(90deg, var(--card-bg) 0%, rgba(255, 255, 255, .10) 50%, var(--card-bg) 100%);
    background-size: 200% 100%;
    animation: explore-shimmer 1.2s linear infinite;
    content-visibility: auto;
    contain-intrinsic-size: auto 260px;
}
.euser-card.no-photo { animation: none; }

.euser-card-img {
    width: 100%; height: 100%;
    object-fit: cover; display: block;
    opacity: 0; transition: opacity .25s ease-out;
}
.euser-card-img.loaded { opacity: 1; }

.euser-card-fallback {
    width: 100%; height: 100%;
    display: flex; align-items: center; justify-content: center;
    font-size: 54px; font-weight: 800;
    color: var(--text-muted);
    background: var(--card-bg);
}

.euser-card-overlay {
    position: absolute; left: 0; right: 0; bottom: 0;
    padding: 32px 11px 11px;
    background: linear-gradient(to top, rgba(0, 0, 0, .92) 0%, rgba(0, 0, 0, .55) 50%, transparent 100%);
    color: #fff;
    pointer-events: none;
}
/* Tipografía igualada al feed: nombre = body, handle/meta = body−3px, chips = body−4px. */
.euser-card-name {
    font-weight: 700; font-size: var(--bs-body-font-size); line-height: 1.2;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.euser-card-handle {
    font-size: calc(var(--bs-body-font-size) - 3px); opacity: .8;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.euser-card-meta {
    font-size: calc(var(--bs-body-font-size) - 3px); opacity: .9; margin-top: 3px;
    display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
}
.euser-card-chips {
    display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px;
    max-height: 54px; overflow: hidden;
}
.euser-card-chip {
    display: inline-flex; align-items: center; gap: 3px;
    font-size: calc(var(--bs-body-font-size) - 4px); line-height: 1.4;
    border-radius: 6px; padding: 2px 8px;
}
.euser-card-chip i { width: 12px; height: 12px; }
/* Categoría que le gusta → relleno accent (resalta, es el gancho). */
.euser-card-chip--cat {
    background: var(--accent); border: 1px solid var(--accent);
    color: #000; font-weight: 600;
}
/* Idioma → translúcido neutro + icono languages. */
.euser-card-chip--lang {
    background: rgba(255, 255, 255, .16); border: 1px solid rgba(255, 255, 255, .3);
    color: #fff;
}
/* "+N" → indica que hay más (idiomas o categorías) sin listarlos todos. */
.euser-card-chip--more {
    background: rgba(255, 255, 255, .1); border: 1px solid rgba(255, 255, 255, .22);
    color: #fff; font-weight: 600;
}

/* Contador de likes clickeable (abre la lista de quién dio me gusta). El icono
   sigue toggleando; solo el número abre el sheet. */
.like-count-clickable { cursor: pointer; }
.like-count-clickable:hover { text-decoration: underline; }

.euser-card-follow {
    position: absolute; top: 9px; right: 9px; z-index: 2;
    border: none; border-radius: 99px;
    padding: 6px 13px; font-size: 12px; font-weight: 700;
    cursor: pointer;
    -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.euser-card-follow.is-follow { background: var(--accent, #ffb800); color: #000; }
.euser-card-follow.is-following {
    background: rgba(0, 0, 0, .5); color: #fff;
    border: 1px solid rgba(255, 255, 255, .45);
}

/* ── Visor de fotos de perfil (carrusel fullscreen, swipe nativo) ──────
   Se abre al tocar la foto de perfil. Swipe = scroll-snap horizontal
   (sin math de touch). Flechas solo en escritorio (hover/fine pointer). */
.photo-viewer {
    position: fixed; inset: 0; z-index: 3000;
    background: rgba(0, 0, 0, .96);
}
.photo-viewer-track {
    display: flex; width: 100%; height: 100%;
    overflow-x: auto; overflow-y: hidden;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}
.photo-viewer-track::-webkit-scrollbar { display: none; }
.photo-viewer-slide {
    flex: 0 0 100%; width: 100%; height: 100%;
    scroll-snap-align: center;
    display: flex; align-items: center; justify-content: center;
}
.photo-viewer-slide img { max-width: 100%; max-height: 100%; object-fit: contain; }
.photo-viewer-close {
    position: absolute; z-index: 2;
    top: calc(env(safe-area-inset-top, 0px) + 12px); right: 14px;
    width: 40px; height: 40px; border-radius: 50%;
    background: rgba(0, 0, 0, .5); border: none; color: #fff;
    display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.photo-viewer-counter {
    position: absolute; z-index: 2;
    top: calc(env(safe-area-inset-top, 0px) + 18px); left: 50%; transform: translateX(-50%);
    color: #fff; font-size: 13px; font-weight: 600;
    background: rgba(0, 0, 0, .4); padding: 4px 12px; border-radius: 99px;
}
.photo-viewer-nav {
    position: absolute; z-index: 2; top: 50%; transform: translateY(-50%);
    width: 44px; height: 44px; border-radius: 50%;
    background: rgba(0, 0, 0, .45); border: none; color: #fff;
    display: none; align-items: center; justify-content: center; cursor: pointer;
}
.photo-viewer-nav.prev { left: 14px; }
.photo-viewer-nav.next { right: 14px; }
@media (hover: hover) and (pointer: fine) { .photo-viewer-nav { display: flex; } }
.photo-viewer-dots {
    position: absolute; z-index: 2;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 16px); left: 50%; transform: translateX(-50%);
    display: flex; gap: 6px;
}
.photo-viewer-dots span { width: 7px; height: 7px; border-radius: 50%; background: rgba(255, 255, 255, .35); }
.photo-viewer-dots span.on { background: #fff; }

.explore-card {
    position: relative;
    border-radius: 6px;
    overflow: hidden;
    cursor: pointer;
    /* Shimmer placeholder: gradiente animado mientras la img carga.
       Cuando la img tiene .loaded (set en JS al disparar 'load'), su
       opacity pasa a 1 y cubre el shimmer.
       Contraste alto a propósito — el delta entre stops define qué
       tan perceptible es la "ola" del barrido. */
    background:
        linear-gradient(90deg,
            var(--card-bg) 0%,
            rgba(255,255,255,.10) 50%,
            var(--card-bg) 100%);
    background-size: 200% 100%;
    animation: explore-shimmer 1.2s linear infinite;
    aspect-ratio: 9/11;
    /* content-visibility: cards fuera del viewport NO se renderizan ni
       paintean. Browser solo procesa las visibles. Al volver a Explorar
       desde otra view, repaint solo de las visibles → fast switch.
       contain-intrinsic-size reserva espacio para off-screen (auto =
       recuerda tamaño tras primer paint). */
    content-visibility: auto;
    contain-intrinsic-size: auto 244px;
}

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

.explore-card img {
    opacity: 0;
    transition: opacity .25s ease-out;
}
.explore-card img.loaded {
    opacity: 1;
}

/* Cuando la img/video del card YA cargó, frenar el shimmer del CONTENEDOR y dejar
   un fondo sólido neutro. Sin esto, los PNG transparentes dejan ver la "ola" del
   shimmer del padre a través de sus zonas transparentes (el shimmer es background
   del .explore-card, no de la img). El listener global de shorts.js marca .loaded
   en la img al disparar 'load' → :has() reacciona solo. */
.explore-card:has(img.loaded),
.explore-card:has(video.loaded) {
    background: var(--card-bg);
    animation: none;
}

/* ── SHIMMER DE CARGA GLOBAL (default app-wide) ───────────────────────────
   Replica el efecto de Explorar (.explore-card) en TODA img/video de la app:
   "ola" animada mientras el recurso carga; al terminar, JS le pone .loaded y
   se frena. En <img> además fade-in (opacity 0→1). En <video> NO tocamos
   opacity (para que el poster nunca quede invisible) — solo la ola de fondo.
   Reusa @keyframes explore-shimmer. Opt-out: clase .no-shimmer (logos, íconos,
   sprites que no deban parpadear). El JS que marca .loaded está en shorts.js. */
img:not(.loaded):not(.no-shimmer),
video:not(.loaded):not(.no-shimmer) {
    background-image: linear-gradient(90deg,
        var(--card-bg) 0%, rgba(255, 255, 255, .10) 50%, var(--card-bg) 100%);
    background-size: 200% 100%;
    background-repeat: no-repeat;
    animation: explore-shimmer 1.2s linear infinite;
}
img:not(.no-shimmer) { opacity: 0; transition: opacity .25s ease-out; }
img.loaded, img.no-shimmer { opacity: 1; }
img.loaded, video.loaded { animation: none; background-image: none; }

#explore-grid.layout-1 .explore-card {
    aspect-ratio: 16/10;
    border-radius: 10px;
}

.explore-card img,
.explore-card video,
.profile-post img,
.profile-post video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.explore-card-overlay {
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(0, 0, 0, .7), transparent 50%);
    color: #fff;
    opacity: 0;
    transition: opacity .2s;
    display: flex;
    align-items: flex-end;
    padding: 8px;
}

[data-theme="light"] .explore-card-overlay {
    background: linear-gradient(to top, rgba(255, 255, 255, .85), transparent 50%);
    color: #1a1a1a;
}

.explore-card:hover .explore-card-overlay {
    opacity: 1;
}

.explore-video-badge {
    position: absolute;
    top: 6px;
    right: 6px;
    background: rgba(0, 0, 0, .6);
    color: #fff;
    border-radius: 4px;
    padding: 2px 5px;
    font-size: 10px;
}

[data-theme="light"] .explore-video-badge {
    background: rgba(255, 255, 255, .75);
    color: #1a1a1a;
}

.explore-empty {
    grid-column: 1/-1;
    color: var(--text-muted);
}

.layout-btn {
    color: var(--text-muted);
    transition: background .15s, color .15s;
}

.layout-btn.active {
    color: var(--text);
    background: var(--surface);
}

/* ── INSTALL BANNER ── */
#installContainer {
    z-index: 1090;
}

/* ── PROFILE ── */
.profile-header {
    border-bottom: 1px solid var(--border-clr);
}

.profile-pic {
    width: 86px;
    height: 86px;
    border-radius: 50%;
    border: 3px solid var(--accent);
    background: #555;
    overflow: hidden;
    cursor: pointer;
}

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

.profile-post {
    aspect-ratio: 1;
    overflow: hidden;
    cursor: pointer;
    position: relative;
    background: var(--card-bg);
}

/* Profile stats — clickable tabs */
.profile-stat {
    cursor: pointer;
    padding: 4px 6px;
    border-radius: 8px;
    transition: background .15s;
}

.profile-stat:hover {
    background: var(--surface);
}

.profile-stat .small {
    color: var(--text-muted);
}

.profile-stat.active .fs-5,
.profile-stat.active .small {
    color: var(--accent);
}

/* User list (followers / following) */
.profile-grid.user-list {
    display: block;
    padding: 0;
    gap: 0;
}

.user-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 16px;
    border-bottom: 1px solid var(--border-clr);
}

.user-row-avatar {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    overflow: hidden;
    flex-shrink: 0;
    background: var(--surface);
    display: flex;
    align-items: center;
    justify-content: center;
}

.user-row-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.user-row-info {
    min-width: 0;
}

.user-row-action {
    border: 0 !important;
    border-radius: 999px !important;
    padding: 6px 14px !important;
    font-size: 12px !important;
    font-weight: 600 !important;
    flex-shrink: 0;
}

.user-row-action.user-row-action-on {
    background: var(--purple) !important;
    color: #fff !important;
}

.user-row-action.user-row-action-on:hover {
    background: var(--purple-hover) !important;
}

/* User-row content clickable cursor */
.user-row-avatar,
.user-row-info {
    cursor: pointer;
}

/* Profile follow header button (perfil ajeno) */
#profile-follow-btn.profile-follow-on {
    background: var(--purple) !important;
    color: #fff !important;
    border: 0 !important;
}

#profile-follow-btn.profile-follow-on:hover {
    background: var(--purple-hover) !important;
}

/* ── SETTINGS ── */
.theme-opt {
    flex: 1 1 calc(33.33% - 8px);
    min-width: 80px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 12px 8px;
    border-radius: 14px;
    border: 2px solid var(--border-clr);
    background: var(--surface);
    color: var(--text);
    font-family: 'Ubuntu', sans-serif;
    cursor: pointer;
    transition: border-color .15s, background .15s;
    text-align: center;
}

.theme-opt.active {
    border-color: var(--accent);
    background: rgba(232, 255, 71, .08);
}

[data-theme="light"] .theme-opt.active {
    border-color: #b8cc00;
    background: rgba(0, 0, 0, .06);
}

/* ── NAVBAR ── */
#navbar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    height: calc(var(--nb-h) + env(safe-area-inset-bottom, 0px));
    padding-bottom: env(safe-area-inset-bottom, 0px);
    background: var(--nb-bg);
    border-top: 1px solid var(--border-clr);
    z-index: 200;
}

.nb-btn {
    color: var(--text-muted);
    cursor: pointer;
    transition: color .15s;
    font-family: 'Ubuntu', sans-serif;
}

.nb-btn span {
    font-size: 10px;
    font-weight: 500;
}

.nb-btn.active {
    color: var(--accent);
}

[data-theme="light"] .nb-btn.active {
    color: #1a1a1a;
}

/* Badge de notificaciones no leídas — overlay sobre el icono `bell` del navbar.
   Se inyecta vía JS (updateNotificationsBadge). El .nb-btn necesita position:
   relative para que el badge se posicione respecto al botón. */
.nb-btn {
    position: relative;
}
.notif-badge {
    position: absolute;
    top: 4px;
    right: calc(50% - 22px);
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 999px;
    background: #FF4D4D;
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
    pointer-events: none;
}

/* ── CREATE ── */
#view-create {
    overflow: hidden;
}

.create-type-btn {
    color: var(--text-muted);
    transition: background .15s, color .15s;
}

.create-type-btn.active {
    background: var(--accent) !important;
    color: #000 !important;
}

/* Botones de visibilidad (Pública / Privada) en el form Crear */
/* Pill-toggle reusable (botones en parejas tipo Pública/Privada,
   Porcentaje/Fijo, Imagen/Video, etc). El comportamiento de toggle (active)
   lo maneja cada wire en JS — esta clase solo es VISUAL. Para evitar
   wires accidentalmente cruzados, cada grupo de toggles debe scopear su
   querySelectorAll por su propio data-attribute, NO por esta clase. */
.create-toggle-pill,
.create-vis-btn /* alias legado: misma apariencia */ {
    padding: 8px 12px;
    border: 1px solid var(--border-clr);
    background: var(--surface);
    color: var(--text-muted);
    border-radius: 10px;
    font-size: 13px;
    cursor: pointer;
    transition: background .15s, color .15s, border-color .15s;
}
.create-toggle-pill.active,
.create-vis-btn.active {
    background: var(--accent);
    color: #000;
    border-color: var(--accent);
}

.create-file-trigger {
    width: 100%;
    border: 2px dashed var(--border-clr);
    border-radius: 14px;
    padding: 28px 16px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    background: var(--surface);
    color: var(--text-muted);
    font-size: 13px;
    transition: border-color .15s, color .15s;
}

.create-file-trigger:hover {
    border-color: var(--accent);
    color: var(--accent);
}

.create-file-trigger i {
    font-size: 32px;
}

.create-media-preview {
    position: relative;
    width: 100%;
    border-radius: 12px;
    overflow: hidden;
    background: var(--card-bg);
    margin-top: 10px;
}

/* ── Flujo "Desde URL": hint, picker, loading ── */
.create-url-hint {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 16px;
    margin-top: 10px;
    background: var(--surface);
    border: 1px dashed var(--border-clr);
    border-radius: 12px;
    color: var(--text-muted);
    font-size: 13px;
    line-height: 1.4;
}
.create-url-hint[hidden] { display: none; }
.create-url-hint-icon {
    width: 20px;
    height: 20px;
    color: var(--accent);
    flex-shrink: 0;
}
.create-url-hint-text { flex: 1; }

.create-url-picker {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-top: 10px;
    padding: 10px;
    background: var(--surface);
    border: 1px solid var(--border-clr);
    border-radius: 12px;
}
.create-url-picker[hidden] { display: none; }
.create-url-picker-title {
    font-size: 12px;
    color: var(--text-muted);
    margin-bottom: 4px;
    padding: 0 4px;
}
.create-url-picker-opt {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    background: var(--card-bg);
    border: 1px solid var(--border-clr);
    border-radius: 10px;
    color: var(--text);
    font-size: 12px;
    cursor: pointer;
    text-align: left;
    transition: border-color .15s, background .15s;
}
.create-url-picker-opt:hover {
    border-color: var(--accent);
    background: var(--input-bg);
}
.create-url-picker-opt i {
    width: 16px;
    height: 16px;
    color: var(--accent);
    flex-shrink: 0;
}
.create-url-picker-opt-text {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.create-url-loading {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 40px 20px;
    background: var(--card-bg);
    min-height: 180px;
}
.create-url-loading .spinner-border {
    width: 32px;
    height: 32px;
}

/* ── Error card cuando la URL no permite extracción (403, bloqueo, etc) ── */
.create-url-error {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 18px 16px;
    background: var(--card-bg);
}
.create-url-error-head {
    display: flex;
    align-items: flex-start;
    gap: 10px;
}
.create-url-error-icon {
    width: 20px;
    height: 20px;
    color: #f87171;     /* rojo suave */
    flex-shrink: 0;
    margin-top: 2px;
}
.create-url-error-tech {
    flex: 1;
    color: var(--text);
    font-size: 13px;
    font-weight: 600;
    line-height: 1.35;
}
.create-url-error-explain {
    color: var(--text-muted);
    font-size: 12px;
    line-height: 1.5;
    padding: 10px 12px;
    background: var(--surface);
    border-left: 3px solid rgba(248, 113, 113, .5);
    border-radius: 0 6px 6px 0;
}
.create-url-error-tip {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 10px 12px;
    background: var(--surface);
    border: 1px solid var(--border-clr);
    border-radius: 8px;
    color: var(--text);
    font-size: 12px;
    line-height: 1.4;
}
.create-url-error-tip i {
    width: 16px;
    height: 16px;
    color: var(--accent);
    flex-shrink: 0;
    margin-top: 2px;
}
.create-url-error-tip b {
    color: var(--accent);
    font-weight: 600;
}

/* ── Badge de cobertura geográfica (post.coverage_*) ─────────────
   Visible en los 3 renderers (TikTok / Twitter / Instagram). Anchor
   nativo que abre Google Maps en nueva pestaña. Click ya hace
   stopPropagation desde el HTML para no disparar el click del slide
   (post-detail). ────────────────────────────────────────────────── */
.post-coverage {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 1px 7px;
    border-radius: 99px;
    background: rgba(255, 255, 255, .08);
    color: var(--text);   /* blanco en dark, casi negro en light — sigue tema */
    font: inherit;        /* hereda tipografía del contexto (card-meta-line, etc) */
    border: 0;            /* reset <button> */
    cursor: pointer;
    text-decoration: none !important;
    line-height: 1.4;
    transition: background .15s, color .15s;
    vertical-align: baseline;
}
.post-coverage:hover {
    background: var(--accent);
    color: #000;
}
.post-coverage i,
.post-coverage svg {
    width: 12px;
    height: 12px;
    stroke-width: 2.2;
}
.card-cov-sep {
    color: rgba(255, 255, 255, .35);
    margin: 0 2px;
}
/* En tema claro */
[data-theme="light"] .post-coverage {
    background: rgba(0, 0, 0, .06);
}
[data-theme="light"] .card-cov-sep {
    color: rgba(0, 0, 0, .35);
}

/* MOBILE override REMOVIDO — antes ocultaba label/radio del post-coverage en
   cronología (<=600px) para no competir con username/handle/tiempo. User
   pidió que se vea completo igual que en las otras vistas. */

/* ── Overlay con botones flotantes sobre el preview de imagen/video ── */
.preview-overlay {
    position: absolute;
    inset: 0;
    pointer-events: none;  /* deja pasar clicks al video; los hijos los recapturan */
}

.preview-overlay-toolbar {
    position: absolute;
    top: 10px;
    right: 10px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    pointer-events: auto;
}

.preview-overlay-btn {
    width: 38px;
    height: 38px;
    border-radius: 50%;
    border: 0;
    background: rgba(0, 0, 0, .55);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background .15s, transform .15s;
    padding: 0;
}
.preview-overlay-btn:hover {
    background: var(--accent);
    color: #000;
    transform: scale(1.05);
}
.preview-overlay-btn:active { transform: scale(.95); }
.preview-overlay-btn svg {
    width: 18px;
    height: 18px;
    stroke-width: 2.2;
}

/* Play button central — solo video, oculto durante reproducción */
.preview-play-btn {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 64px;
    height: 64px;
    border-radius: 50%;
    border: 0;
    background: rgba(0, 0, 0, .65);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    pointer-events: auto;
    transition: opacity .2s, transform .15s, background .15s;
    padding: 0;
}
.preview-play-btn:hover {
    background: var(--accent);
    color: #000;
}
.preview-play-btn:active { transform: translate(-50%, -50%) scale(.92); }
.preview-play-btn svg {
    width: 28px;
    height: 28px;
    margin-left: 3px;  /* ajuste óptico del triángulo play */
    fill: currentColor;
    stroke: currentColor;
}
.create-media-preview.preview-playing .preview-play-btn {
    opacity: 0;
    pointer-events: none;
}

/* Cursor pointer sobre el video preview (indica que es clickeable) */
.create-media-preview video {
    cursor: pointer;
}

/* Botón "🎨 Filtros" debajo del preview (solo imágenes) */
.create-filter-btn {
    width: 100%;
    margin-top: 8px;
    padding: 10px;
    border-radius: 10px;
    border: 1px solid var(--border-clr);
    background: var(--surface);
    color: var(--text);
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    transition: border-color .15s, color .15s;
}
.create-filter-btn:hover { border-color: var(--accent); color: var(--accent); }
.create-filter-btn[hidden] { display: none; }

/* Bootstrap d-flex tiene !important — sobrescribir cuando hidden */
#create-image-tools[hidden],
#create-video-tools[hidden] { display: none !important; }

/* Badge "Privada" en la línea meta del slide */
.slide-private {
    color: #ffd54f;
    font-weight: 600;
}

/* ─── FEED VIEW MODES ────────────────────────────────────────────────
   El #feed tiene class .feed-mode-tiktok | .feed-mode-twitter | .feed-mode-instagram
   según la vista activa. CSS adapta scroll, layout y aparición de elementos.
   ──────────────────────────────────────────────────────────────────── */

/* TikTok mode (vista actual): scroll-snap obligatorio, slides full-viewport.
   El CSS existente para .slide ya cubre este modo. */
.feed-mode-tiktok {
    scroll-snap-type: y mandatory;
    overflow-y: auto;
    height: 100%;
}

/* Timeline modes (Twitter / Instagram): scroll libre sin snap. */
.feed-mode-twitter,
.feed-mode-instagram {
    scroll-snap-type: none;
    overflow-y: auto;
    height: 100%;
    background: var(--bg);
}

/* En timeline modes, los .slide ya NO son full-viewport. Reset height. */
.feed-mode-twitter .slide,
.feed-mode-instagram .slide {
    height: auto !important;
    scroll-snap-align: none;
    background: transparent;
}

/* ─── TWITTER / X CARDS ─── */
.feed-card-twitter {
    display: block;
    background: var(--card-bg);
    border-bottom: 1px solid var(--border-clr);
    padding: 14px 14px 8px;
    color: var(--text);
}
.feed-card-twitter .card-header {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin-bottom: 8px;
}
.feed-card-twitter .card-avatar {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    flex-shrink: 0;
    object-fit: cover;
    background: var(--surface);
}
.feed-card-twitter .card-avatar-fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 18px;
    color: var(--text-muted);
}
.feed-card-twitter .card-user { flex: 1; min-width: 0; }
.feed-card-twitter .card-name {
    font-weight: 700;
    font-size: 14px;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.feed-card-twitter .card-meta-line {
    font-size: 12px;
    color: var(--text-muted);
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px 6px;
}
.feed-card-twitter .card-handle { color: var(--text-muted); }
.feed-card-twitter .card-private { color: #ffd54f; font-weight: 600; }
.feed-card-twitter .card-caption {
    font-size: 14.5px;
    line-height: 1.45;
    color: var(--text);
    margin-bottom: 10px;
    white-space: pre-wrap;
    word-break: break-word;
}
.feed-card-twitter .card-media-wrap {
    position: relative;
    border-radius: 14px;
    overflow: hidden;
    background: #000;
    margin-bottom: 8px;
    max-height: 432px;
}
.feed-card-twitter .card-media-wrap img,
.feed-card-twitter .card-media-wrap video {
    display: block;
    width: 100%;
    max-height: 432px;
    object-fit: contain;
}
/* Defensa contra controles nativos del video: aunque `controls=false` y
   `controlslist` ya están en JS, algunos browsers exponen UI de controles
   bajo ciertas condiciones. Estas reglas garantizan que no se muestren. */
.feed-card-twitter .card-media-wrap video::-webkit-media-controls,
.feed-card-twitter .card-media-wrap video::-webkit-media-controls-enclosure,
.feed-card-twitter .card-media-wrap video::-webkit-media-controls-panel {
    display: none !important;
    -webkit-appearance: none;
}
.feed-card-twitter .card-media-wrap video {
    pointer-events: none;   /* el click va al card-media-wrap, no al video */
}
.feed-card-twitter .card-mute-btn-overlay {
    position: absolute;
    top: 10px;
    right: 10px;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    border: 0;
    background: rgba(0,0,0,.55);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    z-index: 2;
}

/* "Ver más" link: aparece al lado del caption en las 3 vistas (Twitter/IG/Immersive).
   Abre bottom-sheet con info expandida. Color accent para destacar como CTA. */
.more-info-link {
    background: transparent;
    border: 0;
    padding: 0;
    color: var(--accent);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    margin-left: 4px;
    display: inline;
}
.more-info-link:hover { text-decoration: underline; }

/* Caption Twitter: container + line-clamp 3 lines visual truncate. */
.feed-card-twitter .card-caption-wrap {
    padding: 0 12px 8px;
    font-size: 14px;
    color: var(--text);
    line-height: 1.4;
}
.feed-card-twitter .card-caption {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* .ig-extras + .ig-price-chip + .card-price-chip REMOVIDOS — mural/cronología
   migraron a .slide-buy-btn--overlay sobre la media. Coverage badge mural
   ahora vive en ig-footer junto a la fecha. */

/* IG caption con line-clamp 3 lines. */
.feed-card-instagram .ig-caption {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* Sheet de control de audio: info compacta + slider de volumen + mute btn. */
.audio-ctrl-info {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px;
    background: rgba(255,255,255,.04);
    border: 1px solid var(--border-clr);
    border-radius: 12px;
    margin-bottom: 12px;
}
.audio-ctrl-info i { width: 22px; height: 22px; color: var(--accent); flex-shrink: 0; }
.audio-ctrl-title { font-weight: 700; color: var(--text); font-size: 14px; }
.audio-ctrl-sub { color: var(--text-muted); font-size: 12px; }
.audio-ctrl-row {
    display: flex;
    align-items: center;
    gap: 10px;
}
.audio-ctrl-mute {
    background: var(--accent);
    color: var(--bg);
    border: 0;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    flex-shrink: 0;
}
.audio-ctrl-mute i { width: 16px; height: 16px; }
.audio-ctrl-slider {
    flex: 1;
    accent-color: var(--accent);
}
.audio-ctrl-pct {
    font-weight: 700;
    color: var(--text);
    min-width: 36px;
    text-align: right;
    font-size: 13px;
}

/* ── Sheet "Información de la publicación" — visual rico, no labels stackeados ── */
.more-info-grid {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 12px;
}
.mi-card {
    background: rgba(255,255,255,.04);
    border: 1px solid var(--border-clr);
    border-radius: 14px;
    overflow: hidden;
}
[data-theme="light"] .mi-card {
    background: rgba(0,0,0,.025);
}
.mi-card-h {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    font-size: 13px;
    font-weight: 700;
    color: var(--text);
    border-bottom: 1px solid var(--border-clr);
    background: rgba(255,255,255,.02);
}
.mi-card-h i { width: 16px; height: 16px; color: var(--accent); }
.mi-card-body {
    padding: 12px 14px;
    font-size: 13px;
    color: var(--text);
}
.mi-prose { line-height: 1.5; margin: 0; color: var(--text); }
.mi-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.mi-chip {
    background: rgba(255,255,255,.06);
    border: 1px solid var(--border-clr);
    border-radius: 99px;
    padding: 4px 10px;
    font-size: 12px;
    color: var(--text);
    white-space: nowrap;
}
.mi-chip-cat { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 35%, transparent); }
.mi-chip-tag { font-weight: 500; }
.mi-kv {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 4px 0;
    border-bottom: 1px dashed color-mix(in srgb, var(--border-clr) 60%, transparent);
}
.mi-kv:last-child { border-bottom: 0; }
.mi-k { color: var(--text-muted); font-size: 12px; }
.mi-v { color: var(--text); font-weight: 600; }
.mi-split { display: flex; flex-direction: column; gap: 8px; }
.mi-split-row {
    display: grid;
    grid-template-columns: 12px 1fr auto;
    gap: 8px;
    align-items: center;
    font-size: 13px;
}
.mi-split-dot { width: 10px; height: 10px; border-radius: 50%; }
.mi-split-lbl { color: var(--text-muted); }
.mi-split-val { color: var(--text); font-weight: 700; }
.mi-split-total {
    padding-top: 8px;
    border-top: 1px solid var(--border-clr);
    grid-template-columns: 1fr auto;
}
.mi-split-total .mi-split-lbl { color: var(--text); font-weight: 700; }
.mi-progress {
    height: 6px;
    background: rgba(255,255,255,.08);
    border-radius: 99px;
    overflow: hidden;
    margin-top: 8px;
}
.mi-progress-fill { height: 100%; background: var(--accent); transition: width .3s; }

/* Slide caption: line-clamp 3 líneas con "…" al final cuando trunca.
   IMPORTANTE: la regla base (línea ~475) NO debe tener max-height fijo o pisa
   el line-clamp y trunca antes (sin mostrar 3 líneas completas). */
.slide-caption {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
    max-height: none;
    cursor: pointer;
}
.feed-card-twitter .card-caption {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
    cursor: pointer;
}
.feed-card-twitter .card-tag {
    color: var(--accent);
    font-weight: 500;
    margin-right: 2px;
}
.feed-card-instagram .ig-caption,
.feed-card-instagram .ig-caption-text {
    cursor: pointer;
    text-overflow: ellipsis;
}

/* Widget de audio: SOLO mute btn. Pill circular overlay top-right.
   La info del audio se accede vía "ver más" del caption. */
.mute-info-widget {
    position: absolute;
    top: 10px;
    right: 10px;
    display: flex;
    align-items: center;
    z-index: 3;
}
.mute-info-btn-mute {
    background: rgba(0,0,0,.6);
    border: 0;
    color: #fff;
    cursor: pointer;
    padding: 0;
    width: 36px;
    height: 36px;
    border-radius: 100px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}
.mute-info-btn-mute i { width: 16px; height: 16px; }
.feed-card-twitter .card-actions {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 4px 0;
    max-width: 480px;
}
.feed-card-twitter .card-action-btn {
    display: flex;
    align-items: center;
    gap: 6px;
    background: transparent;
    border: 0;
    color: var(--text-muted);
    cursor: pointer;
    padding: 6px 8px;
    border-radius: 999px;
    font-size: 14px;
    transition: color .15s, background .15s;
}
.feed-card-twitter .card-action-btn:hover { background: rgba(255,255,255,.06); color: var(--text); }
.feed-card-twitter .card-action-btn.active { color: var(--accent); }
.feed-card-twitter .card-action-btn i { width: 16px; height: 16px; }

/* Tema claro: cards Twitter con fondo blanco + borde gris claro */
[data-theme="light"] .feed-card-twitter {
    background: #fff;
    border-bottom-color: rgba(0,0,0,.08);
}

/* ─── INSTAGRAM CARDS ─── */
.feed-card-instagram {
    display: block;
    background: var(--card-bg);
    border-bottom: 1px solid var(--border-clr);
    margin-bottom: 8px;
    color: var(--text);
}
.feed-card-instagram .card-header-ig {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
}
.feed-card-instagram .ig-avatar {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    object-fit: cover;
    background: var(--surface);
    flex-shrink: 0;
}
.feed-card-instagram .ig-avatar-fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 14px;
    color: var(--text-muted);
}
.feed-card-instagram .ig-user { flex: 1; min-width: 0; }
.feed-card-instagram .ig-name {
    font-weight: 700;
    font-size: 13.5px;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.feed-card-instagram .ig-meta {
    font-size: 11px;
    color: var(--text-muted);
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px 6px;
}
.feed-card-instagram .ig-private { color: #ffd54f; }
.feed-card-instagram .ig-tag {
    color: var(--accent);
    opacity: .85;
    font-weight: 500;
}

.feed-card-instagram .ig-media-wrap {
    position: relative;
    width: 100%;
    background: #000;
    /* Aspect ratio cuadrado por default — clásico Instagram */
    aspect-ratio: 1 / 1;
    overflow: hidden;
}
.feed-card-instagram .ig-media-wrap img,
.feed-card-instagram .ig-media-wrap video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.feed-card-instagram .ig-mute-overlay {
    position: absolute;
    bottom: 12px;
    right: 12px;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: 0;
    background: rgba(0,0,0,.6);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    z-index: 2;
}

.feed-card-instagram .ig-actions {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px 14px 4px;
}
.feed-card-instagram .ig-actions-left {
    display: flex;
    gap: 8px;
}
.feed-card-instagram .ig-action-btn {
    background: transparent;
    border: 0;
    color: var(--text);
    cursor: pointer;
    padding: 6px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: transform .15s, color .15s;
}
.feed-card-instagram .ig-action-btn i {
    width: 24px;
    height: 24px;
}
.feed-card-instagram .ig-action-count {
    margin-left: 6px;
    font-size: 13px;
    color: var(--text);
    font-weight: 600;
    line-height: 1;
}
.feed-card-instagram .ig-action-btn {
    /* Reaplica padding para alinear icono + count en una sola línea horizontal */
    padding: 6px 10px 6px 6px;
    border-radius: 999px;
}
.feed-card-instagram .ig-action-btn:hover { background: rgba(255,255,255,.06); }
.feed-card-instagram .ig-action-btn.active[data-key="like"] {
    color: #ff3b30;
}
.feed-card-instagram .ig-action-btn.active[data-key="like"] i {
    fill: #ff3b30;
}
.feed-card-instagram .ig-action-btn.active[data-key="bookmark"] i {
    fill: currentColor;
}
.feed-card-instagram .ig-action-btn:active {
    transform: scale(0.85);
}

.feed-card-instagram .ig-likes {
    padding: 0 14px 4px;
    font-size: 13.5px;
    color: var(--text);
}
.feed-card-instagram .ig-caption {
    padding: 2px 14px 4px;
    font-size: 13.5px;
    color: var(--text);
    line-height: 1.45;
    word-break: break-word;
}
.feed-card-instagram .ig-caption strong {
    margin-right: 4px;
}
.feed-card-instagram .ig-footer {
    padding: 4px 14px 12px;
    font-size: 11px;
    color: var(--text-muted);
    text-transform: lowercase;
}

/* Tema claro: cards Instagram con fondo blanco */
[data-theme="light"] .feed-card-instagram {
    background: #fff;
    border-bottom-color: rgba(0,0,0,.08);
}
.create-filter-applied-tag {
    position: absolute;
    top: 8px;
    left: 8px;
    z-index: 3;
    padding: 3px 10px;
    background: var(--accent);
    color: #000;
    font-size: 11px;
    font-weight: 700;
    border-radius: 99px;
    box-shadow: 0 2px 6px rgba(0,0,0,.35);
    pointer-events: none;
}

/* ─── FILTER EDITOR (pantalla completa) ─── */
#filter-editor-modal {
    background: #000 !important;
    color: #fff;
    z-index: 1080;
}

/* ════════════════════════════════════════════════════════════════
   MEDIA EDITOR — fullscreen, recipe-based (no-destructivo).
   Layout:
     [header / tool-header]
     [stage = preview img/video]
     [footer = toolbar O tool-controls]
   z-index 2000 (sobre todo lo demás, igual que cámara).
   Theme-aware: usa var(--bg)/--text/--accent del theme activo.
   ════════════════════════════════════════════════════════════════ */
.media-editor {
    position: fixed;
    inset: 0;
    z-index: 2000;
    background: var(--bg);
    color: var(--text);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.media-editor[hidden] { display: none !important; }

/* Header con padding safe-area top (notch) */
.me-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 10px 12px;
    padding-top: max(env(safe-area-inset-top, 0px), 12px);
    border-bottom: 1px solid var(--border-clr);
    flex-shrink: 0;
}
.me-header .me-title {
    font-size: 15px;
    font-weight: 700;
    flex: 1;
    text-align: center;
    color: var(--text);
}
.me-icon-btn {
    background: transparent;
    border: 0;
    color: var(--text);
    width: 38px;
    height: 38px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 8px;
    cursor: pointer;
    padding: 0;
}
.me-icon-btn:hover {
    background: color-mix(in srgb, var(--text) 10%, transparent);
}
.me-icon-btn i { width: 20px; height: 20px; }
.me-icon-btn-accent { color: var(--accent); }
.me-text-btn {
    background: transparent;
    border: 0;
    color: var(--accent);
    font-weight: 700;
    font-size: 14px;
    padding: 8px 14px;
    border-radius: 8px;
    cursor: pointer;
}
.me-text-btn:hover { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.me-text-btn:disabled { opacity: .4; cursor: not-allowed; }

/* Stage: bounded container entre header y footer. SIN nested flex — antes
   `display:flex; align-items:center` causaba sizing circular con el wrap
   (max-w/h:100%) → imágenes muy altas overflowearan el stage por debajo del
   footer. Ahora stage es solo un viewport con overflow:hidden. El centering
   y letterboxing los hace el img/video con object-fit:contain. */
.me-stage {
    flex: 1 1 auto;
    position: relative;
    overflow: hidden;
    background: var(--card-bg);
    min-height: 0;
}

/* Wrap del preview: rellena el stage al 100% via absolute inset:0 + flex
   center. Img interior usa max-w/h:100% sin width/height definidos → browser
   le da su tamaño natural CLAMPED a 100% del wrap manteniendo aspect ratio.
   Resultado: <img> element rect = visible image rect (sin letterbox dentro
   del element). El letterbox queda en el wrap (área alrededor del img).
   Crop tool usa img.getBoundingClientRect() directamente para imgBox. */
.me-preview-wrap {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
.me-preview-wrap.cropped {
    /* aspect-ratio + size se setean inline desde JS según recipe.crop */
}
.me-preview-img,
.me-preview-video {
    max-width: 100%;
    max-height: 100%;
    display: block;
    /* filter se setea inline desde JS según recipe.filter + adjust */
}
.me-preview-wrap.cropped .me-preview-img,
.me-preview-wrap.cropped .me-preview-video {
    position: absolute;
    max-width: none;
    max-height: none;
    object-fit: fill;
}

/* Overlay para herramientas que dibujan encima (crop frame, stickers, etc) */
.me-overlay {
    position: absolute;
    inset: 0;
    pointer-events: none;
    overflow: hidden;
}
/* touch-action:none = deshabilita scroll/pinch nativo del browser durante el
   drag. Sin esto, en móvil el gesto de mover el frame se interrumpe a mitad
   porque el browser intenta scrollear la página. */
.me-overlay.interactive { pointer-events: auto; touch-action: none; user-select: none; -webkit-user-select: none; }

/* Footer: toolbar O tool-controls (mutex via hidden attr) */
.me-footer {
    flex-shrink: 0;
    background: var(--bg);
    border-top: 1px solid var(--border-clr);
    padding-bottom: max(env(safe-area-inset-bottom, 0px), 0px);
}

/* Toolbar: scroll horizontal de tool chips */
.me-toolbar {
    display: flex;
    gap: 10px;
    padding: 14px 14px;
    overflow-x: auto;
    scrollbar-width: none;
}
.me-toolbar::-webkit-scrollbar { display: none; }
.me-tool-chip {
    flex-shrink: 0;
    background: transparent;
    border: 0;
    color: var(--text);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 8px 10px;
    border-radius: 10px;
    cursor: pointer;
    position: relative;
    min-width: 72px;
}
.me-tool-chip:hover { background: color-mix(in srgb, var(--text) 8%, transparent); }
.me-tool-chip i { width: 22px; height: 22px; color: var(--text); }
.me-tool-chip span { font-size: 12px; font-weight: 600; }
/* Badge dot cuando el tool tiene cambios aplicados (recipe.X !== null) */
.me-tool-chip.has-changes::after {
    content: '';
    position: absolute;
    top: 4px;
    right: 12px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 0 2px var(--bg);
}

/* Tool-controls: contenedor genérico donde cada tool monta su UI */
.me-tool-controls {
    padding: 12px 14px;
    max-height: 50vh;
    overflow-y: auto;
}

/* ───── Filter tool: strip horizontal de thumbnails ───── */
.me-filter-strip {
    display: flex;
    gap: 10px;
    overflow-x: auto;
    padding: 4px 0;
    scrollbar-width: none;
}
.me-filter-strip::-webkit-scrollbar { display: none; }
.me-filter-thumb {
    flex-shrink: 0;
    cursor: pointer;
    text-align: center;
    width: 72px;
}
.me-filter-thumb-img {
    width: 72px;
    height: 72px;
    border-radius: 10px;
    overflow: hidden;
    border: 2px solid transparent;
    background: var(--card-bg);
}
.me-filter-thumb.active .me-filter-thumb-img { border-color: var(--accent); }
.me-filter-thumb-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.me-filter-thumb-name {
    font-size: 11px;
    margin-top: 4px;
    color: var(--text);
    opacity: .85;
}

/* ───── Adjust tool: sliders ───── */
.me-adj-row { display: flex; flex-direction: column; gap: 4px; margin-bottom: 14px; }
.me-adj-row label {
    display: flex;
    justify-content: space-between;
    font-size: 13px;
    color: var(--text);
}
.me-adj-row label span { color: var(--accent); font-weight: 700; }
.me-adj-row input[type="range"] {
    width: 100%;
    accent-color: var(--accent);
}

/* ───── Crop tool: ratios chips + zoom slider ───── */
.me-crop-ratios { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 8px; scrollbar-width: none; }
.me-crop-ratios::-webkit-scrollbar { display: none; }
.me-crop-ratio-chip {
    flex-shrink: 0;
    background: transparent;
    color: var(--text);
    border: 1px solid var(--border-clr);
    border-radius: 999px;
    padding: 6px 12px;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
}
.me-crop-ratio-chip.active {
    background: var(--accent);
    color: #111;
    border-color: var(--accent);
}
.me-crop-zoom { display: flex; align-items: center; gap: 8px; margin-top: 8px; }
.me-crop-zoom input[type="range"] { flex: 1; accent-color: var(--accent); }
.me-crop-zoom .label { font-size: 12px; color: var(--text); opacity: .7; min-width: 36px; }
.me-crop-zoom .value { font-size: 12px; color: var(--accent); font-weight: 700; min-width: 40px; text-align: right; }

/* Crop overlay: frame + máscara (cuando crop tool está activo) */
.me-crop-frame {
    position: absolute;
    border: 2px solid #fff;
    box-shadow: 0 0 0 100vmax rgba(0,0,0,.55);
    box-sizing: border-box;
    touch-action: none;
    cursor: move;
}
.me-crop-corner { touch-action: none; }
.me-crop-grid {
    position: absolute;
    inset: 0;
    background:
        linear-gradient(to right, transparent calc(33.33% - 1px), rgba(255,255,255,.3) 33.33%, rgba(255,255,255,.3) calc(33.33% + 1px), transparent calc(33.33% + 1px)),
        linear-gradient(to right, transparent calc(66.66% - 1px), rgba(255,255,255,.3) 66.66%, rgba(255,255,255,.3) calc(66.66% + 1px), transparent calc(66.66% + 1px)),
        linear-gradient(to bottom, transparent calc(33.33% - 1px), rgba(255,255,255,.3) 33.33%, rgba(255,255,255,.3) calc(33.33% + 1px), transparent calc(33.33% + 1px)),
        linear-gradient(to bottom, transparent calc(66.66% - 1px), rgba(255,255,255,.3) 66.66%, rgba(255,255,255,.3) calc(66.66% + 1px), transparent calc(66.66% + 1px));
    pointer-events: none;
}
.me-crop-corner {
    position: absolute;
    width: 24px;
    height: 24px;
    cursor: grab;
}
.me-crop-corner::before, .me-crop-corner::after {
    content: '';
    position: absolute;
    background: var(--accent);
}
.me-crop-corner-tl { top: -2px; left: -2px; }
.me-crop-corner-tl::before { top: 0; left: 0; width: 14px; height: 3px; }
.me-crop-corner-tl::after  { top: 0; left: 0; width: 3px; height: 14px; }
.me-crop-corner-tr { top: -2px; right: -2px; }
.me-crop-corner-tr::before { top: 0; right: 0; width: 14px; height: 3px; }
.me-crop-corner-tr::after  { top: 0; right: 0; width: 3px; height: 14px; }
.me-crop-corner-bl { bottom: -2px; left: -2px; }
.me-crop-corner-bl::before { bottom: 0; left: 0; width: 14px; height: 3px; }
.me-crop-corner-bl::after  { bottom: 0; left: 0; width: 3px; height: 14px; }
.me-crop-corner-br { bottom: -2px; right: -2px; }
.me-crop-corner-br::before { bottom: 0; right: 0; width: 14px; height: 3px; }
.me-crop-corner-br::after  { bottom: 0; right: 0; width: 3px; height: 14px; }

/* ───── Trim tool: timeline + handles ───── */
.me-trim-info {
    display: flex;
    justify-content: space-between;
    font-size: 12px;
    color: var(--text);
    opacity: .8;
    margin-bottom: 8px;
}
.me-trim-timeline {
    position: relative;
    height: 56px;
    background: var(--card-bg);
    border-radius: 8px;
    overflow: hidden;
    touch-action: none;
    cursor: pointer;
}
/* Progress line más visible para que se vea como playhead */
.me-trim-progress {
    pointer-events: none;
    box-shadow: 0 0 6px rgba(255,255,255,.6);
}

/* Botón play/pause overlay del TrimTool — centrado en el stage del preview.
   Visible siempre, baja opacidad durante playback, alta durante pause.
   Pointer-events:auto para que sea clickeable encima del video. */
.me-trim-playpause {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 64px;
    height: 64px;
    border-radius: 50%;
    background: rgba(0, 0, 0, .55);
    border: 0;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    z-index: 5;
    transition: opacity .15s, background .15s;
    pointer-events: auto;
}
.me-trim-playpause i { width: 28px; height: 28px; }
.me-trim-playpause.playing { opacity: .35; }
.me-trim-playpause:hover { opacity: 1; background: rgba(0, 0, 0, .7); }
.me-trim-thumbs {
    display: flex;
    height: 100%;
}
.me-trim-thumbs canvas {
    height: 100%;
    flex: 1;
    display: block;
    object-fit: cover;
}
.me-trim-shade {
    position: absolute;
    top: 0;
    bottom: 0;
    background: rgba(0,0,0,.6);
}
.me-trim-progress {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 2px;
    background: #fff;
    pointer-events: none;
}
.me-trim-handle {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 14px;
    background: var(--accent);
    cursor: grab;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #111;
    z-index: 2;
}
.me-trim-handle::after {
    content: '';
    width: 2px;
    height: 22px;
    background: #111;
    border-radius: 2px;
}

/* Confirm dialog (descartar cambios) */
.me-confirm {
    position: absolute;
    inset: 0;
    z-index: 10;
    background: rgba(0,0,0,.65);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
}
.me-confirm-card {
    background: var(--drawer-bg);
    color: var(--text);
    border-radius: 14px;
    padding: 18px 18px 14px;
    max-width: 340px;
    width: 100%;
    box-shadow: 0 10px 40px rgba(0,0,0,.4);
}
.me-confirm-title { font-size: 15px; font-weight: 700; margin-bottom: 6px; }
.me-confirm-msg { font-size: 13px; opacity: .8; margin-bottom: 14px; line-height: 1.45; }
.me-confirm-actions { display: flex; gap: 8px; }
.me-confirm-actions button { flex: 1; padding: 10px; border-radius: 8px; border: 1px solid var(--border-clr); background: transparent; color: var(--text); font-weight: 600; cursor: pointer; }
.me-confirm-actions button.danger { background: #FF4D4D; color: #fff; border-color: transparent; }

.filter-editor-header {
    border-bottom: 1px solid rgba(255,255,255,.08);
    background: #000;
}
.filter-editor-preview {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #000;
    overflow: hidden;
    min-height: 0;
    padding: 12px;
}
.filter-editor-preview img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    display: block;
}
.filter-editor-tabs {
    border-top: 1px solid rgba(255,255,255,.08);
    border-bottom: 1px solid rgba(255,255,255,.08);
}
.filter-editor-tab {
    flex: 1;
    background: transparent;
    border: 0;
    color: var(--text-muted);
    padding: 12px;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
}
.filter-editor-tab.active {
    color: var(--text);
    border-bottom: 2px solid var(--accent);
}
.filter-editor-pane {
    flex-shrink: 0;
    background: #000;
}
#filter-editor-pane-filters {
    display: flex;
    gap: 10px;
    overflow-x: auto;
    padding: 14px 12px;
    scrollbar-width: thin;
}
.filter-thumb {
    flex: 0 0 auto;
    width: 72px;
    text-align: center;
    cursor: pointer;
    user-select: none;
}
.filter-thumb-img {
    width: 64px;
    height: 64px;
    border-radius: 10px;
    overflow: hidden;
    border: 2px solid transparent;
    margin: 0 auto;
}
.filter-thumb.active .filter-thumb-img {
    border-color: var(--accent);
}
.filter-thumb-img img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.filter-thumb-name {
    margin-top: 6px;
    font-size: 11px;
    color: var(--text-muted);
}
.filter-thumb.active .filter-thumb-name {
    color: var(--accent);
    font-weight: 700;
}
.filter-editor-adjustments {
    padding: 14px 16px 18px;
}
.adj-row {
    margin-bottom: 12px;
}
.adj-row label {
    display: flex;
    justify-content: space-between;
    font-size: 12px;
    color: var(--text-muted);
    margin-bottom: 4px;
}
.adj-row input[type="range"] {
    width: 100%;
    accent-color: var(--accent);
}

/* ─── CROP UI (vive dentro del editor unificado filter-editor-modal) ─── */
/* El modal contenedor ya está estilado por filter-editor + bottom-sheet. */
.crop-editor-stage {
    flex: 1 1 auto;
    position: relative;
    overflow: hidden;
    background: #000;
    touch-action: none;        /* deshabilita scroll/zoom nativo del browser */
    user-select: none;
    min-height: 0;
}
#crop-editor-img {
    position: absolute;
    left: 50%;
    top: 50%;
    transform-origin: center center;
    will-change: transform;
    pointer-events: none;       /* gestures van al stage, no a la imagen */
    max-width: none;
    max-height: none;
}

.crop-mask {
    position: absolute;
    background: rgba(0, 0, 0, .65);
    pointer-events: none;
}
.crop-frame {
    position: absolute;
    border: 1.5px solid #fff;
    box-sizing: border-box;
    pointer-events: none;       /* el stage maneja pan; corners reactivan eventos */
}
.crop-frame.is-free { pointer-events: auto; }
.crop-grid {
    position: absolute;
    inset: 0;
    background:
        linear-gradient(to right, rgba(255,255,255,.25) 1px, transparent 1px) 33.33% 0 / 33.34% 100% repeat-y,
        linear-gradient(to bottom, rgba(255,255,255,.25) 1px, transparent 1px) 0 33.33% / 100% 33.34% repeat-x;
    pointer-events: none;
}
.crop-corner {
    position: absolute;
    width: 22px;
    height: 22px;
    border: 3px solid #fff;
    background: transparent;
    pointer-events: auto;
    cursor: nwse-resize;
    display: none;
}
.crop-frame.is-free .crop-corner { display: block; }
.crop-corner-tl { left: -3px;  top: -3px;    border-right: none;  border-bottom: none; cursor: nwse-resize; }
.crop-corner-tr { right: -3px; top: -3px;    border-left:  none;  border-bottom: none; cursor: nesw-resize; }
.crop-corner-bl { left: -3px;  bottom: -3px; border-right: none;  border-top:    none; cursor: nesw-resize; }
.crop-corner-br { right: -3px; bottom: -3px; border-left:  none;  border-top:    none; cursor: nwse-resize; }

.crop-ratios { white-space: nowrap; }
.crop-ratio-chip {
    flex: 0 0 auto;
    padding: 6px 14px;
    border-radius: 99px;
    border: 1px solid rgba(255,255,255,.2);
    background: transparent;
    color: var(--text-muted);
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
}
.crop-ratio-chip.active {
    background: var(--accent);
    color: #000;
    border-color: var(--accent);
}
#crop-zoom { accent-color: var(--accent); }

/* ─── TRIM EDITOR ─── */
#trim-editor-modal { background: #000 !important; color: #fff; z-index: 1080; }

.trim-editor-preview {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    min-height: 0;
    background: #000;
    padding: 12px;
}
#trim-editor-video {
    max-width: 100%;
    max-height: 100%;
    display: block;
}

.trim-timeline {
    position: relative;
    height: 64px;
    border-radius: 8px;
    overflow: hidden;
    background: #111;
    user-select: none;
    touch-action: none;
}
.trim-thumbs {
    display: flex;
    height: 100%;
    width: 100%;
}
.trim-thumb {
    flex: 1 1 0;
    height: 100%;
    width: 0;            /* permite que flex-grow controle */
    object-fit: cover;
    border: 0;
    pointer-events: none;
    background: #222;
}
.trim-shade {
    position: absolute;
    top: 0;
    height: 100%;
    background: rgba(0, 0, 0, .65);
    pointer-events: none;
}
.trim-shade-left  { left: 0; }
.trim-shade-right { right: 0; }
.trim-handle {
    position: absolute;
    top: 0;
    width: 14px;
    height: 100%;
    background: var(--accent);
    cursor: ew-resize;
    z-index: 3;
    border-radius: 4px;
    box-shadow: 0 0 8px rgba(0,0,0,.5);
}
.trim-handle::before {
    content: '';
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 3px;
    height: 22px;
    background: #000;
    border-radius: 2px;
}
.trim-progress {
    position: absolute;
    top: 0;
    width: 2px;
    height: 100%;
    background: #fff;
    z-index: 2;
    /* pointer-events: auto para que el cursor cambie al pasar sobre la línea.
       El click bubbles al timeline donde el handler de scrub se encarga. */
    pointer-events: auto;
    cursor: ew-resize;
    box-shadow: 0 0 4px rgba(0,0,0,.6);
}
/* Knob al tope de la línea para affordance visual del scrub */
.trim-progress::before {
    content: '';
    position: absolute;
    top: -3px;
    left: 50%;
    transform: translateX(-50%);
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 4px rgba(0,0,0,.5);
    pointer-events: none;  /* el click va a la línea principal */
}
/* Cursor pointer sobre el área del timeline (indica que es scrubeable) */
.trim-timeline { cursor: pointer; }
.trim-handle   { cursor: ew-resize; }
/* Tap en el video del trim editor → toggle play/pause: indicador visual */
#trim-editor-video { cursor: pointer; }

/* Overlay global para procesos de video (compressVideo + trim).
   Layout premium: icono pulsante + título dinámico + stats + barra shimmer. */
.video-progress-overlay {
    position: fixed;
    inset: 0;
    background: radial-gradient(circle at 50% 40%, rgba(0,0,0,.85), rgba(0,0,0,.96));
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1090;
    color: #fff;
    animation: vp-overlay-in .25s ease-out;
}
.video-progress-overlay[hidden] { display: none !important; }

@keyframes vp-overlay-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

.vp-card {
    text-align: center;
    padding: 32px 28px 24px;
    max-width: 340px;
    width: calc(100% - 32px);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
}

/* ── Icono central con anillos pulsantes ── */
.vp-icon-wrap {
    position: relative;
    width: 64px;
    height: 64px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 4px;
}
.vp-icon-ring {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 2px solid var(--accent);
    opacity: 0;
    animation: vp-ring-pulse 2s ease-out infinite;
}
.vp-icon-ring-2 { animation-delay: 1s; }
@keyframes vp-ring-pulse {
    0%   { transform: scale(.6); opacity: .8; }
    100% { transform: scale(1.6); opacity: 0; }
}
.vp-icon {
    width: 28px;
    height: 28px;
    color: var(--accent);
    z-index: 1;
    animation: vp-icon-bob 2.4s ease-in-out infinite;
}
@keyframes vp-icon-bob {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-3px); }
}

/* ── Título + sub-mensaje (cross-fade al cambiar de intento) ── */
.vp-title {
    font-weight: 700;
    font-size: 18px;
    line-height: 1.2;
    transition: opacity .3s ease;
}
.vp-submsg {
    font-size: 13px;
    line-height: 1.4;
    color: rgba(255,255,255,.7);
    max-width: 280px;
    transition: opacity .3s ease;
}
.vp-title.fading, .vp-submsg.fading { opacity: 0; }

/* ── Stats antes/objetivo ── */
.vp-stats {
    display: flex;
    align-items: center;
    gap: 14px;
    background: rgba(255,255,255,.04);
    border: 1px solid rgba(255,255,255,.08);
    border-radius: 12px;
    padding: 10px 16px;
    margin-top: 4px;
}
.vp-stats[hidden] { display: none; }
.vp-stat-item { display: flex; flex-direction: column; gap: 2px; min-width: 56px; }
.vp-stat-label {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: rgba(255,255,255,.5);
}
.vp-stat-value {
    font-weight: 600;
    font-size: 14px;
    color: #fff;
}
.vp-stat-target .vp-stat-value { color: var(--accent); }
.vp-stat-arrow {
    color: rgba(255,255,255,.4);
    display: flex;
    align-items: center;
}
.vp-stat-arrow svg { width: 16px; height: 16px; }

/* ── Barra de progreso con shimmer ── */
.vp-bar-wrap {
    position: relative;
    width: 240px;
    max-width: 80vw;
    height: 8px;
    border-radius: 99px;
    background: rgba(255, 255, 255, .08);
    overflow: hidden;
    margin: 6px auto 0;
}
.vp-bar-fill {
    position: absolute;
    top: 0; left: 0; bottom: 0;
    width: 0;
    /* Fallback para browsers sin color-mix (<Chrome 111, <Firefox 113) */
    background: var(--accent);
    background: linear-gradient(90deg, var(--accent), color-mix(in srgb, var(--accent) 70%, #fff));
    border-radius: 99px;
    transition: width .4s cubic-bezier(.4,0,.2,1);
}
.vp-bar-shimmer {
    position: absolute;
    inset: 0;
    background: linear-gradient(90deg,
        transparent 0%,
        rgba(255,255,255,.35) 50%,
        transparent 100%);
    background-size: 60% 100%;
    background-repeat: no-repeat;
    animation: vp-bar-shimmer 1.6s linear infinite;
    pointer-events: none;
    mix-blend-mode: overlay;
}
@keyframes vp-bar-shimmer {
    0%   { background-position: -60% 0; }
    100% { background-position: 160% 0; }
}

.vp-pct {
    font-size: 22px;
    font-weight: 700;
    letter-spacing: .02em;
    color: #fff;
    margin-top: 4px;
}

.vp-meta {
    font-size: 12px;
    color: rgba(255,255,255,.55);
    display: flex;
    gap: 6px;
}
.vp-meta-sep { color: rgba(255,255,255,.3); }

/* ── Tip rotativo ── */
.vp-tip {
    display: flex;
    align-items: center;
    gap: 8px;
    background: rgba(255,255,255,.05);
    border: 1px solid rgba(255,255,255,.08);
    border-radius: 10px;
    padding: 10px 14px;
    font-size: 12px;
    color: rgba(255,255,255,.75);
    max-width: 300px;
    transition: opacity .35s ease;
    text-align: left;
    line-height: 1.35;
}
.vp-tip[hidden] { display: none; }
.vp-tip.fading { opacity: 0; }
.vp-tip-icon { color: var(--accent); flex-shrink: 0; width: 14px; height: 14px; }

/* ── Info técnica (chiquita, opacidad baja, para quien sepa) ── */
.vp-tech {
    font-size: 10px;
    color: rgba(255,255,255,.32);
    font-family: ui-monospace, 'SF Mono', Menlo, monospace;
    letter-spacing: .02em;
    min-height: 14px;
    margin-top: 2px;
}
.vp-tech:empty { display: none; }

.vp-cancel-btn {
    background: transparent;
    color: rgba(255,255,255,.7);
    border: 1px solid rgba(255,255,255,.18);
    border-radius: 99px;
    padding: 7px 18px;
    font-size: 12px;
    margin-top: 6px;
    cursor: pointer;
    transition: background .15s, color .15s;
}
.vp-cancel-btn:hover {
    background: rgba(255,255,255,.08);
    color: #fff;
}
.vp-cancel-btn:disabled {
    opacity: .5;
    cursor: not-allowed;
}

/* ── Estado de éxito (check verde al terminar) ── */
.vp-card.vp-done .vp-icon-wrap { animation: vp-icon-success .4s ease-out; }
.vp-card.vp-done .vp-icon-ring { animation: none; opacity: 0; }
.vp-card.vp-done .vp-icon { color: #4ade80; animation: none; }
@keyframes vp-icon-success {
    0%   { transform: scale(1); }
    50%  { transform: scale(1.15); }
    100% { transform: scale(1); }
}

/* ═══════════════════════════════════════════════════════════════
   COMPRESSION PRE-FLIGHT — bottom-sheet rediseñado.
   Hero antes/después + grilla 2x2 + nota.
   ═══════════════════════════════════════════════════════════════ */
.cp-body { padding: 16px; }

/* Hero: comparativa actual → objetivo con badge de reducción */
.cp-hero {
    display: flex;
    align-items: stretch;
    gap: 8px;
    margin-bottom: 16px;
}
.cp-hero-side {
    flex: 1;
    background: rgba(255, 255, 255, .04);
    border: 1px solid var(--border-clr);
    border-radius: 14px;
    padding: 14px;
    text-align: center;
}
.cp-hero-target {
    background: color-mix(in srgb, var(--accent) 10%, transparent);
    border-color: color-mix(in srgb, var(--accent) 30%, transparent);
}
.cp-hero-label {
    font-size: 11px;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: .06em;
    margin-bottom: 4px;
}
.cp-hero-value {
    font-size: 20px;
    font-weight: 700;
    color: var(--text);
    line-height: 1.2;
}
.cp-hero-target .cp-hero-value { color: var(--accent); }

.cp-hero-arrow {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 0 4px;
    color: var(--text-muted);
}
.cp-hero-arrow i { width: 20px; height: 20px; }
.cp-hero-badge {
    background: var(--accent);
    color: #000;
    font-weight: 700;
    font-size: 11px;
    padding: 2px 8px;
    border-radius: 999px;
    margin-top: 2px;
}
.cp-hero-badge::before { content: '−'; }

/* Grilla 2x2 con datos del video */
.cp-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
}
.cp-cell {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px;
    background: rgba(255, 255, 255, .04);
    border: 1px solid var(--border-clr);
    border-radius: 12px;
}
.cp-cell-icon {
    width: 18px;
    height: 18px;
    color: var(--accent);
    flex-shrink: 0;
}
.cp-cell-label {
    font-size: 10px;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: .06em;
}
.cp-cell-value {
    font-size: 14px;
    font-weight: 700;
    color: var(--text);
    line-height: 1.2;
}

/* Nota informativa con ícono */
.cp-note {
    margin-top: 16px;
    padding: 12px;
    background: rgba(255, 193, 7, .08);
    border: 1px solid rgba(255, 193, 7, .25);
    border-radius: 10px;
    display: flex;
    align-items: flex-start;
    gap: 8px;
    font-size: 12px;
    color: var(--text);
    line-height: 1.45;
}
.cp-note i {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    color: #FFC107;
    margin-top: 1px;
}

/* Legacy (algunos llamados aún pueden insertar estas rows si no migran). */
.cp-info-row {
    display: flex;
    justify-content: space-between;
    padding: 10px 0;
    font-size: 13px;
    border-bottom: 1px solid var(--border-clr);
}
.cp-info-row:last-of-type { border-bottom: 0; }
.cp-info-row > span:first-child { color: var(--text-muted); }
.cp-info-row > span:last-child  { font-weight: 600; color: var(--text); }
.cp-info-row.cp-estimate > span:last-child { color: var(--accent); }

/* ─── Install toast (banner "Instala la app") ───
   Notificación flotante en la parte superior. Se cierra con la X (solo sesión —
   reaparece al recargar hasta que el user instale la PWA). */
.install-toast {
    position: fixed;
    top: 12px;
    left: 50%;
    transform: translateX(-50%);
    max-width: calc(100% - 24px);
    width: max-content;
    z-index: 1100;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px 10px 38px;     /* extra left para la X */
    background: rgba(255, 198, 26, .85);  /* dorado semi-transparente */
    color: #1a1a1a;
    border-radius: 999px;
    box-shadow: 0 6px 20px rgba(0, 0, 0, .25);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    font-size: 13px;
    line-height: 1.3;
    animation: installToastIn .25s ease-out;
}
.install-toast[hidden] { display: none !important; }

/* ════════════════════════════════════════════════════════════════
   CAMERA CAPTURE — visor fullscreen para foto/video in-app.
   Layout: stage (video preview) ocupa todo + header arriba + footer abajo.
   Diseño tipo Instagram/WhatsApp camera. Z-index alto para overlay.
   ════════════════════════════════════════════════════════════════ */
.camera-capture-container {
    position: fixed;
    inset: 0;
    z-index: 2000;
    background: var(--bg);
    color: var(--text);
    display: flex;
    flex-direction: column;
}
.camera-capture-container[hidden] { display: none !important; }

/* Sin permiso de cámara: ocultamos el footer (shutter/modos) y el picker de
   filtros AR. Son inútiles sin stream activo y se ven raros sobre el empty state. */
.camera-capture-container.no-permission .camera-capture-footer,
.camera-capture-container.no-permission .camera-capture-filters {
    display: none !important;
}

.camera-capture-stage {
    flex: 1;
    position: relative;
    overflow: hidden;
    background: var(--bg);
}
#camera-capture-video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    background: var(--bg);
}
/* Canvas del pipeline AR (Phase 3). Cubre el video cuando hay filtro activo.
   Cuando hidden, queda invisible y se ve el <video> debajo (sin filtro). */
.camera-capture-filter-canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    background: transparent;
}
.camera-capture-filter-canvas[hidden] { display: none !important; }

/* Picker de filtros AR (Phase 3): scroll horizontal entre el stage y el footer. */
.camera-capture-filters {
    display: flex;
    gap: 8px;
    overflow-x: auto;
    padding: 10px 12px;
    background: rgba(0, 0, 0, .35);
    flex-shrink: 0;
    scrollbar-width: none;
}
.camera-capture-filters::-webkit-scrollbar { display: none; }
.camera-capture-filter-chip {
    flex-shrink: 0;
    background: rgba(255, 255, 255, .08);
    border: 2px solid transparent;
    color: #fff;
    border-radius: 999px;
    padding: 6px 12px;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 6px;
}
.camera-capture-filter-chip.active {
    border-color: var(--accent);
    background: color-mix(in srgb, var(--accent) 20%, transparent);
}
.camera-capture-filter-chip i { width: 14px; height: 14px; }
/* Estado loading: spinner reemplaza el icono mientras se carga MediaPipe en
   el primer tap. Evita que el user piense que la app se congeló. */
.camera-capture-filter-chip.loading {
    border-color: var(--accent);
    background: color-mix(in srgb, var(--accent) 12%, transparent);
}
.camera-capture-filter-chip.loading i { display: none; }
.camera-capture-filter-chip.loading::before {
    content: '';
    width: 14px;
    height: 14px;
    border: 2px solid var(--accent);
    border-top-color: transparent;
    border-radius: 50%;
    animation: cam-chip-spin .7s linear infinite;
    flex-shrink: 0;
}
.camera-capture-filter-chip.disabled-while-loading {
    opacity: .5;
    pointer-events: none;
}
@keyframes cam-chip-spin {
    to { transform: rotate(360deg); }
}

/* Preview mirroring para cámara selfie (front).
   Sin esto, el user ve la realidad invertida — mover la mano a la derecha
   parece moverla a la izquierda en el preview (raro/incómodo).
   Mirror = ilusión de espejo: lo que ven en preview matchea como si fuera
   un espejo, comportamiento estándar tipo WhatsApp/Instagram/Snapchat.
   La class `selfie` la setea JS según _cam.facing. */
#camera-capture-video.selfie,
.camera-capture-filter-canvas.selfie {
    transform: scaleX(-1);
}

.camera-capture-empty {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    color: var(--text);
    background: var(--bg);
    text-align: center;
    padding: 20px;
    z-index: 1;
}
.camera-capture-empty #camera-capture-empty-msg {
    color: var(--text);
    opacity: .75;
    line-height: 1.45;
}
.camera-capture-empty #camera-capture-empty-msg b {
    color: var(--accent);
    font-weight: 700;
}
/* Botón secundario theme-aware del empty state. btn-outline-light se vuelve
   invisible en theme claro porque borde y texto son blancos sobre bg blanco. */
.camera-capture-empty-btn {
    border: 1px solid var(--border-clr);
    background: transparent;
    color: var(--text);
}
.camera-capture-empty-btn:hover,
.camera-capture-empty-btn:focus {
    background: color-mix(in srgb, var(--text) 10%, transparent);
    color: var(--text);
}

.camera-capture-timer {
    position: absolute;
    top: 16px;
    left: 50%;
    transform: translateX(-50%);
    background: #FF4D4D;
    color: #fff;
    padding: 4px 12px;
    border-radius: 999px;
    font-size: 13px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.camera-capture-header {
    position: absolute;
    top: 0; left: 0; right: 0;
    padding: 12px;
    padding-top: max(env(safe-area-inset-top, 0px), 12px);
    display: flex;
    align-items: center;
    justify-content: space-between;
    z-index: 2;
}
.camera-capture-iconbtn {
    background: rgba(0, 0, 0, .55);
    color: #fff;
    border: 0;
    border-radius: 50%;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    padding: 0;
}
.camera-capture-iconbtn i { width: 20px; height: 20px; }
.camera-capture-iconbtn.muted { background: rgba(255, 77, 77, .85); }

.camera-capture-footer {
    padding: 16px 20px;
    padding-bottom: max(env(safe-area-inset-bottom, 0px), 24px);
    background: rgba(0, 0, 0, .35);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 28px;
    flex-shrink: 0;
}
.camera-capture-modebtn {
    background: transparent;
    border: 0;
    color: rgba(255, 255, 255, .55);
    font-weight: 700;
    font-size: 14px;
    padding: 8px 10px;
    cursor: pointer;
    text-transform: uppercase;
    letter-spacing: .06em;
}
.camera-capture-modebtn.active {
    color: #fff;
    border-bottom: 2px solid var(--accent);
}
.camera-capture-shutter {
    width: 72px;
    height: 72px;
    border-radius: 50%;
    border: 4px solid #fff;
    background: transparent;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    padding: 0;
    flex-shrink: 0;
}
.camera-capture-shutter-inner {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: #fff;
    transition: background .15s, transform .15s, border-radius .15s;
}
/* Modo video grabando: el inner se vuelve cuadrado rojo (stop button) */
.camera-capture-shutter.recording .camera-capture-shutter-inner {
    background: #FF4D4D;
    width: 28px;
    height: 28px;
    border-radius: 6px;
}

/* ════════════════════════════════════════════════════════════════
   CREATE VIEW — pantalla inicial del flujo Crear (3 botones grandes).
   Aparece antes del form. Tras seleccionar/capturar media, se oculta y
   aparece el form completo. Ver buildCreateView en js/shorts.js.
   ════════════════════════════════════════════════════════════════ */
.create-source-picker {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px;
}
.create-source-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 24px 16px;
    border-radius: 16px;
    border: 2px solid var(--border-clr);
    background: var(--surface);
    color: var(--text);
    cursor: pointer;
    font-family: 'Ubuntu', sans-serif;
    font-weight: 700;
    transition: border-color .15s, background .15s;
}
.create-source-btn:hover:not(:disabled) {
    border-color: var(--accent);
}
.create-source-btn i {
    width: 36px;
    height: 36px;
    color: var(--accent);
}
.create-source-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}
.create-source-btn-sub {
    font-size: 12px;
    color: var(--text-muted);
    font-weight: 400;
}

/* FIX: Bootstrap `.d-flex` usa `display:flex !important` y sobrescribe el
   atributo HTML `hidden` (que normalmente vale display:none). Cuando esos
   wrappers están en estado oculto, forzar display:none para que el `hidden`
   tenga efecto. JS toggle de hidden controla la visibilidad correctamente. */
#create-form-wrap[hidden],
#create-submit-wrap[hidden],
#create-source-picker-wrap[hidden] {
    display: none !important;
}

@keyframes installToastIn {
    from { opacity: 0; transform: translate(-50%, -10px); }
    to   { opacity: 1; transform: translate(-50%, 0); }
}

.install-toast-close {
    position: absolute;
    left: 8px;
    top: 50%;
    transform: translateY(-50%);
    width: 22px;
    height: 22px;
    border: 0;
    background: rgba(0, 0, 0, .15);
    color: #1a1a1a;
    border-radius: 50%;
    font-size: 16px;
    line-height: 1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}
.install-toast-close:hover { background: rgba(0, 0, 0, .3); }

.install-toast-msg {
    flex: 1;
    min-width: 0;
}

.install-toast-btn {
    flex-shrink: 0;
    padding: 5px 12px;
    background: #1a1a1a;
    color: #fff;
    border: 0;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
}
.install-toast-btn:hover { background: #000; }

/* En pantallas anchas evitar que sea super largo */
@media (min-width: 600px) {
    .install-toast { max-width: 460px; }
}

/* ─── COVERAGE PICKER (mapa Leaflet) ─── */
#coverage-editor-modal { background: var(--drawer-bg); color: var(--text); z-index: 1080; }
#coverage-editor-modal .filter-editor-header { background: var(--drawer-bg); border-bottom-color: var(--border-clr); }
.coverage-map-wrap { background: var(--card-bg); }
#coverage-map { width: 100%; height: 100%; background: var(--card-bg); }
.coverage-crosshair {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    pointer-events: none;
    z-index: 500;     /* encima de los tiles, debajo de los popups de Leaflet */
}
.coverage-crosshair .cx-vert,
.coverage-crosshair .cx-horiz {
    position: absolute;
    background: var(--accent);
    box-shadow: 0 0 4px rgba(0,0,0,.6);
}
.coverage-crosshair .cx-vert  { width: 2px; height: 28px; left: -1px; top: -14px; }
.coverage-crosshair .cx-horiz { height: 2px; width: 28px; top: -1px; left: -14px; }
.coverage-crosshair .cx-dot {
    position: absolute;
    width: 10px; height: 10px;
    left: -5px; top: -5px;
    background: var(--accent);
    border: 2px solid #000;
    border-radius: 50%;
}
.coverage-search-item {
    padding: 8px 12px;
    border-bottom: 1px solid var(--border-clr);
    cursor: pointer;
    font-size: 13px;
    color: var(--text);
}
.coverage-search-item:hover { background: var(--input-bg); }
.coverage-search-item small { display: block; color: var(--text-muted); font-size: 11px; }

/* Badge "auto" en modal de categorías que me gustan */
.liked-cat-badge {
    display: inline-block;
    margin-left: 6px;
    padding: 2px 8px;
    background: rgba(159, 71, 235, .2);
    color: var(--purple);
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    border-radius: 99px;
    vertical-align: middle;
}

.create-media-preview img,
.create-media-preview video {
    width: 100%;
    max-height: 260px;
    object-fit: contain;
    display: block;
}

/* ── Dual-range slider (edad objetivo) ──────────────────────────────
   Truco: 2 inputs range superpuestos sobre el mismo track.
   - El input range completo tiene pointer-events: none → no captura clicks
     en el track (que está reservado para el visual).
   - El thumb (::-webkit-slider-thumb / ::-moz-range-thumb) reactiva
     pointer-events: auto → solo el thumb es draggeable.
   - Esto deja ambos thumbs (min + max) accesibles sobre el mismo eje.
   ─────────────────────────────────────────────────────────────────── */
.dual-range {
    position: relative;
    height: 28px;
    width: 100%;
}
.dual-range-track,
.dual-range-fill {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    height: 4px;
    border-radius: 99px;
    pointer-events: none;
}
.dual-range-track {
    left: 0; right: 0;
    background: rgba(255, 255, 255, .12);
}
.dual-range-fill {
    background: var(--accent);
}
.dual-range-input {
    position: absolute;
    top: 0; left: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    background: transparent;
    -webkit-appearance: none;
    appearance: none;
    pointer-events: none;   /* solo thumbs reciben — ver abajo */
}
/* Track del input nativo: invisible (usamos el div .dual-range-track) */
.dual-range-input::-webkit-slider-runnable-track {
    background: transparent;
    border: 0;
    height: 4px;
}
.dual-range-input::-moz-range-track {
    background: transparent;
    border: 0;
    height: 4px;
}
/* Thumb visible y arrastrable */
.dual-range-input::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--accent);
    border: 2px solid var(--bg);
    box-shadow: 0 1px 4px rgba(0, 0, 0, .35);
    cursor: grab;
    pointer-events: auto;   /* thumb sí reactiva */
    margin-top: -8px;       /* centra verticalmente sobre el track de 4px */
}
.dual-range-input::-webkit-slider-thumb:active { cursor: grabbing; }
.dual-range-input::-moz-range-thumb {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--accent);
    border: 2px solid var(--bg);
    box-shadow: 0 1px 4px rgba(0, 0, 0, .35);
    cursor: grab;
    pointer-events: auto;
}
.dual-range-input:focus { outline: none; }
.dual-range-input:focus::-webkit-slider-thumb {
    box-shadow: 0 0 0 4px rgba(232, 255, 71, .25), 0 1px 4px rgba(0, 0, 0, .35);
}
.dual-range-input:focus::-moz-range-thumb {
    box-shadow: 0 0 0 4px rgba(232, 255, 71, .25), 0 1px 4px rgba(0, 0, 0, .35);
}
/* Light theme */
[data-theme="light"] .dual-range-track {
    background: rgba(0, 0, 0, .12);
}

.create-input {
    width: 100%;
    background: var(--input-bg);
    color: var(--text);
    border: 1px solid var(--border-clr);
    border-radius: 12px;
    font-family: 'Ubuntu', sans-serif;
    font-size: 14px;
    padding: 10px 14px;
    outline: none;
    resize: none;
    transition: border-color .15s;
}

/* ─────────────────────────────────────────────────────────────────────
   THEME-AWARE NATIVE <select> + <option>
   ─────────────────────────────────────────────────────────────────────
   PROBLEMA HISTÓRICO:
   <option> dentro de <select> es renderizado por el SISTEMA OPERATIVO,
   no por nuestro CSS. En tema oscuro de la app pero browser/OS en claro,
   las opciones aparecen con fondo blanco + texto blanco (heredado del
   site) = invisible. Bug recurrente en CADA select que se agrega.

   SOLUCIÓN GLOBAL (aplica a TODOS los <select> de la app, presentes y futuros):
   1. color-scheme: dark/light en :root y [data-theme="light"] arriba →
      browser renderiza controles nativos en el esquema correcto.
   2. Estilos explícitos abajo cubren browsers viejos / Firefox que ignora
      color-scheme en options.

   CUÁNDO NO USAR <select>:
   Si necesitás opciones con iconos, descripciones, fotos, búsqueda, scroll
   limitado o estilo custom → USAR bottom-sheet picker (ver openPicker en
   js/shorts.js). El <select> nativo no se puede estilar profundamente y
   en móvil abre un picker del SO que rompe la UX consistente.
   ───────────────────────────────────────────────────────────────────── */
select {
    background: var(--input-bg);
    color: var(--text);
    border: 1px solid var(--border-clr);
    border-radius: 12px;
    font-family: 'Ubuntu', sans-serif;
    font-size: 14px;
    padding: 8px 12px;
    outline: none;
    appearance: auto;
}
select:focus { border-color: var(--accent); }
select option {
    background: var(--drawer-bg);
    color: var(--text);
}
select option:checked,
select option:hover {
    background: color-mix(in srgb, var(--accent) 25%, var(--drawer-bg));
    color: var(--text);
}
[data-theme="light"] select option {
    background: #fff;
    color: #111;
}
[data-theme="light"] select option:checked,
[data-theme="light"] select option:hover {
    background: color-mix(in srgb, var(--accent) 25%, #fff);
    color: #111;
}

.create-input::placeholder {
    color: var(--text-muted);
}

.create-input:focus {
    border-color: color-mix(in srgb, var(--text) 30%, transparent);
}

/* ── MUSIC PICKER ── */
.create-music-btn {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    background: var(--input-bg);
    color: var(--text);
    border: 1px solid var(--border-clr);
    border-radius: 12px;
    padding: 12px 14px;
    font-family: 'Ubuntu', sans-serif;
    font-size: 14px;
    text-align: left;
    cursor: pointer;
    transition: border-color .15s;
}

.create-music-btn:hover {
    border-color: color-mix(in srgb, var(--text) 30%, transparent);
}

.create-music-btn i:first-child {
    color: var(--accent);
    font-size: 18px;
}

.picker-option {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 18px;
    cursor: pointer;
    border-bottom: 1px solid var(--border-clr);
    color: var(--text);
    font-size: 14px;
    transition: background .15s;
}

.picker-option:hover {
    background: var(--surface);
}

.picker-option.selected {
    color: var(--accent);
    font-weight: 600;
}

.picker-option .picker-check {
    width: 18px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--accent);
}

.create-picker-trigger {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    background: var(--input-bg);
    border: 1px solid var(--border-clr);
    color: var(--text);
    border-radius: 10px;
    padding: 10px 12px;
    font-size: 14px;
    text-align: left;
}

.create-picker-trigger:hover {
    border-color: var(--text-dim);
}

.music-tab {
    background: var(--input-bg);
    color: var(--text-dim);
    border: 1px solid transparent;
    font-size: 13px;
    padding: 8px 10px;
}

.music-tab.active {
    background: var(--accent);
    color: #000;
    border-color: var(--accent);
}

.music-pane {
    min-height: 200px;
}

.lib-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: 10px;
    transition: background .15s;
}

.lib-row:hover {
    background: var(--surface);
}

.lib-row.playing {
    background: var(--surface);
}

.lib-row .lib-play {
    flex-shrink: 0;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--accent);
    color: #000;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    border: 0;
}

/* ── Lucide icon (svg replaces <i data-lucide>) ── */
.action-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    padding: 10px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.08);
}

.action-icon svg {
    width: 1em;
    height: 1em;
}

/* ── HEADER de Inicio (app-logo + acciones) ──
   Layout único para los 3 elementos. Solo visible en pestaña Inicio.
   Comportamiento según modo de feed:
     - TikTok: transparente, overlay sobre slide (estilo TikTok real).
     - Twitter / Instagram: barra opaca, feed con padding-top para no quedar tapado.
*/
#feed-header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 50;
    display: none;
    align-items: center;
    justify-content: space-between;
    /* Respeta status bar / notch (safe-area-inset-top) sumando padding extra arriba. */
    padding: calc(12px + env(safe-area-inset-top, 0px)) 12px 12px;
    pointer-events: none;
}
#feed-header > * { pointer-events: auto; }

body:has(.nb-btn[data-view="feed"].active) #feed-header {
    display: flex !important;
}

#app-logo {
    display: flex !important;
    align-items: center;
    visibility: visible !important;
    opacity: 1 !important;
    flex-shrink: 0;
    font-weight: 900;
    font-size: 22px;
    letter-spacing: -.02em;
    user-select: none;
    line-height: 1;
    min-height: 22px;
    /* Texto: fill con gradiente del accent del tema → tono suave del mismo accent
       → accent. Animado horizontalmente para movimiento continuo. Stroke en 0
       (apagado pero mantengo el parámetro por si se quiere reactivar). */
    color: transparent;
    -webkit-text-stroke: 0px var(--accent);
    /* Gradient: accent → mismo color con menor opacidad (mantiene hue, baja intensidad)
       → accent. Antes era 30% accent y se perdía el color; ahora 65% mantiene visible. */
    background: linear-gradient(
        90deg,
        var(--accent) 0%,
        color-mix(in srgb, var(--accent) 65%, transparent) 50%,
        var(--accent) 100%
    );
    background-size: 200% 100%;
    -webkit-background-clip: text;
    background-clip: text;
    animation: appLogoGradient 3.5s linear infinite;
    /* Sombra: legibilidad sobre media en modo inmersivo. */
    filter: drop-shadow(0 2px 8px rgba(0, 0, 0, .7));
}

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

.feed-header-actions {
    display: flex;
    gap: 8px;
}

#feed-filter-btn {
    background: rgba(0, 0, 0, .55);
    color: #fff;
    border: 0;
    border-radius: 50%;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    padding: 0;
}
#feed-filter-btn i {
    width: 18px;
    height: 18px;
}

/* Botón de mensajes (chat) en el header de Inicio — mismo look que el de filtro. */
#chat-nav-btn {
    position: relative;
    background: rgba(0, 0, 0, .55);
    color: #fff;
    border: 0;
    border-radius: 50%;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    padding: 0;
}
#chat-nav-btn i { width: 18px; height: 18px; }
body:has(#feed.feed-mode-tiktok) #chat-nav-btn,
body:has(#feed.feed-mode-twitter) #chat-nav-btn,
body:has(#feed.feed-mode-instagram) #chat-nav-btn {
    background: var(--surface);
    color: var(--text);
}
/* Badge de no leídos sobre el ícono de mensajes. */
.chat-header-badge {
    position: absolute;
    top: -3px;
    right: -3px;
    min-width: 20px;
    height: 20px;
    padding: 0 5px;
    border-radius: 10px;
    background: var(--accent);
    color: #000;
    font-size: 11px;
    font-weight: 700;
    line-height: 20px;
    text-align: center;
    border: 2px solid var(--bg);
}

/* ─── CHAT (vista de mensajería) ──────────────────────────────────── */
#view-chat { background: var(--bg); }
.chat-view-header {
    display: flex; align-items: center; gap: 10px;
    padding: 12px 14px; flex-shrink: 0;
    border-bottom: 1px solid var(--border-clr);
}
.chat-view-header .chat-back { background: none; border: 0; color: var(--text); cursor: pointer; padding: 4px; display: flex; }
.chat-view-header .chat-title { font-weight: 700; font-size: 16px; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.chat-thread-list { flex: 1; overflow-y: auto; }
.chat-thread-row {
    display: flex; align-items: center; gap: 12px;
    padding: 12px 14px; cursor: pointer;
    border-bottom: 1px solid var(--border-clr);
}
.chat-thread-row:hover { background: rgba(255, 255, 255, .03); }
.chat-thread-avatar {
    width: 48px; height: 48px; border-radius: 50%; flex-shrink: 0;
    background: var(--surface); display: flex; align-items: center; justify-content: center;
    font-weight: 700; color: var(--text-muted); overflow: hidden;
}
.chat-thread-avatar img { width: 100%; height: 100%; object-fit: cover; }
.chat-thread-main { flex: 1; min-width: 0; }
.chat-thread-name { font-weight: 600; font-size: 15px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-thread-last { font-size: 13px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-thread-last.unread { color: var(--text); font-weight: 600; }
.chat-thread-meta { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; flex-shrink: 0; }
.chat-thread-time { font-size: 11px; color: var(--text-muted); }
.chat-thread-unread {
    min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
    background: var(--accent); color: #000; font-size: 11px; font-weight: 700;
    line-height: 18px; text-align: center;
}

.chat-messages { flex: 1; overflow-y: auto; padding: 14px; display: flex; flex-direction: column; gap: 6px; }
.chat-bubble {
    max-width: 78%; padding: 8px 12px; border-radius: 16px;
    font-size: 14px; line-height: 1.35; word-wrap: break-word; white-space: pre-wrap;
}
.chat-bubble.mine   { align-self: flex-end;   background: var(--accent);  color: #000;        border-bottom-right-radius: 4px; }
.chat-bubble.theirs { align-self: flex-start; background: var(--surface); color: var(--text); border-bottom-left-radius: 4px; }
.chat-bubble-sender { display: block; font-size: 11px; font-weight: 700; color: var(--accent); margin-bottom: 2px; }
.chat-bubble-time { font-size: 10px; opacity: .55; margin-top: 2px; display: block; text-align: right; }
.chat-input-row {
    display: flex; align-items: center; gap: 8px;
    padding: 10px 12px; flex-shrink: 0; border-top: 1px solid var(--border-clr);
}
.chat-input-row input {
    flex: 1; background: var(--surface); border: 1px solid var(--border-clr);
    border-radius: 20px; padding: 9px 14px; color: var(--text); font-size: 14px; outline: none;
}
.chat-send-btn {
    width: 38px; height: 38px; border-radius: 50%; border: 0; flex-shrink: 0;
    background: var(--accent); color: #000; display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.chat-empty {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    flex: 1; gap: 8px; color: var(--text-muted); padding: 40px; text-align: center;
}

/* Botón "Traducir" bajo cada burbuja. */
.chat-translate-btn {
    display: block; margin-top: 4px; padding: 0;
    background: none; border: 0; cursor: pointer;
    font-size: 11px; font-weight: 600; opacity: .85;
}
.chat-bubble.mine   .chat-translate-btn { color: rgba(0, 0, 0, .6); }
.chat-bubble.theirs .chat-translate-btn { color: var(--accent); }

/* ── Reply en chat ── */
.chat-bubble { position: relative; }
/* Botón ⋯ de acciones. Va en el GUTTER (fuera de la burbuja, del lado opuesto a la
   alineación → theirs: derecha, mine: izquierda), centrado vertical. Así NO tapa el
   texto/imagen del mensaje. Chip de fondo + siempre visible (en móvil no hay :hover,
   y sobre una imagen un botón transparente quedaba invisible). El max-width 78% de la
   burbuja deja gutter suficiente (>28px en cualquier ancho) → no recorta ni scrollea. */
.chat-msg-action-btn {
    position: absolute; top: 50%; transform: translateY(-50%);
    width: 24px; height: 24px; padding: 0; border: 1px solid var(--border-clr); border-radius: 50%;
    background: var(--card-bg); cursor: pointer; opacity: .85;
    display: flex; align-items: center; justify-content: center;
    box-shadow: 0 1px 4px rgba(0, 0, 0, .18);
}
.chat-msg-action-btn i { width: 14px; height: 14px; }
.chat-msg-action-btn:hover { opacity: 1; }
.chat-bubble.theirs .chat-msg-action-btn { right: -28px; color: var(--text); }
.chat-bubble.mine   .chat-msg-action-btn { left: -28px;  color: var(--text); }
/* Cita del mensaje citado dentro de la burbuja (tap → salta al original). */
.chat-reply-quote {
    padding: 3px 8px; margin-bottom: 4px; border-radius: 6px;
    border-left: 3px solid var(--accent); cursor: pointer; max-width: 100%;
}
.chat-bubble.theirs .chat-reply-quote { background: rgba(255, 255, 255, .06); }
.chat-bubble.mine   .chat-reply-quote { background: rgba(0, 0, 0, .10); border-left-color: rgba(0, 0, 0, .45); }
.chat-reply-quote-user { font-size: 11px; font-weight: 700; }
.chat-reply-quote-snippet { font-size: 12px; opacity: .8; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Flash al saltar al mensaje original. */
.chat-bubble-highlight { animation: chatHl 1.4s ease; }
@keyframes chatHl {
    0%   { box-shadow: 0 0 0 0 var(--accent); }
    20%  { box-shadow: 0 0 0 3px var(--accent); }
    100% { box-shadow: 0 0 0 0 transparent; }
}
/* Pill "Respondiendo a …" encima del composer. */
.chat-reply-pill {
    display: flex; align-items: center; gap: 8px;
    margin: 0 12px 6px; padding: 6px 8px;
    background: var(--surface); border-radius: 8px; flex-shrink: 0;
}
.chat-reply-pill-bar { width: 3px; align-self: stretch; background: var(--accent); border-radius: 2px; flex-shrink: 0; }
.chat-reply-pill-text { flex: 1; min-width: 0; }
.chat-reply-pill-user { font-size: 12px; font-weight: 700; color: var(--accent); }
.chat-reply-pill-snippet { font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-reply-pill-close { background: none; border: 0; color: var(--text-muted); cursor: pointer; padding: 4px; flex-shrink: 0; }
.chat-reply-pill-close i { width: 16px; height: 16px; }
/* Opciones del bottom-sheet de acciones del mensaje. */
.chat-action-opt {
    display: flex; align-items: center; gap: 12px; width: 100%;
    padding: 14px 16px; border: 0; background: none; cursor: pointer;
    color: var(--text); font-size: 15px; text-align: left; border-radius: 10px;
}
.chat-action-opt:hover { background: rgba(255, 255, 255, .05); }
.chat-action-opt i { width: 20px; height: 20px; color: var(--text-muted); }
/* Indicador "Cargando…" al traer mensajes anteriores (scroll-up). */
.chat-older-loader {
    align-self: center; padding: 6px 12px; margin: 4px auto;
    font-size: 12px; color: var(--text-muted);
}

/* Bottom-sheet de traducción. */
.chat-tr-backdrop {
    position: fixed; inset: 0; background: rgba(0, 0, 0, .5);
    z-index: 100050; opacity: 0; pointer-events: none; transition: opacity .2s ease;
}
.chat-tr-backdrop.open { opacity: 1; pointer-events: auto; }
.chat-tr-sheet {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 100051;
    background: var(--bg); border-top-left-radius: 16px; border-top-right-radius: 16px;
    border-top: 1px solid var(--border-clr);
    padding: 10px 16px calc(16px + env(safe-area-inset-bottom, 0px)) 16px;
    transform: translateY(100%); transition: transform .25s ease;
    max-height: 70vh; overflow-y: auto;
}
.chat-tr-sheet.open { transform: translateY(0); }
.chat-tr-handle { width: 40px; height: 4px; border-radius: 2px; background: var(--text-dim, #666); margin: 0 auto 12px; }
.chat-tr-title { font-weight: 700; font-size: 15px; margin-bottom: 10px; }
.chat-tr-original {
    font-size: 13px; color: var(--text-muted); background: var(--surface);
    border-radius: 10px; padding: 10px; margin-bottom: 10px; white-space: pre-wrap;
}
.chat-tr-result {
    font-size: 15px; color: var(--text); background: var(--surface);
    border-radius: 10px; padding: 10px; white-space: pre-wrap; min-height: 40px;
}

/* Header opaco en TODOS los modos (TikTok / Twitter / Instagram). Antes en TikTok
   era transparente y quedaba flotando sobre el slide; ahora el slide arranca debajo
   del header (ver #app shift abajo). */
body:has(#feed.feed-mode-tiktok) #feed-header,
body:has(#feed.feed-mode-twitter) #feed-header,
body:has(#feed.feed-mode-instagram) #feed-header {
    background: var(--bg);
    border-bottom: 1px solid var(--border-clr);
    box-shadow: 0 1px 0 rgba(255,255,255,.04);
}
/* Header opaco → sin sombra sobre logo/botón (no compite con media de fondo). */
body:has(#feed.feed-mode-tiktok) #app-logo,
body:has(#feed.feed-mode-twitter) #app-logo,
body:has(#feed.feed-mode-instagram) #app-logo {
    filter: none;
}
body:has(#feed.feed-mode-tiktok) #feed-filter-btn,
body:has(#feed.feed-mode-twitter) #feed-filter-btn,
body:has(#feed.feed-mode-instagram) #feed-filter-btn {
    background: var(--surface);
    color: var(--text);
}
.feed-mode-twitter,
.feed-mode-instagram {
    /* Alto del header (~64px) + safe-area-inset-top (status bar / notch). Evita
       que el primer post quede tapado por el header fixed en celulares con notch
       o status bar Android. */
    padding-top: calc(64px + env(safe-area-inset-top, 0px));
}
/* TikTok/immersive: el slide es altura 100% de #app y usa scroll-snap. Para que
   el header NO quede encima del slide, achicamos #app desde arriba por el alto
   del header. Solo cuando feed-mode-tiktok está activo Y la vista feed visible. */
body:has(.nb-btn[data-view="feed"].active):has(#feed.feed-mode-tiktok) #app {
    top: calc(64px + env(safe-area-inset-top, 0px));
}

/* ── Button system (overrides Bootstrap variants) ── */
.btn-warning,
.btn-warning:visited {
    background-color: var(--accent) !important;
    border-color: var(--accent-border) !important;
    color: #000 !important;
}

.btn-warning:hover,
.btn-warning:focus,
.btn-warning:active {
    background-color: var(--accent-hover) !important;
    border-color: var(--accent-border) !important;
    color: #000 !important;
}

.btn-secondary,
.btn-secondary:visited {
    background-color: transparent !important;
    border-color: var(--border-clr) !important;
    color: var(--text) !important;
}

.btn-secondary:hover,
.btn-secondary:focus,
.btn-secondary:active {
    background-color: var(--surface) !important;
    border-color: var(--text-dim) !important;
    color: var(--text) !important;
}

.btn-dark,
.btn-dark:visited {
    background-color: #1a1a1a !important;
    border-color: var(--border-clr) !important;
    color: var(--text) !important;
}

.btn-dark:hover,
.btn-dark:focus,
.btn-dark:active {
    background-color: #262626 !important;
    border-color: var(--text-dim) !important;
}

.btn-link {
    border: 0 !important;
    box-shadow: none !important;
}

/* ── Form controls (Bootstrap override → shorts theme) ──
   Antes: .form-control quedaba blanco con texto oscuro en tema dark
   (Bootstrap default), feo en modales login/register. Ahora hereda
   --input-bg + --text + --border-clr para matchear el resto de UI. */
.form-control,
.form-select,
textarea.form-control {
    background-color: var(--input-bg) !important;
    color: var(--text) !important;
    border: 1px solid var(--border-clr) !important;
}

.form-control:focus,
.form-select:focus,
textarea.form-control:focus {
    background-color: var(--input-bg) !important;
    color: var(--text) !important;
    border-color: var(--accent) !important;
    box-shadow: 0 0 0 .15rem rgba(0, 250, 158, .15) !important;
}

.form-control::placeholder,
textarea.form-control::placeholder {
    color: var(--text-muted) !important;
    opacity: 1;
}

.form-control:disabled,
.form-control[readonly] {
    background-color: var(--surface) !important;
    color: var(--text-dim) !important;
    opacity: .8;
}

.form-label,
.form-text {
    color: var(--text-dim) !important;
}

/* ── btn-primary / btn-success → acento shorts (los modales login (success)
   y register (primary) usaban azul / verde Bootstrap default). ── */
.btn-primary,
.btn-primary:visited,
.btn-success,
.btn-success:visited {
    background-color: var(--accent) !important;
    border-color: var(--accent-border) !important;
    color: #000 !important;
}

.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active,
.btn-success:hover,
.btn-success:focus,
.btn-success:active {
    background-color: var(--accent-hover) !important;
    border-color: var(--accent-border) !important;
    color: #000 !important;
}

/* ── Modal chrome (Bootstrap default = white). Heredar tema shorts. ── */
.modal-content {
    background-color: var(--drawer-bg) !important;
    color: var(--text) !important;
    border: 1px solid var(--border-clr) !important;
}

.modal-header {
    border-bottom: 1px solid var(--border-clr) !important;
}

.modal-footer {
    border-top: 1px solid var(--border-clr) !important;
}

.modal-header .btn-close {
    filter: invert(1) grayscale(100%);
    opacity: .7;
}

[data-theme="light"] .modal-header .btn-close {
    filter: none;
}

/* ─── DESKTOP LAYOUT — solo Twitter (cronologica) e Instagram (mural).
   TikTok (inmersivo) queda full-bleed como ahora. Cards centradas con
   ancho tipo "mobile-en-desktop" (520px) para que la imagen cuadrada
   del mural no rebase la altura del viewport en monitores grandes.
   Breakpoint 768px = iPad portrait y arriba. ─── */
@media (min-width: 768px) {
    #feed.feed-mode-twitter,
    #feed.feed-mode-instagram,
    #post-detail-feed.feed-mode-twitter,
    #post-detail-feed.feed-mode-instagram {
        padding-inline: 1rem;
    }

    .feed-mode-twitter .slide,
    .feed-mode-instagram .slide {
        max-width: 520px;
        margin-inline: auto;
    }

    /* Explorar: misma columna "mobile-en-desktop" (520px centrado) que mural/
       cronología. Solo la grilla — la barra de búsqueda queda full-width. El
       layout de columnas (1/2/3) elegido por el user se respeta dentro de 520px. */
    #explore-grid {
        max-width: 520px;
        margin-inline: auto;
    }

    /* Scrollbar visible en desktop. En mobile el navegador no muestra barra
       y el touch-scroll basta; en desktop sin barra el usuario no tiene
       indicador visual de posición ni puede arrastrar. */
    #feed.feed-mode-twitter,
    #feed.feed-mode-instagram,
    #post-detail-feed.feed-mode-twitter,
    #post-detail-feed.feed-mode-instagram,
    #view-explore #explore-scroll,
    #view-profile {
        scrollbar-width: thin;
        scrollbar-color: var(--text-dim) transparent;
    }
    #feed.feed-mode-twitter::-webkit-scrollbar,
    #feed.feed-mode-instagram::-webkit-scrollbar,
    #post-detail-feed.feed-mode-twitter::-webkit-scrollbar,
    #post-detail-feed.feed-mode-instagram::-webkit-scrollbar,
    #view-explore #explore-scroll::-webkit-scrollbar,
    #view-profile::-webkit-scrollbar {
        display: block;
        width: 8px;
    }
    #feed.feed-mode-twitter::-webkit-scrollbar-thumb,
    #feed.feed-mode-instagram::-webkit-scrollbar-thumb,
    #post-detail-feed.feed-mode-twitter::-webkit-scrollbar-thumb,
    #post-detail-feed.feed-mode-instagram::-webkit-scrollbar-thumb,
    #view-explore #explore-scroll::-webkit-scrollbar-thumb,
    #view-profile::-webkit-scrollbar-thumb {
        background: var(--text-dim);
        border-radius: 4px;
    }
}

/* ════════════════════════════════════════════════════════════════
   DASHBOARD — sub-vista del perfil propio (Mi dashboard).
   Render dentro de picker-modal. Métricas event-sourcing.
   ════════════════════════════════════════════════════════════════ */
.dash-wrap {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 14px;
    padding-bottom: max(env(safe-area-inset-bottom, 0px), 24px);
}
.dash-card {
    background: var(--card-bg);
    border: 1px solid var(--border-clr);
    border-radius: 14px;
    padding: 14px;
}
.dash-balance-label {
    font-size: 12px;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: .06em;
    margin-bottom: 4px;
}
.dash-balance-value {
    font-size: 26px;
    font-weight: 800;
    color: var(--accent);
    line-height: 1.1;
    margin-bottom: 14px;
}
.dash-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}
.dash-grid > div {
    background: color-mix(in srgb, var(--text) 4%, transparent);
    border-radius: 10px;
    padding: 10px 12px;
}
.dash-mini-label {
    font-size: 11px;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: .04em;
    margin-bottom: 2px;
}
.dash-mini-value {
    font-size: 14px;
    font-weight: 700;
    color: var(--text);
}

/* ─── Formato tipográfico de montos CR ───
   Parte entera grande + parte decimal más chica/dim/superscript para que NUNCA
   se confunda con separador de miles. Universal — independiente del locale.
   Uso: <span class="cr-amount"><span class="cr-int">200</span><span
        class="cr-frac">.013</span><span class="cr-unit">CR</span></span>
*/
.cr-amount { display: inline-flex; align-items: baseline; gap: 3px; line-height: 1; }
.cr-int    { font-weight: 700; color: inherit; }
.cr-frac   { opacity: .55; font-weight: 500; }
.cr-unit   { font-size: .68em; opacity: .6; margin-left: 4px; letter-spacing: .04em; font-weight: 500; }

/* Botón info pequeño al lado de labels en el dashboard.
   Reusa estilo del share-info-open: btn-link mini con icono lucide info. */
.dash-info-btn {
    background: transparent;
    border: 0;
    padding: 0;
    margin-left: 4px;
    line-height: 1;
    color: var(--text-muted);
    cursor: pointer;
    vertical-align: middle;
    opacity: .75;
    transition: opacity .15s, color .15s;
}
.dash-info-btn:hover { opacity: 1; color: var(--accent); }
.dash-info-btn i { width: 12px; height: 12px; vertical-align: middle; }

/* ─── Barra de progreso "Fondos de la bolsa viral" en openShareOfferModal ───
   Track gris (100% = signed_sum) + fill accent (porción ya distribuida).
   Visual: cuanto más llena, menos queda en la bolsa. Empty = nada se distribuyó. */
.share-pool-bar {
    position: relative;
    width: 100%;
    height: 8px;
    /* var(--surface) hace swap entre temas (blanco-soft en dark, negro-soft en light).
       Antes era rgba(255,255,255,.08) hardcoded → invisible en modo claro. */
    background: var(--surface);
    border-radius: 4px;
    overflow: hidden;
    margin-top: 8px;
}
.share-pool-bar-fill {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    background: var(--accent);
    border-radius: 4px;
    transition: width .3s ease;
}
.share-pool-bar-legend {
    display: flex;
    justify-content: space-between;
    font-size: 11px;
    color: var(--text-muted);
    margin-top: 6px;
}
.dash-section-title {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: .05em;
    margin-bottom: 10px;
    font-weight: 600;
}
.dash-section-title i { width: 16px; height: 16px; }
.dash-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 8px 0;
    border-bottom: 1px solid var(--border-clr);
    font-size: 13px;
}
.dash-row:last-child { border-bottom: 0; }
.dash-row-label { color: var(--text); }
.dash-row-value { color: var(--accent); font-weight: 700; }
.dash-ref-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 0;
    border-bottom: 1px solid var(--border-clr);
    cursor: pointer;
    transition: background .12s;
}
.dash-ref-row:last-child { border-bottom: 0; }
.dash-ref-row:hover { background: color-mix(in srgb, var(--text) 4%, transparent); }
.dash-ref-avatar {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--card-bg);
    overflow: hidden;
    flex-shrink: 0;
    border: 1px solid var(--border-clr);
}
.dash-ref-avatar img { width: 100%; height: 100%; object-fit: cover; }
.dash-ref-name {
    flex: 1;
    font-size: 14px;
    font-weight: 600;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.dash-ref-earned {
    color: var(--accent);
    font-weight: 700;
    font-size: 13px;
    white-space: nowrap;
}
.dash-event-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 0;
    border-bottom: 1px solid var(--border-clr);
    font-size: 13px;
}
.dash-event-row:last-child { border-bottom: 0; }
.dash-event-text {
    flex: 1;
    min-width: 0;
}
.dash-event-amount {
    font-weight: 700;
    white-space: nowrap;
}

/* ── Iconos lucide NO interactivos dentro de controles ──────────────────
   lucide.createIcons() REEMPLAZA el <i data-lucide> por un <svg> nuevo al
   renderizar. En la primera interacción (desktop), si el swap de nodo cae
   entre pointerdown y click, el browser cancela el click: el target original
   (el icono) desapareció del DOM. Por eso clickear el ICONO fallaba al primer
   intento, pero el número/texto contiguo (no reemplazado) sí funcionaba.
   pointer-events:none → el click SIEMPRE cae en el botón/control padre, que
   lucide nunca toca. Inmune al swap de nodo y al placeholder 0×0.
   Scopeado a lucide a propósito: `svg` global rompería los mapas Leaflet de
   cobertura (que sí necesitan recibir clicks). */
/* ── Buscador del view-chat (chats + grupos + texto de mensajes) ─────── */
.chat-search-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--border-clr);
}
.chat-search-icon { width: 18px; height: 18px; color: var(--text-muted); flex-shrink: 0; }
.chat-search-row input {
    flex: 1;
    min-width: 0;
    border: 0;
    background: transparent;
    color: var(--text);
    font-size: 15px;
    outline: none;
}
.chat-search-clear {
    flex-shrink: 0;
    border: 0;
    background: transparent;
    color: var(--text-muted);
    font-size: 16px;
    line-height: 1;
    cursor: pointer;
    padding: 2px 4px;
}
.chat-search-section {
    padding: 12px 14px 6px;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--text-muted);
}
/* Botón "Unirse" en filas de grupo público dentro del buscador. */
.egroup-join {
    flex-shrink: 0;
    align-self: center;
    border: 0;
    border-radius: 99px;
    padding: 7px 16px;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    background: var(--accent);
    color: #fff;
}

[data-lucide],
.lucide {
    pointer-events: none;
}