/* PROTOCOL_73 — Brand CSS (companion to Tailwind).
   Migrated from LingoNebula (2026-05-24). Migrated to Expediente (2026-07-18).

   Tokens (colors) live in ONE place: static/css/expediente-tokens.css
   (DESIGN_SYSTEM.md §7). This file only defines things Tailwind utilities
   can't express directly: keyframes, pseudo-element decorations, custom
   scrollbar, and a couple of legacy classes still consumed by
   not-yet-migrated templates. Nothing here should hardcode a brand hex —
   consume var(--token) or var(--token) + color-mix() for tints/glows.

   Cleanup 2026-07-18 (Worldcup migration pass): removed everything with
   zero real usage across templates — .status-live/.status-live-dark,
   .terminal-panel/.terminal-panel--active, .glass-panel, .neon-glow,
   .data-grid-bg/.data-grid-bg-dark/.dot-grid-bg, .crt-glow* utilities +
   their custom properties, .module-card, the whole .access-* block
   (16a-16d, orphaned since "Cripto opcional" left the landing), and the
   §1 legacy --color-* custom properties (either unused or migrated to
   Expediente tokens inline where they were still consumed). See
   .claude/agent-memory/frontend-engineer/ for the full audit trail. */

/* ── 1. GLOBAL FONT & BASE ── */
html {
    scroll-behavior: smooth;
    /* Standard scrollbar (Firefox/Edge/Chromium) — without this, Edge and
       Windows render the dark system scrollbar, which shows as a black line
       on the right of the page regardless of theme. */
    scrollbar-width: thin;
    scrollbar-color: color-mix(in srgb, var(--ink) 25%, transparent) var(--bg);
}

body {
    /* Archivo is already applied via the `font-sans` class on <body> in
       base.html (Tailwind preflight + explicit class) — no font-family
       override needed here. Only base surface colors, theme-aware. */
    background-color: var(--bg);
    color: var(--ink);
}

/* ── 2. STATUS PILLS ── */
/* "Pending" pill — still consumed by templates/learning/index.html.
   Gold/amber family → warn token (DESIGN_SYSTEM.md §2.1: "estado en curso, avisos"). */
.status-pending {
    background: var(--warn-tint);
    border: 1px solid color-mix(in srgb, var(--warn) 45%, transparent);
    color: var(--warn);
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

/* ── 3. ANIMATIONS (generic, color-agnostic) ── */
@keyframes blink {
    0%, 49.9% { opacity: 1; }
    50%, 100%  { opacity: 0; }
}

@keyframes pulse-dot {
    0%, 100% { opacity: 1; }
    50%       { opacity: 0.3; }
}

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

.animate-cursor-blink {
    animation: blink 1s step-end infinite;
}

.animate-pulse-dot {
    animation: pulse-dot 2s ease-in-out infinite;
}

.animate-spin-slow {
    animation: spin 8s linear infinite;
}

/* ── 4. GLOBAL FOCUS RING (WCAG 2.4.7) ── */
/* Acento de la herramienta activa vía tokens Expediente
   (light/dark lo resuelve expediente-tokens.css). */
*:focus-visible {
    outline: 2px solid var(--accent, #15803D);
    outline-offset: 2px;
}

*:focus:not(:focus-visible) {
    outline: none;
}

/* ── 5. REDUCED MOTION GUARD (WCAG 2.3.3 / 2.1 AA 2.3) ── */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration:       0.01ms !important;
        animation-iteration-count: 1     !important;
        transition-duration:      0.01ms !important;
    }
}

/* ── 6. CUSTOM SCROLLBAR ── */
::-webkit-scrollbar {
    width: 4px;
    height: 4px;
}
::-webkit-scrollbar-track {
    background: var(--bg);
}
::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, var(--ink) 15%, transparent);
}
::-webkit-scrollbar-thumb:hover {
    background: color-mix(in srgb, var(--ink) 30%, transparent);
}

/* ── 7. TOOL CARDS ── */
.tool-card {
    background: var(--surface);
    border: 1px solid var(--rule);
    transition: box-shadow 150ms ease, border-color 150ms ease, transform 150ms ease;
}

.tool-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 16px rgba(0,0,0,0.08);
    border-color: var(--accent, #15803D);
}

/* Arrow slide on card hover — targets .tool-card-arrow inside */
.tool-card .tool-card-arrow {
    display: inline-block;
    transition: transform 150ms ease;
}

.tool-card:hover .tool-card-arrow {
    transform: translateX(4px);
}

/* ── 8. LANDING ANIMATIONS (Ajuste 4 — 2026-05-24) ── */

/* === 8a. HERO REVEAL (stagger fade + slide-up) ===
   Fail-safe: elements start VISIBLE by default.
   JS adds .js-anim-ready to <html> to activate the hidden-initial state.
   Without JS, content is always visible. */

.html-js-ready .hero-reveal-item {
    opacity: 0;
    transform: translateY(12px);
}

@keyframes hero-fade-up {
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.hero-reveal-item.is-revealed {
    animation: hero-fade-up 450ms ease forwards;
}

/* === 8b. HEADLINE WIPE (clip from left to right) ===
   Chosen over decode/scramble: fully CSS-driven, always
   terminates in readable state, no intermediate garbage chars.
   Fail-safe: without .js-anim-ready class the text is visible. */

.html-js-ready .hero-headline-line {
    clip-path: inset(0 100% 0 0);
}

@keyframes wipe-reveal {
    to { clip-path: inset(0 0% 0 0); }
}

.hero-headline-line.is-revealed {
    animation: wipe-reveal 550ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

/* === 8c. STAT COUNT-UP (cosmetic only — JS drives the number) ===
   No specific CSS needed; stat spans already visible. */

/* === 8d. TOOL CARD HOVER micro-interaction — covered by section 7 above === */

/* === 8e. LANGUAGES GROUP — collapsible panel === */

/* Panel transition height: CSS handles the smooth open/close.
   JS sets max-height via scrollHeight so we don't hard-code a pixel value. */
.languages-modules-panel {
    max-height: 2000px; /* safe fallback without JS */
    transition: max-height 420ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* Languages chevron rotation */
.languages-chevron {
    transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* === 8f. MODULE DEPLOY STAGGER ANIMATION ===
   Fail-safe: .module-deploy-initial is added by JS only.
   Without JS, cards are fully visible at all times. */

@keyframes module-deploy {
    0% {
        opacity: 0;
        transform: translateY(16px);
        clip-path: inset(0 0 100% 0);
    }
    40% {
        clip-path: inset(0 0 0% 0);
    }
    100% {
        opacity: 1;
        transform: translateY(0);
        clip-path: inset(0 0 0% 0);
    }
}

.module-deploy-initial {
    opacity: 0;
    transform: translateY(16px);
}

.module-deploy-in {
    animation: module-deploy 480ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

/* ── 8g. REDUCED MOTION OVERRIDE (all landing effects) ── */
@media (prefers-reduced-motion: reduce) {
    .html-js-ready .hero-reveal-item,
    .html-js-ready .hero-headline-line {
        opacity: 1 !important;
        transform: none !important;
        clip-path: none !important;
        animation: none !important;
    }
    .tool-card:hover {
        transform: none !important;
    }
    .languages-modules-panel {
        transition: none !important;
    }
    .languages-chevron {
        transition: none !important;
    }
    .module-deploy-initial {
        opacity: 1 !important;
        transform: none !important;
    }
    .module-deploy-in {
        animation: none !important;
        opacity: 1 !important;
        transform: none !important;
    }
}

/* ── 9. HUB ANIMATIONS (Learning Hub — 2026-05-25) ── */

/* === 9a. REVEAL ESCALONADO (hub-reveal-item) ===
   El JS del Hub aplica opacity/transform inline en runtime (fail-safe).
   Las transiciones son inline también para poder variar delay por data-hub-delay.
   Este bloque solo añade el reduced-motion override a nivel CSS como seguro. */

@media (prefers-reduced-motion: reduce) {
    .hub-reveal-item {
        opacity: 1 !important;
        transform: none !important;
        transition: none !important;
    }
}

/* === 9b. HEATMAP — brillo sutil al hover de cada celda ===
   La celda es un <div> con title. Añadimos cursor pointer para UX.
   Solo en el contenedor: no sobreescribir colores de fondo ya definidos. */
.hub-heatmap-cell {
    transition: filter 120ms ease, opacity 120ms ease;
    cursor: default;
}

.hub-heatmap-cell:not([data-future]):hover {
    filter: brightness(1.25);
    opacity: 0.9;
}

/* ── 10. QUINIELA (Worldcup) — animaciones, retokenizado a Expediente (2026-07-18) ──
   Identidad = accent (bronce de Worldcup). Premio/tickets (familia dorada
   legacy) = warn. Selección/confirmación = success. Nada de hex de cancha
   ni de oro suelto: todo var(--token) o color-mix() sobre un token.
   Eliminado en este pase (huérfano, cero uso real): .confirm-bar-active/
   .confirm-btn-active + @keyframes cta-pulse (la barra sticky de v2 ya no
   existe, el flujo actual abre el modal directo al tocar una bandera),
   .phase-row-active (tabla vieja, reemplazada por el timeline en v3),
   .confetti-piece + @keyframes confetti-fall (sin disparador JS en el
   template — el confeti nunca llegó a conectarse), .pitch-stripes (clase
   suelta sin consumidores; el degradado del hero ya trae su propia
   textura), y el bloque de custom properties --pitch-*/--gold-*. */

/* === 10a. HERO — textura sutil de campo (neutra, sobre --ink) === */
.quiniela-hero-texture {
    background-image: repeating-linear-gradient(
        0deg,
        transparent,
        transparent 40px,
        color-mix(in srgb, var(--ink) 4%, transparent) 40px,
        color-mix(in srgb, var(--ink) 4%, transparent) 80px
    );
}

/* === 10b. PARTICULAS FLOTANTES EN HERO (color vía clase Tailwind en el span) === */
@keyframes float-particle {
    0%   { transform: translateY(0) translateX(0) scale(1);   opacity: 0.4; }
    33%  { transform: translateY(-18px) translateX(6px) scale(1.1); opacity: 0.7; }
    66%  { transform: translateY(-10px) translateX(-4px) scale(0.9); opacity: 0.5; }
    100% { transform: translateY(0) translateX(0) scale(1);   opacity: 0.4; }
}

.quiniela-particle {
    position: absolute;
    border-radius: 50%;
    pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
    .quiniela-particle { animation: float-particle 4s ease-in-out infinite; }
    .quiniela-particle-1 { animation-duration: 4.2s; animation-delay: 0s; }
    .quiniela-particle-2 { animation-duration: 5.8s; animation-delay: 1.1s; }
    .quiniela-particle-3 { animation-duration: 6.1s; animation-delay: 0.7s; }
    .quiniela-particle-4 { animation-duration: 3.9s; animation-delay: 2s; }
    .quiniela-particle-5 { animation-duration: 5s;   animation-delay: 0.4s; }
}

/* === 10c. TEAM CARD STAGGER (fade-in + slide-up) === */
@keyframes team-fade-in {
    from {
        opacity: 0;
        transform: translateY(8px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.team-card-initial {
    opacity: 0;
    transform: translateY(8px);
}

.team-card-in {
    animation: team-fade-in 280ms ease-out forwards;
    animation-delay: calc(var(--qi-index, 0) * 18ms);
}

/* === 10d. TEAM CARD — hover lift (neutral shadow, no colored glow) === */
.team-option {
    transition: transform 150ms ease, box-shadow 150ms ease, border-color 150ms ease, background-color 150ms ease;
    position: relative;
    overflow: hidden;
}

@media (prefers-reduced-motion: no-preference) {
    .team-option:hover {
        transform: translateY(-3px);
        box-shadow: 0 6px 16px rgba(0,0,0,0.10);
    }
}

/* Sheen diagonal al hover — highlight neutro (blanco), no es glassmorphism
   (no hay blur ni superposición translúcida de panel, es un sweep de luz). */
.team-option::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(
        110deg,
        transparent 30%,
        rgba(255,255,255,0.12) 50%,
        transparent 70%
    );
    transform: translateX(-100%);
    transition: transform 0ms;
    pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
    .team-option:hover::after {
        transform: translateX(100%);
        transition: transform 350ms ease;
    }
}

/* === 10e. RIPPLE (al seleccionar) — success, no accent: es un estado de
   confirmación, no de identidad (DESIGN_SYSTEM.md §2.3). === */
@keyframes ripple-expand {
    0% {
        transform: translate(-50%, -50%) scale(0);
        opacity: 0.5;
    }
    100% {
        transform: translate(-50%, -50%) scale(3.5);
        opacity: 0;
    }
}

.team-ripple {
    position: absolute;
    width: 60px;
    height: 60px;
    border-radius: 50%;
    background: radial-gradient(circle, color-mix(in srgb, var(--success) 45%, transparent) 0%, transparent 70%);
    pointer-events: none;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) scale(0);
}

@media (prefers-reduced-motion: no-preference) {
    .team-ripple.ripple-active {
        animation: ripple-expand 500ms ease-out forwards;
    }
}

/* === 10f. CHECK BADGE (success) === */
.team-check-badge {
    position: absolute;
    top: 6px;
    right: 6px;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--success);
    color: var(--surface);
    font-size: 11px;
    font-weight: 900;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 1px 4px rgba(0,0,0,0.15);
    opacity: 0;
    transform: scale(0.5);
    transition: opacity 150ms ease, transform 150ms ease;
}

.team-check-badge.badge-visible {
    opacity: 1;
    transform: scale(1);
}

/* Nombre de equipo: hasta 2 líneas, centrado, sin cortar con "…" */
.team-name {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    min-height: 2.2em;   /* reserva 2 líneas para alinear las tarjetas */
}

/* Tarjeta seleccionada: resaltado (borde + fondo + sombra) — success,
   estado de confirmación, no identidad de marca. */
.team-option.team-selected {
    border-color: var(--success);
    border-width: 2px;
    background-color: var(--success-tint);
    box-shadow: 0 6px 16px rgba(0,0,0,0.12);
    transform: translateY(-2px);
}
.team-option.team-selected .team-card-top-bar {
    background-color: var(--success);
}

/* === 10g. MODAL OVERLAY + PANEL ANIMATIONS (color-agnostic) === */
@keyframes modal-overlay-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@keyframes modal-overlay-out {
    from { opacity: 1; }
    to   { opacity: 0; }
}

@keyframes modal-panel-in {
    from {
        opacity: 0;
        transform: translateY(12px) scale(0.96);
    }
    to {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
}

@keyframes modal-panel-out {
    from {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
    to {
        opacity: 0;
        transform: translateY(8px) scale(0.97);
    }
}

.modal-overlay-enter {
    animation: modal-overlay-in 200ms ease-out forwards;
}

.modal-overlay-exit {
    animation: modal-overlay-out 150ms ease-in forwards;
}

.modal-panel-enter {
    animation: modal-panel-in 220ms cubic-bezier(0.16,1,0.3,1) forwards;
}

.modal-panel-exit {
    animation: modal-panel-out 150ms ease-in forwards;
}

/* === 10h. CARD CELEBRATORIA (estado prediction locked) — entrada, sin color === */
@keyframes trophy-entrance {
    0%   { opacity: 0; transform: scale(0.7) rotate(-8deg); }
    60%  { transform: scale(1.08) rotate(3deg); }
    80%  { transform: scale(0.97) rotate(-1deg); }
    100% { opacity: 1; transform: scale(1) rotate(0deg); }
}

@media (prefers-reduced-motion: no-preference) {
    .trophy-flag-anim {
        animation: trophy-entrance 500ms cubic-bezier(0.16,1,0.3,1) forwards;
    }
}

/* === 10i. TICKET BADGE — dorado (warn) + bronce (accent), shimmer ===
   "El premio/rifa es dorado" (brief): tickets se quedan en la familia warn
   con un toque de accent-deep (bronce Worldcup) para que se sienta propio
   de la herramienta, no un ámbar genérico. Texto siempre oscuro, derivado
   del propio warn vía color-mix (no depende de --ink, que se invierte
   entre temas — así el ticket stub es legible sobre el shimmer en ambos). */
@keyframes badge-shimmer {
    0%   { background-position: -200% center; }
    100% { background-position: 200% center; }
}

.ticket-badge-shimmer {
    background: linear-gradient(
        90deg,
        var(--warn) 0%, var(--accent-deep) 30%,
        color-mix(in srgb, var(--warn) 55%, white) 50%,
        var(--accent-deep) 70%, var(--warn) 100%
    );
    background-size: 200% auto;
    color: color-mix(in srgb, var(--warn) 25%, black);
    font-weight: 900;
    letter-spacing: 0.05em;
}

@media (prefers-reduced-motion: no-preference) {
    .ticket-badge-shimmer {
        animation: badge-shimmer 3s linear infinite;
    }
}

/* === 10j. VICTORY STATE (warn — familia dorada, "medalla") === */
@keyframes victory-pulse-border {
    0%, 100% {
        border-color: color-mix(in srgb, var(--warn) 50%, transparent);
        box-shadow: 0 0 0 0 transparent;
    }
    50% {
        border-color: var(--warn);
        box-shadow: 0 0 16px color-mix(in srgb, var(--warn) 35%, transparent);
    }
}

@media (prefers-reduced-motion: no-preference) {
    .victory-card {
        animation: victory-pulse-border 2.5s ease-in-out infinite;
    }
}

/* === 10k. PRIZE POOL HERO — shimmer bronce→dorado === */
@keyframes prize-shimmer {
    0%   { background-position: -300% center; }
    100% { background-position: 300% center; }
}

.prize-pool-amount {
    background: linear-gradient(
        90deg,
        var(--accent-deep) 0%,
        var(--warn) 25%,
        var(--accent) 50%,
        var(--warn) 75%,
        var(--accent-deep) 100%
    );
    background-size: 300% auto;
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}

@media (prefers-reduced-motion: no-preference) {
    .prize-pool-amount {
        animation: prize-shimmer 4s linear infinite;
    }
}

/* === 10l. PARTICIPATE STEPS — tarjetas de reglas === */
.participate-step {
    background: var(--surface);
    border: 1px solid var(--rule);
    border-radius: .5rem;
    transition: border-color 150ms ease, box-shadow 150ms ease;
}

.participate-step:hover {
    border-color: color-mix(in srgb, var(--accent) 50%, transparent);
    box-shadow: 0 4px 16px rgba(0,0,0,0.08);
}

/* === 10m. PHASE TIMELINE === */
/* Línea conectora horizontal (desktop) */
.phase-timeline-track {
    position: relative;
}

.phase-timeline-track::before {
    content: '';
    position: absolute;
    top: 22px;  /* centra con el nodo */
    left: 0;
    right: 0;
    height: 2px;
    background: linear-gradient(
        90deg,
        var(--rule) 0%,
        color-mix(in srgb, var(--warn) 45%, transparent) 50%,
        var(--rule) 100%
    );
    z-index: 0;
    pointer-events: none;
}

/* En mobile no mostramos la línea horizontal */
@media (max-width: 767px) {
    .phase-timeline-track::before { display: none; }
}

.phase-timeline-node {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}

/* Nodo activo: la fase EN CURSO usa warn (DESIGN_SYSTEM §2.1: "estado en
   curso, avisos"); fases pasadas usan success (Tailwind directo en el
   template); fases futuras quedan muted (Tailwind directo también). */
@keyframes node-pulse {
    0%, 100% { box-shadow: 0 0 0 0 transparent; }
    50%       { box-shadow: 0 0 0 5px color-mix(in srgb, var(--warn) 30%, transparent); }
}

.phase-timeline-node.node-active .node-dot {
    background: var(--warn);
    border-color: var(--warn);
}

@media (prefers-reduced-motion: no-preference) {
    .phase-timeline-node.node-active .node-dot {
        animation: node-pulse 2s ease-in-out infinite;
    }
}

/* Mobile: línea vertical conectora */
.phase-timeline-mobile-line {
    width: 2px;
    height: 28px;
    background: linear-gradient(to bottom, color-mix(in srgb, var(--warn) 45%, transparent), var(--rule));
    margin: 2px auto;
}

/* ── 10n. REDUCED MOTION OVERRIDE GLOBAL QUINIELA ── */
@media (prefers-reduced-motion: reduce) {
    .team-card-initial {
        opacity: 1 !important;
        transform: none !important;
    }
    .team-card-in {
        animation: none !important;
        opacity: 1 !important;
        transform: none !important;
    }
    .team-option:hover {
        transform: none !important;
    }
    .team-option::after {
        display: none !important;
    }
    .team-ripple.ripple-active {
        animation: none !important;
        display: none !important;
    }
    .team-check-badge {
        transition: none !important;
    }
    .modal-overlay-enter {
        animation: modal-overlay-in 100ms ease-out forwards !important;
    }
    .modal-overlay-exit {
        animation: modal-overlay-out 100ms ease-in forwards !important;
    }
    .modal-panel-enter {
        animation: none !important;
        opacity: 1 !important;
        transform: none !important;
    }
    .modal-panel-exit {
        animation: none !important;
        opacity: 0 !important;
    }
    .trophy-flag-anim {
        animation: none !important;
        opacity: 1 !important;
        transform: none !important;
    }
    .ticket-badge-shimmer {
        animation: none !important;
    }
    .victory-card {
        animation: none !important;
    }
    .quiniela-particle {
        animation: none !important;
    }
}
