/* ============================================================
   MODAL DE PRODUCTO — sólo el "chrome" de la ventana.

   El contenido de adentro lo estiliza assets/product-detail.css, el
   mismo componente que usa producto.html: acá está la ventana, no la
   ficha.

   **Vive en su propio archivo desde el prompt 32.** Estuvo en el
   <style> de index.html mientras el modal abría en una sola grilla de
   una sola página; ahora lo comparten index.html y catalogo.html, y
   copiarlo en el segundo <style> era garantizar que se desincronicen
   —es la regla de CLAUDE.md, "nunca volver a escribir chrome en un
   HTML"—.

   No va en base.css ni en product-detail.css: base.css lo cargan las
   cuatro páginas de tienda y product-detail.css también producto.html,
   y ninguna de las dos tiene modal. Es un componente propio, con su JS
   al lado (assets/product-modal.js).

   ORDEN DE CARGA: después de product-detail.css, que es lo que
   estiliza lo de adentro. Y después de aos.css, como los otros dos
   componentes.
   ============================================================ */

.pm-dialog {
    /* Imprescindible. El navegador centra un dialog modal con
       `inset: 0` + `margin: auto`, pero el reset `* { margin: 0 }`
       del <style> de la página le gana y lo deja pegado arriba a la
       izquierda. Además de verse mal, eso rompía el cierre por
       backdrop: con el modal en 0,0 no queda "afuera" arriba ni
       a la izquierda donde clickear. */
    margin: auto;
    border: none;
    padding: 0;
    background: var(--bg-alt);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    width: min(1100px, calc(100% - 48px));
    max-width: none;
    max-height: 90vh;
    overflow: hidden;
    box-shadow: 0 40px 120px -30px rgba(0,0,0,0.85);
}
.pm-dialog::backdrop { background: rgba(4,1,10,0.72); }
/* El alto y el overflow de .pm-body se declaran UNA sola vez, abajo,
   en el bloque del layout de tres columnas: desde el prompt 40 esto
   no scrollea. Acá queda sólo lo que sigue siendo del chrome. */
.pm-body { overscroll-behavior: contain; }

/* Mientras viaja la consulta de la ficha. El modal se abre
   enseguida —el clic tiene que tener respuesta inmediata— y el
   contenido llega después; sin esto, la ventana se abriría en
   blanco y se leería como un cuelgue.
   Reusa .grid-estado-spinner de assets/product-card.css: es el
   mismo spinner de las grillas y no hace falta un segundo.
   El mismo bloque muestra los dos casos que no son un producto:
   la consulta que falló y el slug que ya no existe. */
.pm-cargando {
    min-height: 320px; display: flex; flex-direction: column;
    align-items: center; justify-content: center; gap: 14px;
    padding: 60px 32px; text-align: center;
}
.pm-cargando p { font-size: 14px; font-weight: 300; color: var(--text-muted); max-width: 42ch; }
.pm-link { color: var(--accent); text-decoration: none; font-weight: 500; }
.pm-link:hover { text-decoration: underline; }

.pm-close {
    position: absolute; top: 12px; right: 12px; z-index: 3;
    width: 38px; height: 38px; display: flex; align-items: center; justify-content: center;
    background: rgba(255,255,255,0.06); border: 1px solid var(--border);
    border-radius: 50%; cursor: pointer; color: var(--text-secondary);
    font-family: inherit; transition: background .2s, color .2s, border-color .2s;
}
.pm-close:hover { background: rgba(255,255,255,0.12); color: var(--text); border-color: var(--accent); }
.pm-close:focus-visible { outline: 2px solid var(--accent-light); outline-offset: 2px; }
.pm-close svg { width: 17px; height: 17px; stroke: currentColor; }

/* ============================================================
   EL LAYOUT DE ADENTRO — tres columnas, alto fijo, sin scroll
   (prompt 40)

   Hasta acá el modal mostraba la ficha COMPLETA y scrolleaba:
   medido, .pm-body daba scrollHeight 1292-1333 contra 648 de
   alto útil a 1280x720 —o sea 685 px de más— y el botón
   "Agregar al carrito" caía en y=1196, a dos pantallas del clic
   que abrió la ventana. A 390 px eran 1241 px de sobra.

   Ahora la ventana es un grid de alto fijo y lo que entra lo
   decide PD.render(p, { compacto: true }), que devuelve tres
   bloques hermanos en vez de .gallery + .product-details. Lo que
   se cae está en producto.html, a un clic, y el pie de .pm-ficha
   lo enlaza.

   Se fueron dos reglas con esto:
     · el padding de .pm-body .product-layout — ya no hay
       .product-layout adentro del modal;
     · el `position: sticky` de .pm-body .gallery, que existía
       sólo para que la columna de la foto no se vaciara al
       scrollear. Sin scroll no tiene nada que resolver.
   ============================================================ */
.pm-body { max-height: none; overflow: hidden; }

.pm-grid {
    display: grid;
    grid-template-columns: 330px minmax(0, 1fr) 300px;
    /* El alto de la ventana lo fija el grid, no el contenido: es
       lo que hace que un perfume con tres listas de notas y otro
       con una midan lo mismo. */
    height: 470px;
    overflow: hidden;
}
/* Sin esto una fila de grid no baja de su min-content y el
   contenido largo estira la caja en vez de recortarse. */
.pm-grid > * { min-height: 0; }

.pm-foto {
    background: var(--surface);
    border-right: 1px solid var(--border-light);
    display: flex; align-items: center; justify-content: center;
    padding: 26px;
}
.pm-foto img { max-width: 100%; max-height: 100%; object-fit: contain; }
.pm-foto-vacia { font-size: 13px; color: var(--text-muted); opacity: .22; }

.pm-ficha {
    display: flex; flex-direction: column;
    padding: 34px 34px 28px;
    overflow: hidden;
}
/* Misma especificidad (0,2,0) que `.product-details .product-brand`
   de product-detail.css: si fuera menor, la ficha compacta se
   quedaría sin la marca en púrpura; si fuera mayor, habría que
   mantener dos reglas en competencia. */
.pm-ficha .product-brand {
    font-size: 11px; font-weight: 600; color: var(--accent);
    text-transform: uppercase; letter-spacing: 2px; margin-bottom: 8px;
}
/* Playfair y no Inter: es un título, no UI — el mismo criterio que
   los títulos de display de base.css. Las DOS páginas que cargan el
   modal ya piden Playfair con itálica en su <link>; producto.html no
   la pide, y no la necesita porque nunca usa `compacto`. */
.pm-ficha .product-name {
    font-family: 'Playfair Display', serif;
    font-size: 34px; font-weight: 400; line-height: 1.12;
    letter-spacing: -0.01em; margin-bottom: 8px;
    /* Dos líneas y no más. Cada línea son 38,1 px sobre un presupuesto
       de 377: medido, un nombre de tres líneas empujaba 52 px y lo que
       se recortaba era el PIE DE LA PIRÁMIDE, o sea texto cortado por
       la mitad. Es la misma razón del line-clamp de las notas — el alto
       fijo no perdona una línea de más—, aplicada al título. */
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.pm-ficha .product-name em { font-style: italic; color: var(--accent-bright); }
.pm-linea { font-size: 13px; color: var(--text-secondary); opacity: .78; margin-bottom: 14px; }

/* Las secciones de adentro pierden el margen grande de la ficha
   completa (32px): acá el alto es el recurso escaso. */
.pm-ficha .accords-section, .pm-ficha .notes-section { margin-bottom: 14px; }
.pm-ficha .notes-section { margin-bottom: 0; }
/* Dos filas de chip como tope (29 + 8 de gap + 29 = 66, medido). El
   `+N` ya avisa que la lista sigue, así que una tercera fila cuesta
   37 px del presupuesto para no decir nada nuevo. Cuando el título se
   come dos líneas, es esto lo que cede — y cede en el borde de una
   fila, no cortando el texto de la pirámide. */
.pm-ficha .accord-list { max-height: 66px; overflow: hidden; }
.pm-ficha h3 { font-size: 11px; letter-spacing: 1.4px; margin-bottom: 10px; }
/* El subtítulo va DENTRO del mismo h3 —es la misma frase— pero sin
   las mayúsculas ni el peso del rótulo, que es lo que lo vuelve
   una aclaración y no un segundo título. */
.pm-sub { font-weight: 400; text-transform: none; letter-spacing: 0; opacity: .6; }
.pm-accord-mas { opacity: .6; }

.pm-etapas { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.pm-etapa {
    padding: 12px 14px; border-radius: 12px;
    background: var(--surface); border: 1px solid var(--border-light);
    border-top: 2px solid var(--border);
}
/* Tres tonos del mismo púrpura, de más claro a más oscuro: la
   pirámide se lee como una secuencia y no como tres tarjetas. */
.pm-etapa--salida  { border-top-color: var(--accent-light); }
.pm-etapa--corazon { border-top-color: var(--accent); }
.pm-etapa--fondo   { border-top-color: #6d1a9c; }
.pm-etapa-icono { font-size: 14px; line-height: 1; margin-bottom: 6px; }
.pm-etapa-rotulo { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px; }
.pm-etapa-tiempo { font-size: 10px; opacity: .7; margin-bottom: 6px; }
.pm-etapa-notas {
    font-size: 12.5px; line-height: 1.45; color: var(--text-secondary); opacity: .85;
    /* El alto fijo no perdona una tercera línea. */
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* El cuerpo se come el espacio sobrante y RECORTA; el enlace es su
   hermano y mide lo suyo. Es lo que hace que el pie esté siempre a la
   vista sin depender del alto del contenido: con todo suelto en el
   mismo flex, un perfume con acordes largos lo empujaba afuera. */
.pm-ficha-cuerpo { flex: 1 1 auto; min-height: 0; overflow: hidden; }

.pm-verficha {
    flex: 0 0 auto; padding-top: 16px;
    display: flex; align-items: center; gap: 8px;
    font-size: 12.5px; color: var(--accent); text-decoration: none;
}
.pm-verficha:hover { text-decoration: underline; }
.pm-verficha:focus-visible { outline: 2px solid var(--accent-light); outline-offset: 3px; border-radius: 4px; }
/* Los dos textos conviven en el markup y el CSS elige por tramo: el
   largo no entra en la fila de 48 px de mobile. */
.pm-verficha-corto { display: none; }

.pm-compra {
    background: var(--surface);
    border-left: 1px solid var(--border-light);
    display: flex; flex-direction: column;
    padding: 34px 28px 28px;
}
.pm-compra .price-box {
    margin-bottom: 18px; padding-bottom: 18px;
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 10px;
}
.pm-compra .price-current { font-size: 34px; font-weight: 700; }
.pm-compra .price-old { margin-left: 0; }
/* El porcentaje lo calcula product-detail.js con la misma cuenta que
   el badge de la card. Nunca se guarda: sería un tercer número. */
.pm-dto {
    font-size: 12px; font-weight: 700; color: var(--accent-bright);
    padding: 3px 8px; border-radius: 100px;
    background: rgba(176,38,255,0.14); border: 1px solid rgba(176,38,255,0.3);
}
.pm-compra .stock-badge { align-self: flex-start; margin-bottom: 18px; }
.pm-compra .quantity-row { margin-bottom: 14px; }
/* La tira se apila en columna: en 300 px de ancho, las tres en fila
   entran cortadas. Y va al pie, con el auto. */
.pm-compra .trust-strip {
    flex-direction: column; align-items: flex-start; gap: 8px;
    margin-top: auto; padding-top: 18px;
}

/* Entrada y salida. `allow-discrete` + @starting-style es lo que
   permite animar un <dialog>, que pasa de display:none a block. */
.pm-dialog, .pm-dialog::backdrop {
    transition: opacity .28s ease, transform .28s cubic-bezier(.22,1,.36,1),
                overlay .28s allow-discrete, display .28s allow-discrete;
}
.pm-dialog { opacity: 0; transform: translateY(14px) scale(.985); }
.pm-dialog[open] { opacity: 1; transform: none; }
.pm-dialog::backdrop { opacity: 0; }
.pm-dialog[open]::backdrop { opacity: 1; }
@starting-style {
    .pm-dialog[open] { opacity: 0; transform: translateY(14px) scale(.985); }
    .pm-dialog[open]::backdrop { opacity: 0; }
}
/* ============================================================
   LA HOJA APILADA — 1060 px para abajo

   UN solo corte y dos layouts, y la razón es de aritmética, no de
   gusto: esta ficha necesita **470 px de alto con tres columnas** o
   **unos 750 apilada**. No hay una tercera forma en el medio.

   Las dos columnas laterales son fijas (330 + 300 = 630) y el diálogo
   es `min(1100px, 100% - 48px)`, así que cuando se achica lo único
   que cede es la del medio. Medido con tres columnas: la ficha quedaba
   en 220 px a 900, en 88 a 768 y en 68 a 620, con 74, 313 y 313 px de
   texto recortado.

   Se probó un layout intermedio de dos columnas con la compra de barra
   al pie, y no cierra: esa barra necesita ~880 px de contenido en un
   renglón y a 900 el diálogo deja 804, así que se parte en dos y le
   come el alto a la fila de arriba (44 px recortados a 900 y a 821).
   Achicar el precio no alcanza —el `flex-basis: 100%` de las cuotas NO
   fuerza el salto, porque el porcentaje queda indefinido al medir el
   contenido— y esconder el badge de stock es perder un dato de venta.
   (Las cuotas se fueron el 2026-10-02 y los ~880 px de la barra se
   midieron con ellas: si alguna vez se reabre el layout intermedio, hay
   que volver a medirla sin ellas.)

   Entonces: abajo de 1060, la misma hoja a pantalla completa que ya
   usaba el celular. Es lo que da el alto que la ficha apilada pide, y
   es la forma que ya tiene el proyecto para esto.
   ============================================================ */
@media (max-width: 1060px) {
    .pm-dialog {
        width: 100%; height: 100%; max-height: 100%;
        inset: 0; margin: 0; border-radius: 0; border: none;
    }
    .pm-body { height: 100dvh; }
    .pm-grid {
        grid-template-columns: 1fr;
        /* Tres filas y no cuatro: el enlace NO es hijo del grid, vive
           adentro de .pm-ficha. Lo que lo vuelve una banda propia es
           que .pm-ficha-cuerpo recorta y él mide 48 px fijos. */
        /* La foto son 252 px, pero NO fijos: en una pantalla corta se
           comen el presupuesto de la ficha y el texto termina cortado
           (medido en 360x640: 115 px recortados). `min(252px, 30dvh)`
           deja los 252 intactos de 840 px de alto para arriba —que es
           el caso de referencia, 390x844— y los va bajando en las
           pantallas cortas, con piso de 120. */
        grid-template-rows: max(120px, min(252px, 30dvh)) minmax(0, 1fr) auto;
        height: 100dvh;
    }
    .pm-foto {
        /* El alto lo pone la fila del grid, no el bloque: escrito acá
           en duro volvería a ser fijo y el clamp de arriba no serviría
           de nada. */
        box-sizing: border-box; height: auto; min-height: 0;
        border-right: none; border-bottom: 1px solid var(--border-light);
        padding: 22px;
    }
    .pm-ficha { padding: 22px 20px 0; overflow: hidden; }
    .pm-ficha .product-name { font-size: 26px; }
    .pm-linea { margin-bottom: 16px; }
    /* Las tres etapas van una por renglón y en UNA línea. Apiladas en
       tarjetas cuestan 223 px del presupuesto del cuerpo y ahí el texto
       de la última quedaba CORTADO POR LA MITAD: medido, 17 px de más
       en el caso suave y 80 en el peor (nombre de dos líneas + dos
       filas de acordes). En un renglón cuestan 117 y entra el peor
       caso con aire. El borde de color sigue separando las tres. */
    .pm-etapas { grid-template-columns: 1fr; gap: 6px; }
    .pm-etapa { display: flex; align-items: baseline; gap: 8px; padding: 7px 12px; }
    .pm-etapa-icono { display: none; }
    .pm-etapa-rotulo, .pm-etapa-tiempo { flex: 0 0 auto; margin-bottom: 0; }
    .pm-etapa-notas { flex: 1 1 auto; min-width: 0; -webkit-line-clamp: 1; }

    /* El enlace pasa a ser una FILA propia del grid, de 48 px: así no
       depende del alto del contenido de arriba, que es como se
       escondía en la primera versión. Por eso sale del flujo de
       .pm-ficha y pierde el `margin-top: auto`. */
    .pm-verficha {
        padding-top: 0; height: 48px; flex-shrink: 0;
        justify-content: space-between;
        /* A sangre: .pm-ficha tiene 20 px de padding lateral y la banda
           tiene que tocar los dos bordes, así que se los devuelve con
           margen negativo y se los repone como padding propio. */
        margin: 0 -20px; padding-left: 20px; padding-right: 20px;
        background: #150c24;
        border-top: 1px solid var(--border-light);
        border-bottom: 1px solid var(--border-light);
    }
    .pm-verficha-largo { display: none; }
    .pm-verficha-corto { display: inline; }

    /* La barra de compra baja al pie: precio arriba, en una línea, y
       cantidad + botón abajo. */
    .pm-compra {
        flex-direction: row; flex-wrap: wrap; align-items: center; gap: 12px;
        background: var(--bg); border-left: none;
        padding: 14px 20px 24px;
    }
    .pm-compra .price-box {
        flex-basis: 100%; margin-bottom: 0; padding-bottom: 0;
        gap: 0 8px; align-items: center;
    }
    .pm-compra .price-current { font-size: 24px; }
    .pm-compra .stock-badge { display: none; }
    .pm-compra .quantity-row { margin-bottom: 0; }
    /* "CANTIDAD" se saca de la VISTA, no del lector de pantalla: el
       <label for> sigue nombrando al input. En 390 px ese rótulo se
       comía 75 px y al botón le quedaban 121 para 118 de texto —medido,
       1,5 px de aire por lado, que se lee como un botón roto—. Un
       stepper de +/− con el número en el medio no necesita rótulo. */
    .pm-compra .quantity-row label {
        position: absolute; width: 1px; height: 1px;
        overflow: hidden; clip-path: inset(50%); white-space: nowrap;
    }
    .pm-compra .add-btn { flex: 1; padding-left: 12px; padding-right: 12px; }
    /* 52 px y no 40: es la altura mínima de un blanco táctil. */
    .pm-compra .qty-btn, .pm-compra .qty-input { height: 52px; }
    .pm-compra .add-btn { padding: 0; height: 52px; }
    /* No hay alto para esto en 390 px. */
    .pm-compra .trust-strip { display: none; }

    .pm-dialog { transform: none; }
    @starting-style { .pm-dialog[open] { transform: none; } }
}

/* ============================================================
   PANTALLAS CORTAS — 700 px de alto o menos

   Un teléfono viejo de 360x640 tiene 200 px menos de alto que el
   390x844 de referencia, y ahí la hoja recortaba 115 px de la ficha.
   La foto ya cede sola con el `min(252px, 30dvh)` de arriba; esto
   recupera el resto apretando los aires, que es lo único que queda
   cuando no hay alto: ningún dato se cae.
   ============================================================ */
@media (max-width: 1060px) and (max-height: 700px) {
    .pm-ficha { padding: 12px 20px 0; }
    .pm-ficha .product-name { font-size: 22px; }
    .pm-linea { margin-bottom: 8px; }
    .pm-ficha .accords-section { margin-bottom: 8px; }
    .pm-ficha h3 { margin-bottom: 6px; }
    .pm-etapas { gap: 4px; }
    .pm-etapa { padding: 5px 10px; }
    .pm-verficha { height: 42px; }
    .pm-compra { padding: 10px 20px 14px; gap: 8px; }
}
