/* ════════════════════════════════════════════════════════════════════
   PLANTILLA CLASSIC · digitalVCard-Pro
   ════════════════════════════════════════════════════════════════════
   Estilos de la tarjeta pública. Todo bajo el wrapper `.dvc-classic`.

   ESCALADO PROPORCIONAL
   ─────────────────────────────────────────────────────────────────
   El wrapper tiene una variable CSS `--u` (heredable por todos los
   descendientes) que representa el ancho efectivo del contenedor.
   Cada tamaño interno se expresa como `calc(factor * var(--u))`,
   donde `factor` es la fracción del ancho que ocupa (0–1).

   Ej. `.dvc-photo` con `width: calc(0.41 * var(--u))` mide:
     · 252×0.41 = 103px en el preview pequeño del editor
     · 324×0.41 = 133px en el modal del editor
     · 360×0.41 = 148px en el móvil real del visitante

   Una sola fuente de verdad, sin container queries (compatible con
   cualquier navegador), sin overrides duplicados.
   ════════════════════════════════════════════════════════════════════ */

/* ── Reset interno ──────────────────────────────────────────── */
.dvc-classic, .dvc-classic *,
.dvc-classic *::before, .dvc-classic *::after { box-sizing: border-box; }

/* ── Wrapper raíz ──────────────────────────────────────────── */
.dvc-classic {
    /* Unidad base = ancho efectivo. El editor sobrescribe esto
       según el contenedor (preview pequeño, modal, móvil real). */
    --u: 360px;
    /* Velocidad del fondo animado (segundos por ciclo, 2-14) */
    --bg-speed: 8s;
    /* Variable indirecta: día por defecto, noche cuando data-theme="night" */
    --bg-active: var(--dvc-bg-day, linear-gradient(135deg, #ffd320, #ff9e07, #ffa000, #ffb300));

    /* `position: relative` es obligatorio: el `::before` con position:absolute
       que pinta el degradado en motions rotate/wave/zoom debe anclarse a
       este wrapper, no al primer ancestor positioned. */
    position: relative;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    color: #fff;
    font-family: 'Poppins', -apple-system, BlinkMacSystemFont, sans-serif;
    -webkit-font-smoothing: antialiased;
    background: var(--bg-active);
    background-size: 200% 200%;
    background-repeat: no-repeat;
    transition: background 400ms ease;
    /* Padding base + safe-area de iOS (sesión 8). Con viewport-fit=cover
       el fondo del body cubre el notch (efecto edge-to-edge deseado),
       pero el contenido necesita apartarse del status bar y del home
       indicator. env() devuelve 0px en navegadores no-iOS, así que no afecta
       al desktop ni a Android. */
    padding-top:    calc(0.06 * var(--u) + env(safe-area-inset-top));
    padding-right:  calc(0.05 * var(--u) + env(safe-area-inset-right));
    padding-bottom: calc(0.05 * var(--u) + env(safe-area-inset-bottom));
    padding-left:   calc(0.05 * var(--u) + env(safe-area-inset-left));
    overflow: hidden;
}
/* Modo noche — redefine la variable indirecta para que toda la cascada
   (color base + dos copias + animación) reaccione automáticamente.
   También cambia --bg-speed por --bg-speed-night cuando exista, para que las
   animaciones del modo noche tengan su propia velocidad independiente. */
.dvc-classic[data-theme="night"],
[data-theme="night"] .dvc-classic {
    --bg-active: var(--dvc-bg-night, var(--dvc-bg-day));
    --bg-speed:  var(--bg-speed-night, var(--bg-speed));
}
/* Modo sólido: desactiva animación y reset de tamaño de background */
.dvc-classic[data-bg-mode="solid"] {
    animation: none;
    background-size: 100% 100%;
    background-position: 0 0;
}
/* Animación desactivada explícitamente (toggle "Animar movimiento" OFF) */
.dvc-classic[data-bg-anim="off"] {
    animation: none;
    background-position: 0% 50%;
}
/* Gradient con motion H/V/D: DOS COPIAS del fondo side-by-side
   se desplazan unidas. Cuando la primera sale por un extremo, la segunda
   (idéntica) ya está exactamente donde estaba la primera al inicio.
   Bucle continuo perfecto, sin saltos ni rebotes. */
.dvc-classic[data-bg-mode="gradient"][data-bg-motion="horizontal"],
.dvc-classic[data-bg-mode="gradient"][data-bg-motion="vertical"],
.dvc-classic[data-bg-mode="gradient"][data-bg-motion="diagonal"] {
    background-image: var(--bg-active), var(--bg-active);
    background-size: 100% 100%, 100% 100%;
    background-repeat: no-repeat, no-repeat;
    animation-duration: var(--bg-speed);
    animation-timing-function: linear;
    animation-iteration-count: infinite;
    animation-direction: normal;
}
.dvc-classic[data-bg-mode="gradient"][data-bg-motion="horizontal"] {
    background-position: 0% 0%, 100% 0%;
    animation-name: dvcClassicBgMove;
}
.dvc-classic[data-bg-mode="gradient"][data-bg-motion="vertical"] {
    background-position: 0% 0%, 0% 100%;
    animation-name: dvcClassicBgMoveV;
}
.dvc-classic[data-bg-mode="gradient"][data-bg-motion="diagonal"] {
    background-position: 0% 0%, 100% 100%;
    animation-name: dvcClassicBgMoveD;
}
/* Rotación: una sola copia con background-size 200% (cíclica natural) */
.dvc-classic[data-bg-mode="gradient"][data-bg-motion="rotation"] {
    background-image: var(--bg-active);
    background-size: 200% 200%;
    animation-name: dvcClassicBgMoveR;
    animation-direction: normal;
    animation-timing-function: ease-in-out;
}

/* Bucle continuo sin salto: del 0% al 100% en una sola dirección.
   Funciona sin "tirón" porque el degradado se sirve ya espejado
   (A,B,C,D,C,B,A) — los colores en la posición 0% y 100% coinciden. */
/* Keyframes para motion H/V/D: animan DOS background-positions a la vez.
   Una copia sale por un extremo mientras la otra (idéntica) ocupa su lugar. */
@keyframes dvcClassicBgMove {
    from { background-position: 0% 0%, 100% 0%; }
    to   { background-position: -100% 0%, 0% 0%; }
}
@keyframes dvcClassicBgMoveV {
    from { background-position: 0% 0%, 0% 100%; }
    to   { background-position: 0% -100%, 0% 0%; }
}
@keyframes dvcClassicBgMoveD {
    from { background-position: 0% 0%, 100% 100%; }
    to   { background-position: -100% -100%, 0% 0%; }
}
/* Rotación: ya era cíclica, no necesita ajuste */
@keyframes dvcClassicBgMoveR {
    0%   { background-position: 0% 50%; }
    25%  { background-position: 50% 0%; }
    50%  { background-position: 100% 50%; }
    75%  { background-position: 50% 100%; }
    100% { background-position: 0% 50%; }
}

/* ──────────────────────────────────────────────────────────────────────
   MOTIONS NUEVAS (importadas del LFDP GradientGenerator):
     · rotate → rota la dirección visual del degradado (default).
     · wave   → hue-rotate fluido sobre el degradado.
     · zoom   → background-size pulsa de 100% a 150%.
   El layer de gradient vive en `.dvc-classic::before` para no afectar
   al contenido (texto, foto, RRSS) cuando se aplican filter/transform.
   El wrapper queda transparente; el contenido se eleva con z-index.
   Las viejas (horizontal/vertical/diagonal/rotation) se mantienen para
   no romper tarjetas ya activas en BD.
   ────────────────────────────────────────────────────────────────────── */
.dvc-classic[data-bg-mode="gradient"][data-bg-motion="rotate"],
.dvc-classic[data-bg-mode="gradient"][data-bg-motion="wave"],
.dvc-classic[data-bg-mode="gradient"][data-bg-motion="zoom"] {
    background: transparent;
    background-image: none;
    animation: none;
}
.dvc-classic[data-bg-mode="gradient"][data-bg-motion="rotate"]::before,
.dvc-classic[data-bg-mode="gradient"][data-bg-motion="wave"]::before,
.dvc-classic[data-bg-mode="gradient"][data-bg-motion="zoom"]::before {
    content: "";
    position: absolute;
    /* inset:-100% extiende el ::before a 300%×300% del padre, centrado. Así
       cuando rota 45° sus lados siempre cubren las esquinas del padre (la
       diagonal del cuadrado interno supera la diagonal del rectángulo del
       wrapper), evitando los triángulos negros que se veían antes. */
    inset: -100%;
    background-image: var(--bg-active);
    background-size: 200% 200%;
    background-position: center center;
    background-repeat: no-repeat;
    z-index: 0;
    transform-origin: center center;
    animation-duration: var(--bg-speed);
    animation-iteration-count: infinite;
    animation-timing-function: linear;
    will-change: transform, filter, background-size;
}
.dvc-classic[data-bg-mode="gradient"][data-bg-motion="rotate"]::before {
    animation-name: dvcMotionRotate;
}
.dvc-classic[data-bg-mode="gradient"][data-bg-motion="wave"]::before {
    animation-name: dvcMotionWave;
    animation-timing-function: ease;
}
.dvc-classic[data-bg-mode="gradient"][data-bg-motion="zoom"]::before {
    animation-name: dvcMotionZoom;
    animation-timing-function: ease-in-out;
}
/* Eleva el contenido por encima del ::before */
.dvc-classic[data-bg-motion="rotate"] > *,
.dvc-classic[data-bg-motion="wave"]   > *,
.dvc-classic[data-bg-motion="zoom"]   > * {
    position: relative;
    z-index: 1;
}
/* Animación off (toggle "Animar movimiento" desactivado): estático sin
   transform/filter. Se reduce el ::before a inset:0 (= mismo tamaño del padre)
   y background-size 100% 100% para que cubra exactamente sin rotar ni escalar.
   NOTA: el modo noche YA NO fuerza estático — desde la decisión 2026-05-10
   tiene paridad funcional con día (anula §6.14 del HANDOFF). Si el cliente
   quiere noche estático, simplemente desactiva "Animar movimiento" en el
   bloque de configuración del modo noche. */
.dvc-classic[data-bg-anim="off"][data-bg-motion="rotate"]::before,
.dvc-classic[data-bg-anim="off"][data-bg-motion="wave"]::before,
.dvc-classic[data-bg-anim="off"][data-bg-motion="zoom"]::before {
    animation: none !important;
    inset: 0;
    background-size: 100% 100%;
    transform: none;
    filter: none;
}

@keyframes dvcMotionRotate {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}
/* Wave suave (decidido 2026-05-10): el rango hue-rotate va de -10° a +15° en
   lugar del original -30°/+45°. El cliente sigue viendo claramente sus colores
   marca; el efecto solo añade un latido sutil sin transformarlos. */
@keyframes dvcMotionWave {
    0%   { filter: hue-rotate(0deg)   brightness(1); }
    33%  { filter: hue-rotate(15deg)  brightness(1.04); }
    66%  { filter: hue-rotate(-10deg) brightness(0.97); }
    100% { filter: hue-rotate(0deg)   brightness(1); }
}
@keyframes dvcMotionZoom {
    0%, 100% { background-size: 100% 100%; }
    50%       { background-size: 150% 150%; }
}

/* ── Header (logo izq · toggle día/noche dcha) ─────────────── */
.dvc-classic .dvc-card__hdr {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: calc(0.07 * var(--u));
    flex-shrink: 0;
}
.dvc-classic .dvc-card__logo {
    height: calc(0.05 * var(--u));
    width: auto;
    display: block;
    opacity: 0.92;
    user-select: none;
}
.dvc-classic .dvc-theme-toggle {
    width: calc(0.094 * var(--u));
    height: calc(0.094 * var(--u));
    border-radius: 50%;
    background: rgba(0,0,0,0.28);
    border: none;
    color: #fff;
    cursor: pointer;
    position: relative;
    display: flex; align-items: center; justify-content: center;
    font-size: calc(0.039 * var(--u));
    transition: background 200ms ease, transform 200ms ease;
    padding: 0;
}
.dvc-classic .dvc-theme-toggle:hover { background: rgba(0,0,0,0.4); transform: scale(1.05); }

.dvc-classic .dvc-theme-toggle__moon,
.dvc-classic .dvc-theme-toggle__sun {
    position: absolute;
    top: 50%; left: 50%;
    transition: opacity 500ms ease, transform 500ms ease;
}
.dvc-classic .dvc-theme-toggle__moon { opacity: 1; transform: translate(-50%, -50%) rotate(0deg); }
.dvc-classic .dvc-theme-toggle__sun  { opacity: 0; transform: translate(-50%, -50%) rotate(-180deg); }

.dvc-classic[data-theme="night"] .dvc-theme-toggle__moon,
[data-theme="night"] .dvc-classic .dvc-theme-toggle__moon { opacity: 0; transform: translate(-50%, -50%) rotate(180deg); }
.dvc-classic[data-theme="night"] .dvc-theme-toggle__sun,
[data-theme="night"] .dvc-classic .dvc-theme-toggle__sun  { opacity: 1; transform: translate(-50%, -50%) rotate(0deg); }

/* ── Foto / avatar ─────────────────────────────────────────── */
.dvc-classic .dvc-photo {
    width: calc(0.57 * var(--u));
    height: calc(0.57 * var(--u));
    border-radius: 50%;
    /* Borde del avatar configurable (punto 4): grosor y color del cliente con
       fallback al valor por defecto de la plantilla. El color noche se aplica
       más abajo con [data-theme="night"]. */
    border: calc(var(--avatar-borde-grosor, 0.011) * var(--u)) solid var(--avatar-borde-color-dia, #fff);
    background: rgba(255,255,255,0.16);
    overflow: hidden;
    display: flex; align-items: center; justify-content: center;
    margin-bottom: calc(0.04 * var(--u));
    box-shadow: 0 calc(0.033 * var(--u)) calc(0.089 * var(--u)) rgba(0,0,0,0.2);
    flex-shrink: 0;
}
/* `.dvc-photo` ahora es contenedor relativo: dentro vive un BG (img/video)
   ocupando el círculo entero, un OVERLAY opcional centrado encima, y
   un PLACEHOLDER que se muestra solo si no hay BG. Las variantes -night
   sustituyen automáticamente al cambiar data-theme. */
.dvc-classic .dvc-photo { position: relative; }
/* Borde del avatar en modo noche (punto 4): color noche propio, con fallback al
   de día si el cliente no lo cambió. */
.dvc-classic[data-theme="night"] .dvc-photo,
[data-theme="night"] .dvc-classic .dvc-photo {
    border-color: var(--avatar-borde-color-noche, var(--avatar-borde-color-dia, #fff));
}

/* Imagen de fondo del círculo. La versión DÍA siempre se muestra (es el
   fallback). La versión NOCHE solo se renderiza en HTML si el cliente la
   subió, y cuando data-theme="night" se pinta ENCIMA de la día (z-index
   superior). Si no se subió, en noche se sigue viendo la del día. */
.dvc-classic .dvc-photo__bg,
.dvc-classic .dvc-photo__bg-night {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    object-fit: cover;
    object-position: center;
    display: block;
}
.dvc-classic .dvc-photo__bg       { z-index: 1; transition: opacity 200ms ease; }
.dvc-classic .dvc-photo__bg-night { z-index: 1; opacity: 0; transition: opacity 200ms ease; }
.dvc-classic[data-theme="night"] .dvc-photo__bg-night,
[data-theme="night"] .dvc-classic .dvc-photo__bg-night { opacity: 1; z-index: 2; }
/* En modo noche, si el cliente subió variante noche, ocultamos la del día
   para que no se vea por debajo (caso típico: BG/logo con transparencia
   donde la del día queda asomando bajo la del noche → "duplicación"). Si
   NO hay variante noche, la del día sigue visible (fallback). */
.dvc-classic[data-theme="night"] .dvc-photo:has(.dvc-photo__bg-night) .dvc-photo__bg,
[data-theme="night"] .dvc-classic .dvc-photo:has(.dvc-photo__bg-night) .dvc-photo__bg { opacity: 0; }

/* Overlay (logo SVG/PNG transparente). Mismo principio de fallback:
   .dvc-photo__overlay (día) siempre visible si el cliente lo subió;
   .dvc-photo__overlay-night solo se monta si el cliente lo subió y se
   pinta encima en modo noche. Las variables --fg-scale / --fg-pos-y
   controlan tamaño y posición — ojo: el editor inyecta también las
   variantes -day y -night en el wrapper, y aquí abajo tomamos las
   correctas según el tema. */
.dvc-classic .dvc-photo__overlay,
.dvc-classic .dvc-photo__overlay-night {
    position: absolute; left: 50%;
    width: calc(var(--fg-scale-day, var(--fg-scale, 92)) * 1%);
    top:   calc(var(--fg-pos-y-day, var(--fg-pos-y, 50)) * 1%);
    transform: translate(-50%, -50%);
    object-fit: contain;
    pointer-events: none;
    user-select: none;
}
.dvc-classic .dvc-photo__overlay       { z-index: 3; transition: opacity 200ms ease; }
.dvc-classic .dvc-photo__overlay-night { z-index: 3; opacity: 0; transition: opacity 200ms ease; }
.dvc-classic[data-theme="night"] .dvc-photo__overlay-night,
[data-theme="night"] .dvc-classic .dvc-photo__overlay-night { opacity: 1; z-index: 4; }
/* Mismo principio que el BG: en noche, si hay overlay-night subido,
   ocultamos overlay-day para evitar que se vea por debajo (caso típico:
   logos PNG/SVG con transparencia). */
.dvc-classic[data-theme="night"] .dvc-photo:has(.dvc-photo__overlay-night) .dvc-photo__overlay,
[data-theme="night"] .dvc-classic .dvc-photo:has(.dvc-photo__overlay-night) .dvc-photo__overlay { opacity: 0; }
/* Tamaño/posición independientes del overlay según tema. Si las variantes
   noche (--fg-scale-night / --fg-pos-y-night) no están definidas, el
   overlay-night usa las del día como fallback. */
.dvc-classic[data-theme="night"] .dvc-photo__overlay-night,
[data-theme="night"] .dvc-classic .dvc-photo__overlay-night {
    width: calc(var(--fg-scale-night, var(--fg-scale-day, var(--fg-scale, 92))) * 1%);
    top:   calc(var(--fg-pos-y-night, var(--fg-pos-y-day, var(--fg-pos-y, 50))) * 1%);
}

.dvc-classic .dvc-photo__placeholder {
    font-size: calc(0.14 * var(--u));
    color: rgba(255,255,255,0.7);
    z-index: 1;
}

/* ── Nombre / cargo ───────────────────────────────────────── */
.dvc-classic .dvc-name {
    font-size: calc(0.072 * var(--u));
    font-weight: 700;
    line-height: 1.18;
    text-align: center;
    margin-bottom: calc(0.005 * var(--u));
    word-break: break-word;
    max-width: 100%;
    /* Color día por defecto. El tema noche lo sobrescribe abajo. */
    color: var(--name-color-day, #ffffff);
}
.dvc-classic .dvc-role {
    font-size: calc(0.033 * var(--u));
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    text-align: center;
    margin-bottom: calc(0.082 * var(--u));
    color: var(--role-color-day, #ffffffb3);
    /* Sin opacity: el alpha viene del color HEX que elija el cliente
       (ej. #ffffffb3 = blanco al 70%). */
}
/* Modo noche: usa las variables propias si están, si no hereda las del día. */
.dvc-classic[data-theme="night"] .dvc-name,
[data-theme="night"] .dvc-classic .dvc-name {
    color: var(--name-color-night, var(--name-color-day, #ffffff));
}
.dvc-classic[data-theme="night"] .dvc-role,
[data-theme="night"] .dvc-classic .dvc-role {
    color: var(--role-color-night, var(--role-color-day, #ffffffb3));
}

/* ── Botones RRSS ─────────────────────────────────────────── */
/* Grid forzado a 5 columnas: con `max-width = 5 botones + 4 gaps`, el flex-wrap
   solo cabe 5 por fila. La 1ª fila ocupa todo el ancho del contenedor; la 2ª
   (con menos botones) queda centrada gracias a `justify-content: center`.
   Eso da automáticamente el patrón 5+4 (o 5+3+pill, 5+5+, etc.) según
   cuántos enlaces tenga el cliente. */
.dvc-classic .dvc-rrss {
    display: flex;
    flex-wrap: wrap;
    gap: calc(0.026 * var(--u));
    justify-content: center;
    margin-left: auto;
    margin-right: auto;
    margin-bottom: auto;
    max-width: calc(0.829 * var(--u));   /* 5 * 0.145 + 4 * 0.026 = 0.829 */
}
.dvc-classic .dvc-rrss__btn {
    width: calc(0.145 * var(--u));
    height: calc(0.145 * var(--u));
    border-radius: 50%;
    background: rgba(0,0,0,0.35);
    color: #fff;
    display: flex; align-items: center; justify-content: center;
    font-size: calc(0.05 * var(--u));
    border: none;
    cursor: pointer;
    text-decoration: none;
    transition: transform 200ms ease, background 200ms ease;
    padding: 0;
}
.dvc-classic .dvc-rrss__btn:hover {
    transform: translateY(calc(-0.005 * var(--u)));
    background: rgba(0,0,0,0.5);
}
.dvc-classic[data-theme="night"] .dvc-rrss__btn,
[data-theme="night"] .dvc-classic .dvc-rrss__btn { background: rgba(255,255,255,0.15); }
/* El glyph de WhatsApp (FA brands) tiene más aire interno y se ve más pequeño a
   igual font-size → lo agrandamos un poco para que case con los demás iconos. */
.dvc-classic .dvc-rrss__btn .fa-whatsapp { font-size: 1.14em; }
.dvc-classic[data-theme="night"] .dvc-rrss__btn:hover,
[data-theme="night"] .dvc-classic .dvc-rrss__btn:hover { background: rgba(255,255,255,0.22); }

/* Botón "más" (3 puntos / X) — cambia el icono según aria-expanded.
   Vive como un botón más en la rejilla 5+4. Al pulsarlo despliega los
   .dvc-rrss__extras justo debajo (no abre pop-up flotante). */
.dvc-classic .dvc-rrss__more { background: rgba(0,0,0,0.45); }
.dvc-classic .dvc-rrss__more-icon--open { display: none; }
.dvc-classic .dvc-rrss__more[aria-expanded="true"] .dvc-rrss__more-icon--closed { display: none; }
.dvc-classic .dvc-rrss__more[aria-expanded="true"] .dvc-rrss__more-icon--open  { display: inline-block; }

/* Extras inline — fila adicional debajo de las RRSS principales.
   Misma rejilla, mismo tamaño de botones. Empieza colapsado (max-height 0).
   El JS asigna max-height = scrollHeight para animar la apertura, y al
   acabar la transición libera max-height a 'none' para responsive. */
.dvc-classic .dvc-rrss__extras {
    flex-basis: 100%;
    width: 100%;
    max-width: calc(0.829 * var(--u));
    margin-left: auto;
    margin-right: auto;
    margin-top: 0;
    display: flex;
    flex-wrap: wrap;
    gap: calc(0.026 * var(--u));
    justify-content: center;
    max-height: 0;
    overflow: hidden;
    transition: max-height 300ms ease, margin-top 300ms ease;
}
.dvc-classic .dvc-rrss__extras[data-expanded="true"] {
    margin-top: calc(0.026 * var(--u));
}

/* ── Acciones (CTA) ───────────────────────────────────────── */
/* Pill "Guardar contacto" + (opcional) círculo compartir al lado.
   - Sin compartir → el pill ocupa toda la fila (full-width).
   - Con compartir → el pill se achica con flex:1 y el círculo se posiciona
     a la derecha. */
.dvc-classic .dvc-actions {
    width: 100%;
    display: flex;
    gap: calc(0.028 * var(--u));
    margin-top: calc(0.06 * var(--u));
    flex-shrink: 0;
}
.dvc-classic .dvc-actions__save {
    flex: 1;
    background: rgba(0,0,0,0.32);
    color: #fff;
    border: none;
    border-radius: calc(0.078 * var(--u));
    padding: calc(0.039 * var(--u)) calc(0.05 * var(--u));
    display: flex; align-items: center; justify-content: center;
    gap: calc(0.022 * var(--u));
    font-family: inherit;
    font-size: calc(0.042 * var(--u));
    font-weight: 500;
    text-decoration: none;
    cursor: pointer;
    white-space: nowrap;  /* el texto 'Guardar contacto' nunca parte en 2 lineas (preview estrecho) */
    transition: background 200ms ease, transform 200ms ease;
}
.dvc-classic .dvc-actions__save:hover { background: rgba(0,0,0,0.45); transform: translateY(calc(-0.003 * var(--u))); }
.dvc-classic .dvc-actions__save i { font-size: calc(0.044 * var(--u)); }

.dvc-classic :is(.dvc-actions__share, .dvc-actions__qr) {
    width: calc(0.144 * var(--u));
    height: calc(0.144 * var(--u));
    border-radius: 50%;
    background: rgba(0,0,0,0.32);
    color: #fff;
    border: none;
    display: flex; align-items: center; justify-content: center;
    font-size: calc(0.05 * var(--u));
    cursor: pointer;
    flex-shrink: 0;
    transition: background 200ms ease, transform 200ms ease;
    padding: 0;
}
.dvc-classic :is(.dvc-actions__share, .dvc-actions__qr):hover { background: rgba(0,0,0,0.45); transform: translateY(calc(-0.003 * var(--u))); }

.dvc-classic[data-theme="night"] .dvc-actions__save,
.dvc-classic[data-theme="night"] :is(.dvc-actions__share, .dvc-actions__qr),
[data-theme="night"] .dvc-classic .dvc-actions__save,
[data-theme="night"] .dvc-classic :is(.dvc-actions__share, .dvc-actions__qr) {
    background: rgba(255,255,255,0.15);
}
.dvc-classic[data-theme="night"] .dvc-actions__save:hover,
.dvc-classic[data-theme="night"] :is(.dvc-actions__share, .dvc-actions__qr):hover,
[data-theme="night"] .dvc-classic .dvc-actions__save:hover,
[data-theme="night"] .dvc-classic :is(.dvc-actions__share, .dvc-actions__qr):hover {
    background: rgba(255,255,255,0.22);
}

/* ============================================================================
   ESTILOS DE BOTONES · Migration 028
   Controlados por data-rrss-style en .dvc-classic. Aplican a RRSS, "Más
   enlaces", "Guardar contacto" y "Compartir" de forma coherente.
     fill    → default (sin override; los estilos base de arriba pegan)
     outline → borde + fondo transparente
     ghost   → solo icono, sin caja
     glass   → liquid blur iOS 26
   ============================================================================ */

/* ── OUTLINE ─────────────────────────────────────────────── */
.dvc-classic[data-rrss-style="outline"] .dvc-rrss__btn,
.dvc-classic[data-rrss-style="outline"] :is(.dvc-actions__share, .dvc-actions__qr),
.dvc-classic[data-rrss-style="outline"] .dvc-actions__save {
    background: transparent;
    border: 1.5px solid currentColor;
    color: #fff;
}
.dvc-classic[data-rrss-style="outline"] .dvc-rrss__btn:hover,
.dvc-classic[data-rrss-style="outline"] :is(.dvc-actions__share, .dvc-actions__qr):hover,
.dvc-classic[data-rrss-style="outline"] .dvc-actions__save:hover {
    background: rgba(255,255,255,0.08);
    transform: translateY(calc(-0.005 * var(--u)));
}
.dvc-classic[data-rrss-style="outline"][data-theme="night"] .dvc-rrss__btn,
.dvc-classic[data-rrss-style="outline"][data-theme="night"] :is(.dvc-actions__share, .dvc-actions__qr),
.dvc-classic[data-rrss-style="outline"][data-theme="night"] .dvc-actions__save,
[data-theme="night"] .dvc-classic[data-rrss-style="outline"] .dvc-rrss__btn,
[data-theme="night"] .dvc-classic[data-rrss-style="outline"] :is(.dvc-actions__share, .dvc-actions__qr),
[data-theme="night"] .dvc-classic[data-rrss-style="outline"] .dvc-actions__save {
    background: transparent;
}

/* ── GHOST ───────────────────────────────────────────────── */
.dvc-classic[data-rrss-style="ghost"] .dvc-rrss__btn,
.dvc-classic[data-rrss-style="ghost"] :is(.dvc-actions__share, .dvc-actions__qr) {
    background: transparent;
    border: none;
    color: #fff;
    font-size: calc(0.062 * var(--u));
}
.dvc-classic[data-rrss-style="ghost"] .dvc-actions__save {
    background: transparent;
    border: none;
    color: #fff;
}
.dvc-classic[data-rrss-style="ghost"] .dvc-rrss__btn:hover,
.dvc-classic[data-rrss-style="ghost"] :is(.dvc-actions__share, .dvc-actions__qr):hover,
.dvc-classic[data-rrss-style="ghost"] .dvc-actions__save:hover {
    background: transparent;
    transform: translateY(calc(-0.005 * var(--u))) scale(1.05);
}
.dvc-classic[data-rrss-style="ghost"][data-theme="night"] .dvc-rrss__btn,
.dvc-classic[data-rrss-style="ghost"][data-theme="night"] :is(.dvc-actions__share, .dvc-actions__qr),
.dvc-classic[data-rrss-style="ghost"][data-theme="night"] .dvc-actions__save,
[data-theme="night"] .dvc-classic[data-rrss-style="ghost"] .dvc-rrss__btn,
[data-theme="night"] .dvc-classic[data-rrss-style="ghost"] :is(.dvc-actions__share, .dvc-actions__qr),
[data-theme="night"] .dvc-classic[data-rrss-style="ghost"] .dvc-actions__save {
    background: transparent;
}

/* ── GLASS · iOS 26 Liquid Glass ─────────────────────────── */
.dvc-classic[data-rrss-style="glass"] .dvc-rrss__btn,
.dvc-classic[data-rrss-style="glass"] :is(.dvc-actions__share, .dvc-actions__qr),
.dvc-classic[data-rrss-style="glass"] .dvc-actions__save {
    background: rgba(255,255,255,0.14);
    backdrop-filter: blur(22px) saturate(180%);
    -webkit-backdrop-filter: blur(22px) saturate(180%);
    border: 1px solid rgba(255,255,255,0.22);
    box-shadow: 0 4px 24px rgba(0,0,0,0.18),
                inset 0 1px 0 rgba(255,255,255,0.25);
    color: #fff;
}
.dvc-classic[data-rrss-style="glass"] .dvc-rrss__btn:hover,
.dvc-classic[data-rrss-style="glass"] :is(.dvc-actions__share, .dvc-actions__qr):hover,
.dvc-classic[data-rrss-style="glass"] .dvc-actions__save:hover {
    background: rgba(255,255,255,0.22);
    transform: translateY(calc(-0.005 * var(--u)));
}
.dvc-classic[data-rrss-style="glass"][data-theme="night"] .dvc-rrss__btn,
.dvc-classic[data-rrss-style="glass"][data-theme="night"] :is(.dvc-actions__share, .dvc-actions__qr),
.dvc-classic[data-rrss-style="glass"][data-theme="night"] .dvc-actions__save,
[data-theme="night"] .dvc-classic[data-rrss-style="glass"] .dvc-rrss__btn,
[data-theme="night"] .dvc-classic[data-rrss-style="glass"] :is(.dvc-actions__share, .dvc-actions__qr),
[data-theme="night"] .dvc-classic[data-rrss-style="glass"] .dvc-actions__save {
    background: rgba(255,255,255,0.10);
    border-color: rgba(255,255,255,0.16);
}
[data-theme="night"] .dvc-classic[data-rrss-style="glass"] .dvc-rrss__btn:hover,
[data-theme="night"] .dvc-classic[data-rrss-style="glass"] :is(.dvc-actions__share, .dvc-actions__qr):hover,
[data-theme="night"] .dvc-classic[data-rrss-style="glass"] .dvc-actions__save:hover {
    background: rgba(255,255,255,0.18);
}

/* ── Footer ───────────────────────────────────────────────── */
.dvc-classic .dvc-footer {
    margin-top: calc(0.025 * var(--u));
    padding-top: calc(0.015 * var(--u));
    font-size: calc(0.031 * var(--u));
    color: rgba(255,255,255,0.55);
    text-align: center;
    flex-shrink: 0;
}
.dvc-classic .dvc-footer a {
    color: inherit;
    text-decoration: none;
    text-underline-offset: calc(0.0055 * var(--u));
}
.dvc-classic .dvc-footer a:hover {
    text-decoration: underline;
}

/* ════════════════════════════════════════════════════════════════════
   PÁGINA REAL DEL VISITANTE (cuando se sirve la tarjeta)
   ─────────────────────────────────────────────────────────────────────
   · MÓVIL (<920px): la tarjeta ocupa toda la pantalla.
   · ESCRITORIO/TABLET (≥920px): mockup iPhone centrado, con logo
     digitalVCard a la izquierda y flecha → digitalvcard.es a la derecha.
   El editor NO ejecuta esto porque su body tiene su propio estilo.
   ════════════════════════════════════════════════════════════════════ */
body.dvc-classic-page {
    margin: 0;
    /* Stacking context aislado: la capa del fondo (::before, z-index:0) queda
       BAJO el contenido (.dvc-page, z-index:1) y cubre toda la pantalla. */
    position: relative;
    isolation: isolate;
    overflow-x: hidden;
    /* Sin rebote elástico de iOS (overscroll). */
    overscroll-behavior: none;
    --bg-active: var(--dvc-bg-day, #0f0c29);
    background: var(--bg-active);
    background-size: 200% 200%;
    background-repeat: no-repeat;
    background-attachment: fixed;
    /* 100dvh gana en iPhone moderno → el body llena la pantalla VISIBLE real
       (evita la franja blanca que dejaba 100svh al quedarse corto). */
    min-height: 100vh;
    min-height: -webkit-fill-available;
    min-height: 100svh;
    min-height: 100dvh;
    color: #fff;
    font-family: 'Poppins', -apple-system, sans-serif;
}
body.dvc-classic-page[data-bg-mode="solid"] {
    animation: none;
    background-size: 100% 100%;
}
/* Animación off o motion="none": el body queda estático con el degradado
   cubriendo el viewport entero (no a 200%, que mostraba solo una esquina y
   creaba el efecto "rectángulo distinto dentro del iPhone"). */
body.dvc-classic-page[data-bg-anim="off"],
body.dvc-classic-page[data-bg-motion="none"],
body.dvc-classic-page:not([data-bg-motion]) {
    animation: none !important;
    background-size: 100% 100% !important;
    background-position: 0 0 !important;
}

/* Body con motion H/V/D: dos copias side-by-side animadas continuamente */
body.dvc-classic-page[data-bg-mode="gradient"][data-bg-motion="horizontal"],
body.dvc-classic-page[data-bg-mode="gradient"][data-bg-motion="vertical"],
body.dvc-classic-page[data-bg-mode="gradient"][data-bg-motion="diagonal"] {
    background-image: var(--bg-active), var(--bg-active);
    background-size: 100% 100%, 100% 100%;
    background-repeat: no-repeat, no-repeat;
    animation-duration: var(--bg-speed, 14s);
    animation-timing-function: linear;
    animation-iteration-count: infinite;
    animation-direction: normal;
}
body.dvc-classic-page[data-bg-mode="gradient"][data-bg-motion="horizontal"] {
    background-position: 0% 0%, 100% 0%;
    animation-name: dvcClassicBgMove;
}
body.dvc-classic-page[data-bg-mode="gradient"][data-bg-motion="vertical"] {
    background-position: 0% 0%, 0% 100%;
    animation-name: dvcClassicBgMoveV;
}
body.dvc-classic-page[data-bg-mode="gradient"][data-bg-motion="diagonal"] {
    background-position: 0% 0%, 100% 100%;
    animation-name: dvcClassicBgMoveD;
}
body.dvc-classic-page[data-bg-mode="gradient"][data-bg-motion="rotation"] {
    background-image: var(--bg-active);
    background-size: 200% 200%;
    animation: dvcClassicBgMoveR var(--bg-speed, 14s) ease-in-out infinite;
}

/* ── BODY: motions NUEVAS (rotate / wave / zoom) ──────────────────────
   Mismo patrón que en .dvc-classic::before pero el ::before es FIXED al
   viewport. Eso hace que el degradado animado cubra TODO el body y se vea
   atravesando el marco transparente del iPhone en vista escritorio
   (efecto "ventana real"). En móvil, donde el .dvc-classic ocupa la
   pantalla entera (transparente sobre el body), el efecto es simplemente
   "fondo a pantalla completa". */
body.dvc-classic-page[data-bg-mode="gradient"][data-bg-motion="rotate"],
body.dvc-classic-page[data-bg-mode="gradient"][data-bg-motion="wave"],
body.dvc-classic-page[data-bg-mode="gradient"][data-bg-motion="zoom"] {
    background: transparent;
    background-image: none;
    animation: none;
}
body.dvc-classic-page[data-bg-mode="gradient"][data-bg-motion="rotate"]::before,
body.dvc-classic-page[data-bg-mode="gradient"][data-bg-motion="wave"]::before,
body.dvc-classic-page[data-bg-mode="gradient"][data-bg-motion="zoom"]::before {
    content: "";
    position: fixed;
    inset: -100vmax;          /* vmax: cobertura estable basada en el viewport grande */
    background-image: var(--bg-active);
    background-size: 200% 200%;
    background-position: center center;
    background-repeat: no-repeat;
    z-index: 0;               /* dentro del stacking aislado del body: bajo .dvc-page (z-index:1) */
    transform-origin: center center;
    animation-duration: var(--bg-speed, 8s);
    animation-iteration-count: infinite;
    animation-timing-function: linear;
    pointer-events: none;
    will-change: transform, filter, background-size;
}
body.dvc-classic-page[data-bg-mode="gradient"][data-bg-motion="rotate"]::before { animation-name: dvcMotionRotate; }
body.dvc-classic-page[data-bg-mode="gradient"][data-bg-motion="wave"]::before   { animation-name: dvcMotionWave;  animation-timing-function: ease; }
body.dvc-classic-page[data-bg-mode="gradient"][data-bg-motion="zoom"]::before   { animation-name: dvcMotionZoom;  animation-timing-function: ease-in-out; }
/* Animación del body desactivada explícitamente: el ::before queda estático */
body.dvc-classic-page[data-bg-anim="off"][data-bg-motion="rotate"]::before,
body.dvc-classic-page[data-bg-anim="off"][data-bg-motion="wave"]::before,
body.dvc-classic-page[data-bg-anim="off"][data-bg-motion="zoom"]::before {
    animation: none !important;
    inset: 0;
    background-size: 100% 100%;
    transform: none;
    filter: none;
}

/* Body en modo noche — solo redefine la variable indirecta. La animación
   se decide via data-bg-motion (las reglas de motion miran el attr base, que
   ya refleja el tema activo gracias a __dvcSyncTheme en template.html). */
body.dvc-classic-page[data-theme="night"],
[data-theme="night"] body.dvc-classic-page {
    --bg-active: var(--dvc-bg-night, var(--dvc-bg-day));
    --bg-speed:  var(--bg-speed-night, var(--bg-speed));
}

/* ════════════════════════════════════════════════════════════════════
   MARCO TRANSPARENTE en la página real
   ─────────────────────────────────────────────────────────────────────
   En la página del visitante el FONDO vive en el body. La tarjeta
   (.dvc-classic) y el "screen" del iPhone se vuelven transparentes,
   de modo que el degradado animado del body se ve atravesando el
   marco del iPhone como si fuera una ventana real.

   En el editor (donde no hay body.dvc-classic-page), el .dvc-classic
   mantiene su propio fondo + animación, así el cliente ve el preview
   completo dentro del iPhone sin problemas.
   ════════════════════════════════════════════════════════════════════ */
/* En la URL pública el `.dvc-classic` Y el `.dvc-page__screen` deben ser
   completamente transparentes para que el degradado del body se vea
   atravesando el marco del iPhone (efecto "ventana real"). Usamos longhands
   explícitas con !important para evitar cualquier shorthand previo. */
body.dvc-classic-page .dvc-classic,
body.dvc-classic-page .dvc-page__screen {
    background-color: transparent !important;
    background-image: none !important;
    animation: none !important;
}
/* El `.dvc-classic::before` (que pinta el degradado en el editor) aquí debe
   desactivarse — si no, veríamos el degradado dos veces. */
body.dvc-classic-page .dvc-classic::before {
    display: none !important;
}

.dvc-page {
    width: 100%;
    /* 100dvh gana en iPhone moderno (pantalla visible real). vh/fill-available/
       svh como fallback. */
    min-height: 100vh;
    min-height: -webkit-fill-available;
    min-height: 100svh;
    min-height: 100dvh;
    /* Sobre la capa de fondo (::before z-index:0) dentro del stacking del body. */
    position: relative;
    z-index: 1;
    display: flex;
    align-items: stretch;
    justify-content: center;
}

/* ── Móvil: tarjeta a pantalla completa ─────────────────── */
.dvc-page__branding,
.dvc-page__arrow,
.dvc-page__frame { display: none; }

.dvc-page__mockup,
.dvc-page__screen {
    width: 100%;
    flex: 1;
    display: flex;
    flex-direction: column;
}
.dvc-page__screen .dvc-classic {
    --u: min(100vw, 480px);
    width: 100%;
    max-width: 480px;
    margin: 0 auto;
    min-height: 100vh;
    min-height: -webkit-fill-available;
    min-height: 100svh;
    min-height: 100dvh;
}

/* ── Móvil alto (≥800px de altura, <920px de ancho): reparto vertical ──
   En iPhone Pro Max, Plus, Pro y similares el contenido se quedaba
   compactado arriba dejando un hueco grande entre RRSS y "Guardar contacto".
   Añadimos un segundo `margin: auto` al círculo (.dvc-photo) que reparte el
   espacio sobrante en dos huecos: uno entre header y círculo, otro entre
   RRSS y acciones. Se combina con el `margin-bottom: auto` ya existente en
   .dvc-rrss. Sesión 8. */
@media (min-height: 800px) and (max-width: 919px) {
    body.dvc-classic-page .dvc-classic .dvc-photo {
        margin-top: auto;
    }
}

/* ── Escritorio (≥920px): mockup iPhone + branding + flecha ── */
@media (min-width: 920px) {
    .dvc-page {
        align-items: center;
        justify-content: center;
        gap: 4rem;
        padding: 2rem 3rem;
    }

    .dvc-page__branding {
        display: block;
        flex: none;
        max-width: 280px;
        text-decoration: none;
    }
    .dvc-page__brand-logo {
        width: 100%;
        height: auto;
        display: block;
        opacity: 0.95;
        transition: opacity 200ms ease;
    }
    .dvc-page__brand-logo:hover { opacity: 1; }
    .dvc-page__brand-logo--negro { display: none; }

    /* PNG DigitalVCard-iPhone@2x — 2932×5976. Hueco transparente medido con GD
       (esquivando la isla dinámica): left 146, top 122, w 2640, h 5732 →
       ratio 2.171 (≈ iPhone real). Posicionamos el screen en % del mockup, así
       es independiente de la resolución del PNG y del ancho del mockup: si algún
       día cambia la imagen con la misma proporción de hueco, no hay que re-medir. */
    .dvc-page__mockup {
        position: relative;
        width: 390px;
        flex: none;
        display: block;
        filter: drop-shadow(0 32px 64px rgba(0,0,0,0.4));
    }
    .dvc-page__frame {
        display: block;
        width: 100%;
        height: auto;
        position: relative;
        z-index: 2;
        pointer-events: none;
        user-select: none;
    }
    /* Hueco en % del lienzo del PNG: top 2.04% · left 4.98% · w 90.04% · h 95.92%.
       Sin border-radius (el PNG ya redondea sus esquinas). */
    .dvc-page__screen {
        position: absolute;
        top: 2.04%; left: 4.98%;
        width: 90.04%; height: 95.92%;
        overflow: hidden;
        border-radius: 42px;   /* tapa los "picos" rectos bajo el bisel del PNG */
        /* SIN z-index: así el screen NO crea contexto de apilado propio. La
           tarjeta queda bajo el bisel del PNG (z-index:2), pero el sheet del
           microsite (z-index:1000) sube POR ENCIMA del PNG → al abrirlo tapa
           la barra de Safari dibujada en la imagen. El overflow:hidden lo
           sigue recortando al marco. */
        flex: none;
        display: block;
    }
    /* Zona segura del mockup: el PNG lleva dibujadas la status bar/isla
       (arriba 4.96% del hueco) y la barra de Safari (abajo 6.63%). El FONDO
       (degradado del body) llena todo el hueco — lo que insetamos es solo el
       CONTENIDO, para que no se solape con esas franjas. En móvil esto no
       aplica (usa env(safe-area) del dispositivo real). */
    .dvc-page__screen .dvc-classic {
        --u: 351px;
        position: absolute;
        top: 4.96%;
        bottom: 9%;        /* algo más que la franja de Safari → el footer © respira */
        left: 0; right: 0;
        width: auto;
        max-width: none;
        min-height: auto;
        height: auto;
        margin: 0;
    }
    /* Microsite: en escritorio el sheet/lightbox (que en móvil son
       position:fixed = pantalla completa) pasan a position:absolute para
       quedar CONFINADOS a la pantalla del iPhone (overflow:hidden los recorta). */
    .dvc-page__screen .dvc-ms-overlay,
    .dvc-page__screen .dvc-ms-lightbox {
        position: absolute;
    }
    /* El sheet se detiene SOBRE la barra de Safari (no toca el borde) y su
       alto se limita a la pantalla del mockup, no al viewport (el 92vh base
       se veía enorme dentro del marco). El lightbox sí cubre toda la pantalla. */
    /* El sheet llena hasta el fondo de la pantalla → el gris cubre el hueco
       inferior (ya no asoma la tarjeta). La barra de Safari del PNG (z-index:2)
       se dibuja encima; separamos el contenido de ella con padding-bottom.
       max-height relativo a la pantalla del mockup, no al viewport. */
    .dvc-page__screen .dvc-ms-sheet {
        max-height: 75%;   /* 3/4 de la pantalla del mockup; cabecera fija + scroll */
        /* Solo en el marco de escritorio: redondeamos también las esquinas de
           ABAJO para seguir la curva de la pantalla del mockup. En móvil NO
           (base sin radio inferior → la hoja sale desde abajo y queda oculta). */
        border-radius: var(--ms-radius-sheet) var(--ms-radius-sheet) 48px 48px;
    }
    /* El padding que separa el contenido de la barra de Safari del PNG va ahora
       al cuerpo scrolleable (.dvc-ms-body), no a la hoja. */
    .dvc-page__screen .dvc-ms-body {
        padding-bottom: 70px;
    }

    .dvc-page__arrow {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 56px; height: 56px;
        border-radius: 50%;
        background: rgba(255,255,255,0.1);
        color: rgba(255,255,255,0.7);
        text-decoration: none;
        font-size: 1.25rem;
        flex: none;
        transition: all 200ms ease;
        backdrop-filter: blur(8px);
    }
    .dvc-page__arrow:hover {
        background: rgba(255,255,255,0.18);
        color: #fff;
        transform: translateX(4px);
    }
}

/* ── Modo embed (tarjeta cargada dentro de un iframe) ──────────────────
   El visitante ya está en digitalvcard.es (o donde sea que embeba),
   así que el branding y la flecha "ir a digitalvcard.es" son ruido.
   La clase la añade un script inline detectando window.self !== window.top. */
.dvc-page--embed .dvc-page__branding,
.dvc-page--embed .dvc-page__arrow { display: none !important; }

/* En embed: el único hijo visible es el mockup → eliminar gap y padding
   laterales asimétricos heredados del layout 3-columnas (branding · mockup
   · arrow) para que el iPhone quede perfectamente centrado en el viewport. */
@media (min-width: 920px) {
    .dvc-page--embed .dvc-page {
        gap: 0 !important;
        padding: 2rem 0 !important;
    }
}

/* ============================================================================
   OVERLAY "MI QR" · Migration 041
   Modal centrado que aparece al pulsar el botón QR de la tarjeta pública.
   Estética glass-blur Apple-style. JS en template.js (openQrOverlay).
   ============================================================================ */
.dvc-qr-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.55);
    backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
    display: flex; align-items: center; justify-content: center;
    padding: 1.25rem;
    z-index: 9999;
    opacity: 0;
    transition: opacity 220ms ease;
}
.dvc-qr-overlay.is-open { opacity: 1; }

.dvc-qr-card {
    background: #fff;
    color: #1d1d1f;
    border-radius: 28px;
    padding: 1.75rem 1.5rem 1.25rem;
    width: 100%;
    max-width: 360px;
    box-shadow: 0 24px 64px rgba(0,0,0,0.32);
    position: relative;
    transform: scale(0.94);
    transition: transform 220ms cubic-bezier(0.16, 1, 0.3, 1);
}
.dvc-qr-overlay.is-open .dvc-qr-card { transform: scale(1); }

.dvc-qr-close {
    position: absolute;
    top: 0.875rem; right: 0.875rem;
    width: 32px; height: 32px;
    border-radius: 50%;
    background: rgba(0,0,0,0.06);
    color: #1d1d1f;
    border: none;
    display: flex; align-items: center; justify-content: center;
    font-size: 0.875rem;
    cursor: pointer;
    transition: background 160ms ease;
}
.dvc-qr-close:hover { background: rgba(0,0,0,0.12); }

.dvc-qr-card__title {
    margin: 0 0 0.5rem 0;
    padding-right: 2rem;
    font-size: 1.125rem;
    font-weight: 600;
    letter-spacing: -0.01em;
}
.dvc-qr-card__hint {
    margin: 0 0 1.25rem 0;
    font-size: 0.8125rem;
    color: rgba(0,0,0,0.6);
    line-height: 1.45;
}
.dvc-qr-card__frame {
    background: #fff;
    border-radius: 18px;
    padding: 0.75rem;
    border: 1px solid rgba(0,0,0,0.08);
    display: flex; align-items: center; justify-content: center;
    margin-bottom: 1.25rem;
}
.dvc-qr-card__img {
    width: 100%;
    height: auto;
    display: block;
    image-rendering: pixelated;
    border-radius: 8px;
}
.dvc-qr-card__actions {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.625rem;
}
.dvc-qr-btn {
    appearance: none;
    border: 1px solid rgba(0,0,0,0.12);
    background: #fff;
    color: #1d1d1f;
    padding: 0.75rem 1rem;
    border-radius: 12px;
    font-size: 0.875rem;
    font-weight: 500;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    transition: background 160ms ease, transform 160ms ease;
}
.dvc-qr-btn:hover { background: rgba(0,0,0,0.04); transform: translateY(-1px); }
.dvc-qr-btn--primary {
    background: #0071e3;
    color: #fff;
    border-color: #0071e3;
}
.dvc-qr-btn--primary:hover { background: #0077ed; }
.dvc-qr-btn i { font-size: 0.8125rem; }

/* Modo noche: invertir paleta para coherencia con el resto del producto */
@media (prefers-color-scheme: dark) {
    .dvc-qr-card { background: #1c1c1e; color: #f5f5f7; }
    .dvc-qr-close { background: rgba(255,255,255,0.1); color: #f5f5f7; }
    .dvc-qr-close:hover { background: rgba(255,255,255,0.18); }
    .dvc-qr-card__hint { color: rgba(255,255,255,0.6); }
    .dvc-qr-card__frame { background: #fff; border-color: rgba(255,255,255,0.1); }
    .dvc-qr-btn { background: rgba(255,255,255,0.08); color: #f5f5f7; border-color: rgba(255,255,255,0.14); }
    .dvc-qr-btn:hover { background: rgba(255,255,255,0.14); }
}

@media (prefers-reduced-motion: reduce) {
    .dvc-qr-overlay, .dvc-qr-card { transition: none !important; }
    .dvc-qr-card { transform: none !important; }
}
