/* Estilos universales (cargados asíncronos en todos los layouts). Reglas de elemento → @layer base; reglas de clase → @layer componentes. Tema único oscuro "Aura" teal: los fondos claros y los overrides [data-theme] desaparecen; todo hereda de los tokens de critical-css. */ @layer base { h3{max-width: 40ch;} /* Kramdown/Rouge envuelve cada `code` en línea con .language-plaintext .highlighter-rouge automáticamente — sin esta regla queda con el monospace por defecto del navegador, sin relación visual con el resto. */ code { font-family: var(--font-mono); font-size: 0.9em; background: rgba(13, 23, 21, 0.06); padding: 0.15em 0.4em; border-radius: 4px; } /* Enlaces del cuerpo en gris oscuro atenuado con subrayado: el acento se reserva para la conversión (botón sólido, enlace-flecha, datos). */ a { color: var(--color-text); text-decoration: underline; text-decoration-thickness: 1.5px; text-underline-offset: 0.2em; text-decoration-color: rgba(13, 23, 21, 0.25); } a:hover { color: var(--color-accent); text-decoration-color: currentColor; } h5 { font-family: var(--font-mono); font-size: 0.72rem; color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.3em; font-weight: 500; } ul li { margin: 0.5em 0; list-style: none; } ol li::marker { color: var(--color-accent); font-family: var(--font-headings); font-weight: 400; font-size: 2em; line-height: 1; } /* Tablas como índice editorial: filas con hairline, encabezado mono */ table { width: 100%; margin: 2em 0 4em; } table tr { border-bottom: 1px solid var(--color-border); display: flex; padding: 1.2em 0; flex-wrap: wrap; gap: 1em; width: 100%; transition: background-color 0.3s ease, padding-left 0.3s ease; } table tr:hover { background-color: rgba(13, 23, 21, 0.025); } table th { font-family: var(--font-mono); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.2em; color: var(--color-text-muted); } /* Entrada escalonada de filas (receta 4B.2): cada fila de tabla aparece un poco después que la anterior al entrar en pantalla. tbody tr, no thead: la cabecera siempre visible. */ @keyframes tr-pop { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } } @supports (animation-timeline: view()) { @media (prefers-reduced-motion: no-preference) { tbody tr { animation: tr-pop linear both; animation-timeline: view(); animation-range: entry 0% cover 20%; } tbody tr:nth-child(2) { animation-range: entry 4% cover 24%; } tbody tr:nth-child(3) { animation-range: entry 8% cover 28%; } tbody tr:nth-child(4) { animation-range: entry 12% cover 32%; } tbody tr:nth-child(5) { animation-range: entry 16% cover 36%; } tbody tr:nth-child(6) { animation-range: entry 20% cover 40%; } } } /* min(200px, 100%) + min-width: 0 → sin desborde a 390/320 px */ table td, table th { flex: 1 1 min(200px, 100%); min-width: 0; overflow-wrap: anywhere; padding: .5em; font-size: 1rem; } /* Formulario: tarjeta de cristal con brillo teal, inputs translúcidos */ form { background: var(--color-bg-surface); border: 1px solid var(--color-border); color: var(--color-text); font-weight: 500; border-radius: var(--radius-large); box-shadow: var(--shadow-default), var(--glow-accent-soft); padding: clamp(2rem, 5vw, 5rem) clamp(1.5rem, 4vw, 3rem); display: grid; gap: 1em; position: relative; overflow: hidden; } form::before { content: ''; position: absolute; width: 300px; height: 300px; top: -120px; right: -120px; border-radius: 50%; background: var(--color-accent); opacity: 0.05; filter: blur(100px); pointer-events: none; } form input, form textarea { border-radius: var(--radius-default); min-height: 40px; margin-bottom: 1em; padding: 1em; border: 1px solid rgba(13, 23, 21, 0.16); background: rgba(13, 23, 21, 0.03); color: var(--color-text-dark); transition: border-color 0.3s ease, box-shadow 0.3s ease; } form input::placeholder, form textarea::placeholder { color: var(--color-text-muted); } form input:not(input[type="checkbox"]) { width: min(100%, 480px); } form textarea { width: min(100%, 800px); resize: vertical; } form input:focus, form textarea:focus { outline: none; border-color: var(--color-accent); box-shadow: 0 0 0 3px rgba(0, 212, 196, 0.15); } blockquote { background-color: rgba(13, 23, 21, 0.03); border: 1px solid var(--color-border); border-left: 2px solid var(--color-accent); margin: 2rem 0; padding: 2rem; position: relative; overflow: hidden; border-radius: 0 var(--radius-default) var(--radius-default) 0; } blockquote p { font-family: var(--font-body); font-size: clamp(1.2rem, 2vw, 1.5rem); line-height: 1.6; color: var(--color-text); margin: 0; position: relative; z-index: 1; } blockquote::before { content: '"'; font-family: var(--font-headings); font-size: 6rem; color: var(--color-accent); position: absolute; top: -1.4rem; left: 1rem; opacity: 0.15; } blockquote cite { display: block; font-family: var(--font-mono); font-size: 0.8rem; font-style: normal; color: var(--color-secondary-text); margin-top: 1rem; text-align: right; letter-spacing: 0.05em; } blockquote cite::before { content: '— '; } @media (max-width: 768px) { blockquote { padding: 1.5rem; } blockquote::before { font-size: 4rem; } } /* Elementos tipográficos básicos */ p, li { font-size: clamp(1rem, 0.84rem + 0.8vw, 1.25rem); max-width: 70ch; margin-bottom: 1rem; } small { font-size: max(0.875rem, 90%); display: inline-block; } img { border-style: none; max-width: 100%; height: auto; position: relative; z-index: 2; } hr { border: 0; height: 1px; background: linear-gradient(to right, transparent, rgba(13, 23, 21, 0.2), transparent); margin: 2rem 0; } /* Tipografía adicional */ h3 { font-size: clamp(1.75rem, 3vw + 0.5rem, 2.5rem); color: var(--color-secondary-text); } h4, h3.h4 { font-size: clamp(1.25rem, 2.5vw + 0.5rem, 1.875rem); color: var(--color-primary); } /* h3 con aspecto de h4: mantiene la jerarquía h2 → h3 sin cambiar el diseño */ h3.h4 { max-width: none; } /* Accesibilidad */ :focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; } @media (max-width: 600px) { table td, table th { flex: 1 0 100%; } } } @layer componentes { /* Botón flotante para agendar: píldora teal con texto oscuro y brillo */ .agendar-flotante { position: fixed; right: clamp(12px, 3vw, 20px); bottom: clamp(12px, 3vw, 20px); z-index: 900; min-height: 44px; box-sizing: border-box; display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.75rem 1.1rem; border-radius: var(--radius-pill); background: var(--color-accent); color: var(--color-bg-base); font-weight: 700; font-size: 0.95rem; line-height: 1; text-decoration: none; box-shadow: 0 8px 32px rgba(0, 212, 196, 0.3); transition: transform 0.2s ease, background-color 0.2s ease, opacity 0.2s ease, box-shadow 0.2s ease; } .agendar-flotante:hover, .agendar-flotante:focus-visible { background: var(--color-secondary); color: var(--color-bg-base); transform: translateY(-2px); box-shadow: 0 12px 40px rgba(0, 212, 196, 0.45); } .agendar-flotante svg { flex-shrink: 0; } /* Oculto mientras el hero ([data-hero]) está en pantalla (js/app.js): no duplica el CTA del hero ni tapa la foto en móvil. */ .agendar-flotante.es-oculto { opacity: 0; transform: translateY(1rem); pointer-events: none; } .boton:hover .arrow { transform: translateX(4px); } /* Botón secundario: variante ghost del lenguaje Aura (contorno hairline) */ .boton-color-secondary { max-width: max-content; display: inline-flex; align-items: center; padding: clamp(0.875rem, 2.5vw, 1rem) clamp(1.25rem, 3.5vw, 1.75rem); transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); font-size: clamp(1rem, 2.2vw, 1.125rem); font-weight: 600; color: var(--color-text-dark); text-decoration: none; border: 1px solid var(--color-border); border-radius: var(--radius-pill); background: transparent; cursor: pointer; position: relative; } .boton-color-secondary:hover { color: var(--color-accent); border-color: rgba(0, 212, 196, 0.5); background: rgba(0, 212, 196, 0.06); transform: translateY(-2px); box-shadow: var(--glow-accent-soft); } .boton-color-secondary:hover .arrow-color-secondary { transform: translateX(6px); color: var(--color-accent); } .boton-color-secondary:active { transform: translateY(0px); transition: transform 0.1s ease; } .arrow-color-secondary { margin-left: clamp(6px, 1.5vw, 10px); transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55); display: inline-flex; align-items: center; color: var(--color-accent); } .arrow-color-secondary::after { content: "→"; font-size: 1.1em; font-weight: 700; } /* Estilos para cuando los botones están juntos */ .boton + .boton-color-secondary { margin-left: 12px; } @keyframes scroll-down-line { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(10px); } } @keyframes scroll-down-arrow { 0%, 100% { transform: translateX(-50%) translateY(0) rotate(45deg); } 50% { transform: translateX(-50%) translateY(10px) rotate(45deg); } } .breadcrumbs { padding: 1rem 0; font-family: var(--font-mono); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.12em; } .breadcrumbs ol { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; } .breadcrumbs li { display: inline; margin: 0; } .breadcrumbs li:not(:last-child):after { content: "/"; margin: 0 0.5rem; color: var(--color-text-muted); } .breadcrumbs a { color: var(--color-text-muted); text-decoration: none; } .breadcrumbs a:hover { text-decoration: underline; color: var(--color-accent); } .arrow { margin-left: 10px; transition: transform 0.3s ease; } .arrow::after { content: "→"; font-size: 20px; } .animated-line { display: inline-block; width: 2px; background-color: var(--color-accent); height: 100%; transform: scaleY(0); transition: transform 1s ease-out; } .animated-line.visible { transform: scaleY(1); } /* Marco de altura fija para la línea animada de los héroes */ .linea-marco--alta { height: 496px; } .scroll-arrow { width: 2px; height: 60px; margin: 20px auto; position: relative; overflow: visible; cursor: pointer; } .scroll-arrow::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(13, 23, 21, 0.4); animation: scroll-down-line 2s ease-in-out infinite; } .scroll-arrow::after { content: ''; position: absolute; bottom: -10px; left: 50%; width: 10px; height: 10px; border-right: 2px solid rgba(13, 23, 21, 0.4); border-bottom: 2px solid rgba(13, 23, 21, 0.4); transform: translateX(-50%) rotate(45deg); animation: scroll-down-arrow 2s ease-in-out infinite; } .datos { padding: 6em 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1.25rem; align-items: start; article { text-align: left; background: var(--color-bg-surface); border: 1px solid var(--color-border); border-radius: var(--radius-large); padding: 1.75em 1.5em; display: flex; flex-direction: column; gap: 0.6rem; font-size: 0.9rem; line-height: 1.55; h4, .h4 { margin: 0; font-size: 1rem; } small { font-size: 0.8rem; } ul { flex: 1; margin: 0.4rem 0; } li { margin: 0.7em 0; font-size: 0.8rem; line-height: 1.45; } .boton, .boton-color-secondary { margin-top: auto; align-self: stretch; text-align: center; justify-content: center; } } } /* Tarjeta destacada dentro de un grid de .datos (borde de acento arriba) */ .plan-destacado { border-color: rgba(0, 212, 196, 0.4); border-top: 4px solid var(--color-accent); background-color: var(--color-bg-surface); padding: 2em; transform: scale(1.05); } .beneficios { display: grid; gap: 2em; } .beneficios .header_dos_columnas { display: flex; flex-wrap: wrap; gap: 2em; align-items: center; } .beneficios .header_dos_columnas img { flex: 1 1 min(120px, 100%); max-width: 100%; height: auto; position: relative; z-index: 2; } .beneficios .header_dos_columnas h2 { flex: 1 1 min(280px, 100%); max-width: 100%; border-right: 1px solid var(--color-border); padding: 1.5em 1.5em 1.5em 0; margin: 0; @media (max-width: 600px) { border-right: none; border-bottom: 1px solid var(--color-border); padding: 0 0 1em; } } .beneficios .header_dos_columnas p { flex: 0 0 auto; writing-mode: vertical-rl; text-orientation: mixed; margin: 0; font-family: var(--font-mono); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.3em; color: var(--color-text-muted); } .beneficios .puntos_beneficios { display: grid; gap: 2em; width: min(100%, max-content); place-self: end; border-left: 1px solid var(--color-border); padding-left: 4em; small{place-self: end;} } .beneficios .puntos_beneficios li { padding-block: var(--space-md); font-size: 1.5rem; border-bottom: 1px solid var(--color-border); transition: color 0.3s ease; } .beneficios .puntos_beneficios li:last-child { border-bottom: none; } .beneficios .puntos_beneficios li:hover { color: var(--color-accent); } .beneficios .puntos_beneficios a { justify-self: flex-end; } .dos_lados { display: flex; flex-wrap: wrap; align-items: center; padding-bottom: 6em; gap: 1em; img { max-width: min(400px, 100%); border-radius: var(--radius-large); border: 1px solid var(--color-border); box-shadow: var(--shadow-default); object-fit: cover; position: relative; z-index: 2; } .dos_lados_copy { flex: 1 1 min(320px, 100%); display: grid; margin-left: 12px; span{margin-bottom: 0;} } } .dos_lados .dos_lados_copy small, .dos_lados .dos_lados_copy h2 { margin-bottom: 1em; } .dos_lados .dos_lados_copy > small { font-family: var(--font-mono); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.3em; color: var(--color-text-muted); } .servicios { display: grid; grid-template-columns: 1fr auto; gap: 16px; justify-content: space-between; } /* Autodiagnóstico de encaje (jurado-animaciones, firma de la home): casillas reales dentro de la tabla, conteo anunciado por <output> (js/app.js) y un enlace secundario a la agenda (home-fit) para no competir con el botón sólido. */ .encaje { display: flex; gap: .6em; align-items: flex-start; cursor: pointer; } .encaje input { flex: none; inline-size: 1.25em; block-size: 1.25em; margin-block-start: .15em; accent-color: var(--color-accent); cursor: pointer; } .encaje:has(input:checked) { color: var(--color-text-dark); } .encaje-resultado { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 1em; align-items: center; justify-content: space-between; margin-block-start: -2em; } .encaje-resultado output { font-family: var(--font-mono); font-size: .85rem; color: var(--color-text-muted); } .servicios:has(.encaje input:checked) .encaje-resultado output { color: var(--color-secondary-text); } .servicios .dos_lados_copy { padding-left: 20px; border-left: 1px solid var(--color-border); flex: 1 1 min(320px, 100%); place-items: start; margin-bottom: 2em; } .servicios .dos_lados_copy li { margin: 0; list-style: none; } .servicios .dos_lados_copy li .servicios_icon { font-size: 20px; color: var(--color-accent); font-weight: 900; } .servicios .dos_lados_copy #lead_whatsapp { place-self: end; } .casos-uso { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; margin: 32px 0; } .caso__icon { font-size: 2.5rem; display: block; margin-bottom: 32px; } /* Cifra destacada en tarjetas: antes era un <h3 aria-hidden>, que rompía el orden de encabezados */ .caso__cifra, .caso p.caso__cifra { font-size: 2.5rem; font-family: var(--font-headings); font-weight: 400; line-height: var(--line-height-tight); color: var(--color-accent); } .caso p { color: var(--color-text); margin-bottom: 32px; font-size: 1rem; } /* Responsive adjustments */ @media (max-width: 768px) { .casos-uso, .servicios { grid-template-columns: 1fr; } } /* Footer: estructura nueva (CTA gigante en _includes/css/aura.css); aquí el cuerpo de texto y el pie mono. */ .footer { display: grid; gap: 2em; place-items: center; text-align: center; padding: 0 0 3em; border-top: 1px solid var(--color-border); box-shadow: 0 0 0 100vmax var(--color-bg-base); clip-path: inset(0 -100vmax); background: var(--color-bg-base); } .footer-texto { max-width: 68ch; color: var(--color-text); font-size: 0.95rem; line-height: 1.8; } .footer div { border-bottom: 1px solid var(--color-border); } .footer .firma { border-bottom: none; max-width: 200px; } .footer-pie { font-family: var(--font-mono); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.2em; color: var(--color-text-muted); display: flex; flex-wrap: wrap; gap: 0.5em; justify-content: center; align-items: center; } /* Variantes de .wrapper para el cierre de página (sustituyen style=) */ .wrapper--abierto { padding-bottom: 4em; } /* Borde con gradiente animado (receta 4B.4, interactividad-wow-seo): un único uso por página, reservado al CTA de cierre — no es decoración repetible, es la firma visual de "aquí se cierra la venta". */ @property --m-angle { syntax: '<angle>'; initial-value: 0deg; inherits: false; } @keyframes m-spin { to { --m-angle: 360deg; } } .m-border { position: relative; isolation: isolate; border-radius: var(--radius-large); } .m-border::before { content: ""; position: absolute; inset: -1px; z-index: -1; border-radius: inherit; background: conic-gradient(from var(--m-angle), var(--color-accent), var(--color-secondary), rgba(0, 212, 196, 0.2), var(--color-accent)); } .m-border::after { content: ""; position: absolute; inset: 1px; z-index: -1; border-radius: inherit; background: var(--color-bg-surface); } @media (prefers-reduced-motion: no-preference) { .m-border::before { animation: m-spin 6s linear infinite; } } /* CTA de cierre (patrón Cta 4 de 21st.dev): acción a la izquierda —avatar, frase y el único botón sólido— y a la derecha lo que incluye el diagnóstico como lista con check. En móvil se apila. */ .cta-cierre { display: grid; gap: var(--space-xl); align-items: center; padding: var(--space-xl); @media (min-width: 760px) { grid-template-columns: 3fr 2fr; } } .cta-cierre__accion { display: grid; gap: var(--space-md); justify-items: start; p { margin: 0; font-size: 1.15rem; } } .cta-cierre__avatar { width: 56px; height: 56px; border-radius: 50%; object-fit: cover; object-position: 50% 10%; border: 1px solid var(--color-border); } .cta-cierre__incluye { display: grid; gap: var(--space-sm); border-top: 1px solid var(--color-border); padding-top: var(--space-lg); @media (min-width: 760px) { border-top: none; border-left: 1px solid var(--color-border); padding: 0 0 0 var(--space-xl); } p { margin: 0; font-family: var(--font-mono); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.2em; color: var(--color-text-muted); } ul { display: grid; gap: var(--space-sm); margin: 0; padding: 0; list-style: none; } li { display: flex; gap: 0.75em; align-items: baseline; } li::before { content: ""; flex: none; width: 0.35em; height: 0.7em; border: solid var(--color-secondary); border-width: 0 2px 2px 0; rotate: 45deg; translate: 0 -0.15em; } } .wrapper--amplio { padding-bottom: 6em; } .wrapper--separado { margin-top: 4rem; } .resaltar { background: linear-gradient( 120deg, rgba(0, 212, 196, 0.16) 0%, rgba(0, 212, 196, 0.16) 100% ); background-repeat: no-repeat; background-size: 100% 40%; background-position: 0 90%; } /* Resaltado pleno (fondo completo), no solo la franja inferior */ .resaltar--pleno { background: rgba(0, 212, 196, 0.14); padding: 0.2em 0.4em; border-radius: 4px; } /* Cajas de contenido con fondo neutro o de marca (sustituyen style=) */ .panel { padding: 1.5em; } .panel--neutro { background-color: rgba(13, 23, 21, 0.03); border: 1px solid var(--color-border); border-radius: var(--radius-default); margin-bottom: 1em; } .panel--marca { background-color: var(--color-accent-light); border-left: 2px solid var(--color-accent); border-radius: 0 var(--radius-default) var(--radius-default) 0; } /* Banda de sección a todo el ancho: superficie elevada + hairlines */ .fondo { background-color: var(--color-bg-surface); box-shadow: 0 0 0 100vmax var(--color-bg-surface); clip-path: inset(0 -100vmax); border-top: 1px solid var(--color-border); border-bottom: 1px solid var(--color-border); padding: var(--space-seccion) 0; position: relative; z-index: 1; } } /* Componentes del lenguaje visual "Aura" (modelo _plans/aura) portados a la arquitectura Jekyll: marquee de clientes, manifesto palabra a palabra, cifras con count-up, cursor personalizado, CTA gigante del footer, índice editorial tipo WorksList y tarjetas Showcase. Se carga asíncrono desde css/style-default.css. */ @layer componentes { /* ====== Marquee infinito de clientes (modelo Brands.svelte) ====== Pista duplicada (x2) que se desplaza -50% en bucle; el contenido ES/EN son los nombres públicos de _data/casos.yml. aria-hidden: decorativo. */ .marquee { padding: var(--space-lg) 0; border-block: 1px solid var(--color-border); box-shadow: 0 0 0 100vmax var(--color-bg-base); clip-path: inset(0 -100vmax); background: var(--color-bg-base); overflow: hidden; position: relative; display: grid; gap: var(--space-md); justify-items: center; } .marquee-pista { display: flex; width: max-content; gap: var(--space-2xl); padding-inline: var(--space-2xl); } @media (prefers-reduced-motion: no-preference) { .marquee-pista { animation: marquee 32s linear infinite; } .marquee:hover .marquee-pista { animation-play-state: paused; } } @keyframes marquee { to { transform: translateX(-50%); } } .marquee-cliente { font-family: var(--font-headings); font-size: clamp(1.4rem, 3vw, 2.2rem); color: rgba(13, 23, 21, 0.3); white-space: nowrap; transition: color 0.3s ease; } .marquee:hover .marquee-cliente { color: rgba(13, 23, 21, 0.55); } /* ====== Manifesto (modelo Manifesto.svelte) ====== Nivel 1 (CSS puro, sin JS): cada .palabra se enciende de opacidad al cruzar su franja del scroll-timeline nativo, escalonada por :nth-child (mismo patrón que .m-stagger, ver skill interactividad-wow-seo). Sin soporte de animation-timeline, o con reduced-motion, el párrafo se ve completo desde el principio: no depende de JS. */ .manifesto { font-family: var(--font-headings); font-size: clamp(1.6rem, 3.6vw, 2.9rem); line-height: 1.35; letter-spacing: -0.01em; color: var(--color-text-dark); max-width: 24ch; } @keyframes manifesto-palabra { from { opacity: 0.12; } to { opacity: 1; } } @supports (animation-timeline: view()) { @media (prefers-reduced-motion: no-preference) { .manifesto .palabra { animation: manifesto-palabra linear both; animation-timeline: view(); animation-range: entry 0% cover 35%; } /* Escalonado puro CSS (sin --i por style=, la regla del proyecto es cero atributos style= incluso con variables): una franja de scroll-timeline por posición, hasta 30 palabras. Reglas escritas a mano, no generadas con una plantilla: auditoria.py excluye del escaneo de clases cualquier CSS con sintaxis de plantilla (mismo motivo que excluye css/style-default.css, que solo ensambla includes). */ .manifesto .palabra:nth-child(1) { animation-range: entry 0% cover 35%; } .manifesto .palabra:nth-child(2) { animation-range: entry 1.5% cover 36.5%; } .manifesto .palabra:nth-child(3) { animation-range: entry 3% cover 38%; } .manifesto .palabra:nth-child(4) { animation-range: entry 4.5% cover 39.5%; } .manifesto .palabra:nth-child(5) { animation-range: entry 6% cover 41%; } .manifesto .palabra:nth-child(6) { animation-range: entry 7.5% cover 42.5%; } .manifesto .palabra:nth-child(7) { animation-range: entry 9% cover 44%; } .manifesto .palabra:nth-child(8) { animation-range: entry 10.5% cover 45.5%; } .manifesto .palabra:nth-child(9) { animation-range: entry 12% cover 47%; } .manifesto .palabra:nth-child(10) { animation-range: entry 13.5% cover 48.5%; } .manifesto .palabra:nth-child(11) { animation-range: entry 15% cover 50%; } .manifesto .palabra:nth-child(12) { animation-range: entry 16.5% cover 51.5%; } .manifesto .palabra:nth-child(13) { animation-range: entry 18% cover 53%; } .manifesto .palabra:nth-child(14) { animation-range: entry 19.5% cover 54.5%; } .manifesto .palabra:nth-child(15) { animation-range: entry 21% cover 56%; } .manifesto .palabra:nth-child(16) { animation-range: entry 22.5% cover 57.5%; } .manifesto .palabra:nth-child(17) { animation-range: entry 24% cover 59%; } .manifesto .palabra:nth-child(18) { animation-range: entry 25.5% cover 60.5%; } .manifesto .palabra:nth-child(19) { animation-range: entry 27% cover 62%; } .manifesto .palabra:nth-child(20) { animation-range: entry 28.5% cover 63.5%; } .manifesto .palabra:nth-child(21) { animation-range: entry 30% cover 65%; } .manifesto .palabra:nth-child(22) { animation-range: entry 31.5% cover 66.5%; } .manifesto .palabra:nth-child(23) { animation-range: entry 33% cover 68%; } .manifesto .palabra:nth-child(24) { animation-range: entry 34.5% cover 69.5%; } .manifesto .palabra:nth-child(25) { animation-range: entry 36% cover 71%; } .manifesto .palabra:nth-child(26) { animation-range: entry 37.5% cover 72.5%; } .manifesto .palabra:nth-child(27) { animation-range: entry 39% cover 74%; } .manifesto .palabra:nth-child(28) { animation-range: entry 40.5% cover 75.5%; } .manifesto .palabra:nth-child(29) { animation-range: entry 42% cover 77%; } .manifesto .palabra:nth-child(30) { animation-range: entry 43.5% cover 78.5%; } } } /* ====== Cifras con count-up (modelo Stats.svelte) ====== El número vive dentro del texto existente; js/app.js lo anima de 0 al valor final preservando el formato original (1.000 / 1,000 / +). Fila plana con divisor, sin tarjeta: el modelo Stats.svelte no encierra las cifras en cajas, solo las separa en columnas. */ .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--space-xl) var(--space-lg); list-style: none; padding: 0; counter-reset: stat; } /* Bento: la primera cifra (la de más peso narrativo, los años en el negocio) ocupa una celda grande a la izquierda; las otras tres se apilan a la derecha. Solo a partir de 640px — en móvil se queda en columna simple, ya legible sin jerarquía extra. */ @media (min-width: 640px) { .stats-grid { grid-template-columns: 1.3fr 1fr; grid-template-rows: repeat(3, auto); } .stats-grid li:first-child { grid-column: 1; grid-row: 1 / span 3; display: flex; flex-direction: column; justify-content: center; border-left-width: 2px; border-color: var(--color-accent); } .stats-grid li:first-child .stat-cifra { font-size: clamp(3rem, 6vw, 4.5rem); } } /* Entrada escalonada (receta 4B.2): cada cifra aparece un poco después que la anterior al entrar en pantalla. Nunca en el hero; esta fila ya está varias pantallas más abajo. */ @keyframes stats-pop { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: none; } } @supports (animation-timeline: view()) { @media (prefers-reduced-motion: no-preference) { .stats-grid li { animation: stats-pop linear both; animation-timeline: view(); animation-range: entry 0% cover 25%; } .stats-grid li:nth-child(2) { animation-range: entry 6% cover 31%; } .stats-grid li:nth-child(3) { animation-range: entry 12% cover 37%; } .stats-grid li:nth-child(4) { animation-range: entry 18% cover 43%; } } } .stats-grid li { counter-increment: stat; margin: 0; padding-left: var(--space-md); border-left: 1px solid var(--color-border); font-size: 0.95rem; color: var(--color-text); } .stats-grid li::before { content: "0" counter(stat); display: block; font-family: var(--font-mono); font-size: 0.7rem; letter-spacing: 0.25em; color: var(--color-text-muted); margin-bottom: 0.6em; } .stats-grid .stat-cifra { font-family: var(--font-headings); font-size: clamp(2rem, 4vw, 3rem); line-height: 1; color: var(--color-accent); display: inline-block; margin-right: 0.15em; font-variant-numeric: tabular-nums; } /* Cuando la cifra enlaza a su caso real (stat.url en datos.yml): sin subrayado permanente sobre un número grande, afordancia solo al hover. */ a.stat-cifra { text-decoration: none; } a.stat-cifra:hover { text-decoration: underline; text-decoration-color: currentColor; } /* ====== Cursor personalizado (modelo Cursor.svelte) ====== Anillo que sigue al puntero con lerp y crece sobre interactivos. Solo con puntero fino, con JS y sin reduced-motion; el cursor nativo se mantiene visible (adaptación sutil, no lo sustituye). */ .cursor-ring { position: fixed; top: 0; left: 0; z-index: 999; width: 28px; height: 28px; border-radius: 50%; border: 1.5px solid rgba(13, 23, 21, 0.4); background: rgba(13, 23, 21, 0.04); pointer-events: none; transform: translate(-50%, -50%) scale(1); transition: transform 0.25s ease, opacity 0.25s ease; opacity: 0; will-change: transform; } .cursor-ring.visible { opacity: 1; } .cursor-ring.crecido { transform: translate(-50%, -50%) scale(2.4); border-color: rgba(0, 212, 196, 0.6); background: rgba(0, 212, 196, 0.08); } @media (hover: none), (prefers-reduced-motion: reduce) { .cursor-ring { display: none; } } /* ====== Footer con CTA gigante (modelo Footer.svelte) ====== El wordmark de marca en serif gigante, color sólido, y botón circular cuyo disco teal escala en hover. */ .footer-cta { text-align: center; display: grid; justify-items: center; gap: var(--space-xl); padding: var(--space-seccion) 0 var(--space-2xl); position: relative; overflow: hidden; } .footer-cta::before { content: ''; position: absolute; bottom: -180px; left: 50%; transform: translateX(-50%); width: 640px; height: 320px; border-radius: 50%; background: var(--color-accent); opacity: 0.05; filter: blur(200px); pointer-events: none; } .footer-cta .footer-wordmark { font-size: clamp(3rem, 11vw, 10rem); line-height: 0.95; margin: 0; max-width: none; display: block; color: var(--color-text-dark); } /* Se aplica junto a .boton (ver boton.html): max-width y box-shadow se reinician porque .boton los fija en modo píldora (max-content, glow blanco) y aquí el botón es un círculo fijo sin brillo propio. */ .footer-circulo { position: relative; max-width: none; width: clamp(140px, 20vw, 176px); height: clamp(140px, 20vw, 176px); display: grid; place-items: center; text-align: center; border-radius: 50%; background: transparent; box-shadow: none; color: var(--color-text-dark); text-decoration: none; font-weight: 600; font-size: 0.95rem; line-height: 1.3; isolation: isolate; transition: color 0.35s ease; padding: 1em; } .footer-circulo:hover { box-shadow: none; transform: none; } .footer-circulo::before { content: ''; position: absolute; inset: 0; border-radius: 50%; background: var(--color-accent); z-index: -1; transform: scale(0); transition: transform 0.45s cubic-bezier(0.16, 1, 0.3, 1); } .footer-circulo::after { content: ''; position: absolute; inset: 0; border-radius: 50%; border: 1px solid var(--color-border); z-index: -2; transition: border-color 0.35s ease, inset 0.35s ease; } .footer-circulo:hover, .footer-circulo:focus-visible { color: var(--color-bg-base); } .footer-circulo:hover::before, .footer-circulo:focus-visible::before { transform: scale(1); } .footer-circulo:hover::after { border-color: rgba(0, 212, 196, 0.5); } .footer-circulo .arrow { display: none; } /* ====== Tarjetas Showcase (modelo Showcase.svelte) ====== Refuerzo para .caso/.casos-uso (garantías, más casos, mirrors EN): superficie oscura, borde hairline, número fantasma, orbe de brillo que se enciende en hover y separador que escala. */ .casos-uso { counter-reset: showcase; } .casos-uso .caso { counter-increment: showcase; background: var(--color-bg-surface); border: 1px solid var(--color-border); border-radius: var(--radius-large); padding: var(--space-xl); position: relative; overflow: hidden; transition: border-color 0.35s ease, box-shadow 0.35s ease, transform 0.35s ease; } .casos-uso .caso::before { content: "0" counter(showcase); position: absolute; top: 0.15em; right: 0.6rem; font-family: var(--font-headings); font-size: clamp(3rem, 6vw, 4.5rem); line-height: 1; color: rgba(13, 23, 21, 0.05); pointer-events: none; transition: color 0.35s ease; } /* Spotlight que sigue al cursor (receta 4.5b): reemplaza el blob fijo del borde — js/app.js actualiza --mx/--my en pointermove. Sin hover (móvil), la tarjeta se ve normal, sin el radial. */ .casos-uso .caso::after { content: ''; position: absolute; inset: 0; border-radius: inherit; background: radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%), var(--color-accent-light), transparent 70%); opacity: 0; pointer-events: none; transition: opacity 0.3s ease; } .casos-uso .caso:hover { border-color: rgba(0, 212, 196, 0.35); box-shadow: var(--glow-accent-soft); transform: translateY(-4px); background-color: var(--color-bg-surface); } .casos-uso .caso:hover::before { color: rgba(0, 212, 196, 0.14); } @media (hover: hover) { .casos-uso .caso:hover::after { opacity: 1; } } /* ====== Storytelling de proceso en tarjetas apiladas (receta 4B.5, interactividad-wow-seo) ====== Cada etapa queda fija (sticky) un poco más abajo que la anterior conforme se baja, dando sensación de apilado — CSS puro, sin JS. Usado hoy solo en home (_includes/proceso-home.html, _data/proceso.yml); pensado para reutilizarse en páginas de servicio. */ .proceso-home__lista { list-style: none; padding: 0; margin: var(--space-xl) 0; } .proceso-home__card { background: var(--color-bg-surface); border: 1px solid var(--color-border); border-radius: var(--radius-large); padding: var(--space-xl); margin-bottom: var(--space-lg); box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.25); max-width: 640px; margin-inline: auto; } @media (min-width: 640px) { .proceso-home__card { position: sticky; min-height: 40vh; display: flex; flex-direction: column; justify-content: center; } .proceso-home__card:nth-child(1) { top: 9vh; } .proceso-home__card:nth-child(2) { top: 12vh; } .proceso-home__card:nth-child(3) { top: 15vh; } .proceso-home__card:nth-child(4) { top: 18vh; } } @media (max-width: 639px), (prefers-reduced-motion: reduce) { .proceso-home__card { position: static; min-height: 0; } } .proceso-home__numero { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; border-radius: 50%; border: 1px solid var(--color-accent); color: var(--color-accent); font-family: var(--font-headings); font-size: 1.3rem; margin-bottom: var(--space-md); } .proceso-home .boton-color-secondary { margin-top: var(--space-xl); } } /* Botón "volver arriba": círculo de cristal con hairline — el acento se reserva para la conversión. Va encima del botón flotante "Agendar llamada" (44px de alto + 12px de separación). */ @layer componentes { #scroll-to-top { position: fixed; bottom: calc(clamp(12px, 3vw, 20px) + 56px); right: clamp(12px, 3vw, 20px); padding: 0; line-height: 0; width: clamp(40px, 8vw, 50px); height: clamp(40px, 8vw, 50px); display: grid; place-items: center; background-color: rgba(13, 23, 21, 0.05); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); color: var(--color-text-dark); border: 1px solid var(--color-border); border-radius: 50%; cursor: pointer; opacity: 0; visibility: hidden; pointer-events: none; transition: opacity 0.3s, visibility 0.3s, transform 0.3s, border-color 0.3s, color 0.3s; box-shadow: var(--shadow-default); z-index: 900; } #scroll-to-top svg { display: block; width: clamp(16px, 4vw, 20px); height: clamp(16px, 4vw, 20px); } #scroll-to-top.show { opacity: 1; visibility: visible; pointer-events: auto; } #scroll-to-top:hover { border-color: var(--color-accent); color: var(--color-accent); transform: translateY(-2px); } } /* Estilos de páginas concretas: FAQ (details/summary) y formulario de diagnóstico (contacto). Todo en @layer componentes: el CSS sin capa ganaría a las capas del critical CSS. Acordeón oscuro estilo Aura: tarjetas de superficie con icono + que rota a × al abrir. */ @layer componentes { /* FAQ */ .faq { padding: 4em 0; } .faq h2 { margin-bottom: 3em; text-align: center; } /* Selectores bajo .faq, no "details"/"summary" a secas: un selector de elemento bare se aplica a CUALQUIER <details> del sitio (por ejemplo el acordeón de garantías, que es un componente aparte con su propio CSS), no solo al FAQ. */ .faq details { border: 1px solid var(--color-border); margin-bottom: 1em; border-radius: var(--radius-default); background-color: var(--color-bg-surface); transition: border-color 0.3s ease, box-shadow 0.3s ease; } .faq details:hover { border-color: rgba(0, 212, 196, 0.35); } /* El borde de "abierto" lleva el acento apagado */ .faq details[open] { border-color: rgba(0, 212, 196, 0.45); box-shadow: var(--glow-accent-soft); } .faq summary { padding: 1.4em 1.8em; cursor: pointer; font-family: var(--font-body); font-size: clamp(1.05rem, 1.5vw, 1.2rem); color: var(--color-text-dark); border-radius: var(--radius-default); transition: color 0.3s ease; position: relative; display: flex; align-items: center; justify-content: space-between; gap: 1em; list-style: none; } .faq summary::-webkit-details-marker { display: none; } /* Icono + del acordeón: rota 45° al abrir (se convierte en ×) */ .faq summary::after { content: "+"; font-family: var(--font-mono); font-size: 1.4em; font-weight: 400; line-height: 1; color: var(--color-text-muted); transform: rotate(0deg); transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1), color 0.3s ease; margin-left: auto; flex-shrink: 0; display: grid; place-items: center; min-width: 1.6em; min-height: 1.6em; border: 1px solid var(--color-border); border-radius: 50%; } .faq details[open] summary::after { transform: rotate(45deg); color: var(--color-accent); border-color: rgba(0, 212, 196, 0.4); } .faq summary:hover { color: var(--color-accent); } .faq summary strong { font-weight: 700; } .faq details p { padding: 0 1.8em 1.8em; margin: 0; color: var(--color-text); font-size: 1.05rem; line-height: 1.7; } .faq details[open] summary { padding-bottom: 0.8em; } /* Formulario de diagnóstico (contacto): sustituye los style= inline. .campo arma selects/inputs de una columna; el .botón del cierre queda separado 1em de la última pregunta. */ .formulario { max-width: 560px; } .campo { width: 100%; padding: 0.6em 0.8em; margin-top: 0.4em; border: 1px solid rgba(13, 23, 21, 0.16); border-radius: var(--radius-default); background: rgba(13, 23, 21, 0.03); color: var(--color-text-dark); font-size: 1rem; transition: border-color 0.3s ease, box-shadow 0.3s ease; } .campo:focus { outline: none; border-color: var(--color-accent); box-shadow: 0 0 0 3px rgba(0, 212, 196, 0.15); } .formulario .boton { margin-top: 1em; } /* Canales secundarios del contacto (_includes/canales.html): enlaces con flecha, uno por línea, con área táctil de 44px. */ .canales { list-style: none; padding: 0; display: grid; gap: 0.25rem; } .canales li { margin: 0; } /* inline-block: el subrayado cubre el texto y la flecha (atómica) queda fuera */ .canales a { display: inline-block; min-height: 44px; padding-block: 0.4em; } .canales .arrow { display: inline-block; } .canales a:hover .arrow { transform: translateX(4px); } /* Texto solo para lector de pantalla, p. ej. "(se abre en una pestaña nueva)" */ .visualmente-oculto { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; } /* Responsive adjustments */ @media (max-width: 768px) { .faq summary { padding: 1.2em 1.4em; font-size: 1rem; } .faq details p { padding: 0 1.4em 1.4em; font-size: 1rem; } .faq summary::after { font-size: 1.1em; } } } /* Línea de tiempo de casos de éxito — ver _plans/es/03-casos-exito-timeline.md El conector es un span real por hito (no un solo spine sobre toda la lista): así arranca exacto en el centro del primer punto y termina exacto en el centro del último, sin sobrante arriba/abajo, sea cual sea la altura real de cada hito. Reutiliza .animated-line (universales.css) para el scroll-reveal que ya existe en js/app.js (querySelectorAll('.animated-line')). Tema oscuro Aura: puntos y conectores ya salen de los tokens teal. */ @layer componentes { .timeline { --timeline-gap: var(--space-xl); position: relative; list-style: none; display: grid; gap: var(--timeline-gap); padding-inline-start: clamp(2.5rem, 6vw, 3.5rem); } .timeline__item { position: relative; display: grid; grid-template-columns: auto 1fr; gap: var(--space-xs) var(--space-md); align-items: baseline; /* universales.css tiene "p, li { margin-bottom: 1rem; max-width: 70ch }" para prosa; un <li> usado como fila de grid no es prosa y no debe heredar esto — si queda, el conector (que asume 100% + gap == distancia real entre puntos) se queda corto exactamente por ese margen. */ margin-bottom: 0; max-width: none; } .timeline__dot { position: absolute; z-index: 1; left: calc(clamp(0.9rem, 2.2vw, 1.25rem) - clamp(2.5rem, 6vw, 3.5rem)); top: 0.35em; width: 14px; height: 14px; border-radius: 50%; background: var(--color-accent); box-shadow: 0 0 0 4px var(--color-accent-light), 0 0 18px rgba(0, 212, 196, 0.4); } /* Centrado exacto sobre el punto (no a su borde izquierdo) y del punto de este hito al punto del siguiente: 100% (alto de este li) + el gap del grid. Los dos hitos comparten el mismo offset "top", así que se cancela en la resta — no hace falta saber la altura real del contenido de ningún hito. */ .timeline__connector { position: absolute; top: calc(0.35em + 7px); left: calc(clamp(0.9rem, 2.2vw, 1.25rem) - clamp(2.5rem, 6vw, 3.5rem) + 6px); width: 2px; height: calc(100% + var(--timeline-gap)); background-color: var(--color-gray-medium); } .timeline__fecha { grid-column: 1 / -1; display: inline-block; font-family: var(--font-mono); font-size: 0.72rem; font-weight: 500; text-transform: uppercase; letter-spacing: 0.2em; color: var(--color-secondary-text); } .timeline__contenido { grid-column: 1 / -1; h4 { margin-bottom: 0.35em; } p { margin-bottom: 0; color: var(--color-text); } } .timeline--resumen { --timeline-gap: var(--space-md); .timeline__contenido p { font-size: 0.95rem; } } /* Tarjeta del caso — la usa la vista completa (una sola columna en su propia página) y la vista resumen (grid de dos columnas en home, ver .casos-timeline-grid más abajo). Superficie oscura + hairline + glow teal al pasar el cursor (lenguaje Showcase del modelo Aura). */ .timeline-caso { display: flex; flex-direction: column; gap: var(--space-lg); } .timeline-caso--card { background: var(--color-bg-surface); border: 1px solid var(--color-border); border-radius: var(--radius-large); padding: var(--space-xl); position: relative; overflow: hidden; transition: border-color 0.3s ease, box-shadow 0.3s ease, transform 0.3s ease; } .timeline-caso--card::after { content: ''; position: absolute; width: 220px; height: 220px; top: -90px; right: -90px; border-radius: 50%; background: var(--color-accent); opacity: 0.03; filter: blur(100px); pointer-events: none; transition: opacity 0.45s ease; } .timeline-caso--card:hover { border-color: rgba(0, 212, 196, 0.35); box-shadow: var(--glow-accent-soft); transform: translateY(-4px); } .timeline-caso--card:hover::after { opacity: 0.12; } /* Testimonio del cliente: contorno teal apagado + relleno translúcido, sin el signo de comillas gigante que competía con el histórico. Un solo tratamiento para las dos vistas. */ .timeline-caso blockquote { margin: 0; padding: var(--space-md); border: 1px solid rgba(0, 212, 196, 0.3); background-color: rgba(0, 212, 196, 0.05); border-radius: var(--radius-default); } .timeline-caso blockquote::before { display: none; } .timeline-caso blockquote p { font-size: clamp(1.05rem, 1.6vw, 1.2rem); line-height: 1.5; color: var(--color-text); } .timeline-caso blockquote cite { margin-top: 0.6rem; font-size: 0.8rem; } /* Grid de casos en home: 2 columnas fijas en escritorio (nunca 4 angostas — cada tarjeta lleva histórico + testimonio, necesita ancho para leerse), 1 columna en móvil/tablet. No reutiliza .casos-uso (grid-template-columns: repeat(auto-fit, minmax(300px,1fr))): esa clase es de las tarjetas cortas icono+texto (.caso, garantías) y aquí forzaba hasta 4 columnas angostas con contenido mucho más alto. */ .casos-timeline-grid { display: grid; grid-template-columns: 1fr; gap: var(--space-2xl); margin: var(--space-xl) 0; } @media (min-width: 900px) { .casos-timeline-grid { grid-template-columns: repeat(2, 1fr); gap: var(--space-2xl) var(--space-xl); } } .casos-timeline-grid + .boton-color-secondary { margin-top: var(--space-2xl); } /* Tarjeta flip de casos (home): cara frontal con cliente + cifra, cara trasera con el resumen de línea de tiempo (receta 4B.8 de la skill interactividad-wow-seo). Con soporte de hover, la cara trasera cubre la frontal en posición absoluta y el contenedor se dimensiona por la frontal; sin soporte de hover (táctil) la trasera vuelve al flujo normal y ambas caras se leen apiladas — nada queda oculto para quien no tiene mouse. */ .m-flip { perspective: 1400px; } .m-flip__in { position: relative; min-height: 420px; transform-style: preserve-3d; transition: transform 0.7s cubic-bezier(0.16, 1, 0.3, 1); } .m-flip__front, .m-flip__back { backface-visibility: hidden; } .m-flip__back { position: absolute; inset: 0; transform: rotateY(180deg); overflow-y: auto; } @media (hover: hover) and (prefers-reduced-motion: no-preference) { .m-flip:hover .m-flip__in, .m-flip:focus-within .m-flip__in { transform: rotateY(180deg); } } @media (hover: none), (prefers-reduced-motion: reduce) { .m-flip__back { position: static; transform: none; } .m-flip__in { min-height: 0; } } .caso-flip__cara { background: var(--color-bg-surface); border: 1px solid var(--color-border); border-radius: var(--radius-large); padding: var(--space-xl); height: 100%; display: flex; flex-direction: column; justify-content: center; gap: var(--space-sm); text-align: center; } .m-flip__back.caso-flip__cara { justify-content: flex-start; text-align: left; } .caso-flip__cliente { margin: 0; font-family: var(--font-headings); font-size: 1.3rem; color: var(--color-text); } .caso-flip__cifra { margin: 0; font-family: var(--font-headings); font-size: clamp(2rem, 4vw, 2.6rem); color: var(--color-accent); } .caso-flip__cara .logo-cliente { align-self: center; object-position: center; } .caso-flip__cifra .cifra__etiqueta { display: block; font-family: var(--font-body); } .caso-flip__resumen { margin: 0; color: var(--color-text-muted); font-size: 0.95rem; } .caso-flip__hint { margin-top: var(--space-sm); font-size: 0.75rem; letter-spacing: 0.04em; color: var(--color-text-muted); } @media (hover: none) { .caso-flip__hint { display: none; } } } /* Primitivas compartidas por el hero de caso (crítico, solo en layout: caso) y por tarjetas y listados (css/caso.css). Un solo origen para las dos copias. .logo-cliente: altura fija por contexto, ancho por la proporción real del archivo (atributos width/height), nunca se deforma ni se amplía. .cifra: valor grande en serif + etiqueta + periodo, en pila. */ @layer primitivas { .logo-cliente { --logo-alto: 2.25rem; display: block; block-size: var(--logo-alto); inline-size: auto; max-inline-size: min(100%, 14rem); object-fit: contain; object-position: left center; } .logo-cliente--hero { --logo-alto: 3.5rem; margin-inline: auto; object-position: center; } .logo-cliente--marquee { --logo-alto: 1.75rem; } .logo-cliente--cuadrado { block-size: calc(var(--logo-alto) * 1.25); } .logo-cliente--placa { box-sizing: content-box; padding: 0.5rem 0.85rem; background: var(--color-primary); border-radius: var(--radius-default); } .logo-cliente--texto { block-size: auto; font-family: var(--font-headings); font-size: calc(var(--logo-alto) * 0.62); line-height: 1.15; letter-spacing: -0.01em; color: var(--color-primary); } .cifra { display: grid; gap: 0.35rem; margin: 0; max-width: none; } .cifra__valor { font-family: var(--font-headings); line-height: 1; letter-spacing: -0.02em; font-variant-numeric: lining-nums tabular-nums; color: var(--color-primary); } .cifra__antes { color: var(--color-text-muted); text-decoration: line-through; text-decoration-thickness: 1px; } .cifra__etiqueta { font-size: 1rem; line-height: 1.4; color: var(--color-text); } .cifra__periodo { font-family: var(--font-mono); font-size: 0.7rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--color-text-muted); } .cifra--grande .cifra__valor { font-size: clamp(3rem, 6vw + 1rem, 5.5rem); } .cifra--compacta .cifra__valor { font-size: clamp(2rem, 2vw + 1.25rem, 2.6rem); } } /* Páginas de caso y listados de casos (portafolio, más casos, garantías). Especificación: _plans/es/casos/00-formato-caso.md §7. */ @layer componentes { /* h2 con tamaño de h3 (mismo patrón que h3.h4 en universales.css) */ h2.h3 { font-size: clamp(1.5rem, 1.5vw + 1rem, 2.1rem); max-width: 30ch; } /* Franja antes/después + ficha del proyecto */ .caso-resumen { display: grid; gap: var(--space-lg); } .caso-resumen h2 { margin: 0; } .franja-cifras { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr)); margin: 0; border-block: 1px solid var(--color-border); & > div { display: flex; flex-direction: column; gap: 0.3rem; padding: var(--space-lg) var(--space-md); border-inline-start: 1px solid var(--color-border); } & > div:first-child { border-inline-start: 0; padding-inline-start: 0; } dt { font-size: 0.95rem; line-height: 1.4; color: var(--color-text); } dd { margin: 0; } } .franja-cifras__valor { order: -1; font-family: var(--font-headings); font-size: clamp(2.2rem, 3vw + 1rem, 3.2rem); line-height: 1; letter-spacing: -0.02em; font-variant-numeric: lining-nums tabular-nums; color: var(--color-primary); } .franja-cifras__antes { font-size: 0.85rem; color: var(--color-text-muted); } .franja-cifras__periodo { font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--color-text-muted); } @media (max-width: 640px) { .franja-cifras > div { padding-inline: 0; border-inline-start: 0; border-block-start: 1px solid var(--color-border); } .franja-cifras > div:first-child { border-block-start: 0; } } .ficha { display: grid; gap: 0; margin: 0; @media (min-width: 640px) { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--space-xl); } & > div { display: grid; grid-template-columns: 8rem 1fr; gap: var(--space-sm); padding-block: 0.7rem; border-block-end: 1px solid var(--color-border); } dt { font-family: var(--font-mono); font-size: 0.7rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--color-text-muted); padding-top: 0.3rem; } dd { margin: 0; font-size: 1rem; color: var(--color-text-dark); } } /* Dominios largos de clientes (agenciasincemarketing.com) no caben a 320 px: se parten solo cuando no hay otro punto de corte. */ :is(.caso-resumen, .caso-bloque, .dos_lados_copy, .tarjeta) :is(h2, h3, dt, dd, p, a), [aria-labelledby="mas-casos"] > h2 { overflow-wrap: anywhere; } /* Reto, cronología y resultado */ .caso-bloque { display: grid; gap: var(--space-md); justify-items: start; & > h2 { margin: 0; } } .caso-bloque__texto > * { margin-block: 0; } .caso-bloque--resultado { margin-top: var(--space-2xl); padding: var(--space-xl); background: var(--color-bg-surface); border: 1px solid var(--color-border); border-radius: var(--radius-large); } .caso-bloque__accion { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-md) var(--space-lg); margin-top: var(--space-sm); } /* Testimonio: cita serif grande con el logo encima */ .cita { display: grid; gap: var(--space-md); margin: 0; max-width: 52rem; blockquote { margin: 0; } figcaption { display: flex; flex-wrap: wrap; gap: 0.25rem 0.75rem; font-size: 0.95rem; color: var(--color-text-muted); } } .cita--grande blockquote p { font-family: var(--font-headings); font-size: clamp(1.4rem, 1.5vw + 1rem, 2.1rem); line-height: 1.35; color: var(--color-text-dark); } .cita__autor { font-weight: 500; color: var(--color-text-dark); } /* Galería de capturas reales */ .rejilla { --rejilla-min: 16rem; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--rejilla-min)), 1fr)); gap: var(--space-lg); width: 100%; } .rejilla--galeria { --rejilla-min: 18rem; align-items: start; } .galeria-item { margin: 0; display: grid; gap: var(--space-xs); img { width: 100%; border-radius: var(--radius-default); border: 1px solid var(--color-border); box-shadow: var(--shadow-default); } figcaption { font-size: 0.85rem; color: var(--color-text-muted); } } .galeria-item--movil img { max-width: 20rem; justify-self: center; } /* Tarjeta de caso: un solo enlace extendido a toda la tarjeta */ .tarjeta { display: flex; flex-direction: column; gap: var(--space-sm); & > * { margin: 0; } h3 { max-width: none; } h3 a { color: inherit; text-decoration: none; } h3 a::after { content: ""; position: absolute; inset: 0; z-index: 3; } &:has(a:focus-visible) { outline: 2px solid var(--color-accent); outline-offset: 3px; } h3 a:focus-visible { outline: none; } } .tarjeta .eyebrow { letter-spacing: 0.14em; line-height: 1.5; } .tarjeta__imagen { width: calc(100% + 2 * var(--space-xl)); max-width: none; margin: calc(-1 * var(--space-xl)) calc(-1 * var(--space-xl)) var(--space-sm); aspect-ratio: 16 / 9; object-fit: cover; object-position: top center; } @media (min-width: 760px) { .tarjeta--destacada { grid-column: span 2; } } .tarjeta--atenuada { background: transparent; .logo-cliente { opacity: 0.6; filter: grayscale(1); } .cifra__valor { color: var(--color-text-muted); } } @media (prefers-reduced-motion: reduce) { ::view-transition-group(*) { animation: none; } } /* Aparición al entrar en pantalla (Nivel 1, solo CSS): cifras, bloques del relato y tarjetas. Nunca en el hero. Se anima `translate`, no `transform`, para no pisar la elevación de .casos-uso .caso:hover. Sin soporte o con movimiento reducido, todo se ve quieto desde el principio. */ @supports (animation-timeline: view()) { @media (prefers-reduced-motion: no-preference) { :is(.franja-cifras > div, .caso-bloque, .tarjeta) { animation: caso-entra linear both; animation-timeline: view(); animation-range: entry 0% cover 20%; } @keyframes caso-entra { from { opacity: 0; translate: 0 1.5rem; } } } } /* Marquee de logos: en gris, color completo al pasar el cursor */ .marquee .logo-cliente--marquee { filter: grayscale(1); opacity: 0.55; transition: filter 0.3s ease, opacity 0.3s ease; } .marquee .logo-cliente--marquee:hover { filter: none; opacity: 1; } /* Portafolio: otros sitios entregados, en lista compacta */ .sitios-entregados { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr)); gap: var(--space-md); padding: 0; list-style: none; li { display: grid; gap: var(--space-xs); align-content: start; max-width: none; margin: 0; padding: var(--space-md); border: 1px solid var(--color-border); border-radius: var(--radius-default); } p { margin: 0; font-size: 0.95rem; } } .sitios-entregados--pasados li { border-style: dashed; .logo-cliente { opacity: 0.6; filter: grayscale(1); } } } /* Morph del logo entre la tarjeta y el hero del caso (view transition entre documentos, activada en el crítico). Un nombre por caso, generado desde casos.yml; el marquee no lleva data-caso para no repetir nombres. Archivo aparte porque lleva Liquid (auditoria.py no escanea CSS con plantilla). */ @layer componentes { [data-caso="almo-clinic"] .logo-cliente { view-transition-name: logo-almo-clinic; } [data-caso="amada-holistic"] .logo-cliente { view-transition-name: logo-amada-holistic; } [data-caso="dulcita"] .logo-cliente { view-transition-name: logo-dulcita; } [data-caso="grupo-nacional-herramientas"] .logo-cliente { view-transition-name: logo-grupo-nacional-herramientas; } [data-caso="hermes-gamba"] .logo-cliente { view-transition-name: logo-hermes-gamba; } [data-caso="ideas-colombia"] .logo-cliente { view-transition-name: logo-ideas-colombia; } [data-caso="italgel"] .logo-cliente { view-transition-name: logo-italgel; } [data-caso="ivlu"] .logo-cliente { view-transition-name: logo-ivlu; } [data-caso="ladrillera-colombia"] .logo-cliente { view-transition-name: logo-ladrillera-colombia; } [data-caso="leben-inmobiliaria"] .logo-cliente { view-transition-name: logo-leben-inmobiliaria; } [data-caso="medipro"] .logo-cliente { view-transition-name: logo-medipro; } [data-caso="mr-soluciones-integrales"] .logo-cliente { view-transition-name: logo-mr-soluciones-integrales; } [data-caso="seo-saas-b2b"] .logo-cliente { view-transition-name: logo-seo-saas-b2b; } [data-caso="sia-colombia"] .logo-cliente { view-transition-name: logo-sia-colombia; } [data-caso="since-marketing"] .logo-cliente { view-transition-name: logo-since-marketing; } [data-caso="smartinn"] .logo-cliente { view-transition-name: logo-smartinn; } [data-caso="sr-expertos-en-piel"] .logo-cliente { view-transition-name: logo-sr-expertos-en-piel; } [data-caso="tatiana-leal"] .logo-cliente { view-transition-name: logo-tatiana-leal; } [data-caso="turbo-diesel-gd"] .logo-cliente { view-transition-name: logo-turbo-diesel-gd; } } /* Acordeón de garantías (.garantias-list > .garantia, ver _includes/garantias.html). Filas planas con divisor, sin tarjeta/borde/radius — el contenido es largo (promesa + contraste + mecanismo) y una tarjeta obligaba a hacer scroll para leer una sola columna. Título + promesa quedan visibles siempre; el resto se expande con <details>. Ver _plans/es/04-garantias.md */ @layer componentes { .garantias-list { counter-reset: garantia; border-top: 1px solid var(--color-border); } .garantia { counter-increment: garantia; border-bottom: 1px solid var(--color-border); } .garantia__head { display: grid; grid-template-columns: auto auto 1fr auto; align-items: center; gap: var(--space-sm) var(--space-md); padding-block: var(--space-lg); cursor: pointer; list-style: none; } .garantia__head::-webkit-details-marker { display: none; } .garantia__index::before { content: "0" counter(garantia); font-family: var(--font-mono); font-size: 0.8rem; letter-spacing: 0.1em; color: var(--color-text-muted); } .garantia .icon-svg { width: 2rem; height: 2rem; color: var(--color-accent); filter: drop-shadow(0 0 12px rgba(0, 212, 196, 0.35)); } /* Dibujado del icono al entrar en viewport — reutiliza el mismo patrón de scroll-reveal que .animated-line (js/app.js), no una librería nueva. pathLength="1" en cada trazo del SVG normaliza el largo, así stroke-dasharray/-dashoffset funcionan igual en todos. */ @media (prefers-reduced-motion: no-preference) { .icon-svg.animated-icon :is(path, line, circle, rect) { stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 1.1s ease; } .icon-svg.animated-icon.visible :is(path, line, circle, rect) { stroke-dashoffset: 0; } } .garantia__heading h3 { font-size: clamp(1.15rem, 1.6vw, 1.4rem); color: var(--color-primary); transition: color 0.3s ease; } .garantia__head:hover .garantia__heading h3 { color: var(--color-accent); } .garantia__promesa { margin-top: 0.3rem; font-size: 0.95rem; color: var(--color-text); max-width: 60ch; } /* Botón +/- dibujado en CSS puro (dos barras), gira a "−" cuando el <details> está abierto. Mismo lenguaje que el acordeón de FAQ del modelo Aura (Plus/Minus de lucide), sin depender de una librería de iconos. */ .garantia__toggle { position: relative; width: 2.25rem; height: 2.25rem; flex-shrink: 0; border-radius: 50%; background: var(--color-bg-surface); } .garantia__toggle::before, .garantia__toggle::after { content: ""; position: absolute; top: 50%; left: 50%; background: var(--color-text-dark); transition: transform 0.3s ease, opacity 0.3s ease; } .garantia__toggle::before { width: 0.8rem; height: 1.5px; transform: translate(-50%, -50%); } .garantia__toggle::after { width: 1.5px; height: 0.8rem; transform: translate(-50%, -50%); } .garantia[open] .garantia__toggle { background: var(--color-accent); } .garantia[open] .garantia__toggle::before, .garantia[open] .garantia__toggle::after { background: var(--color-bg-base); } .garantia[open] .garantia__toggle::after { opacity: 0; transform: translate(-50%, -50%) rotate(90deg); } .garantia__body { display: grid; gap: 0.4rem; max-width: 68ch; padding-bottom: var(--space-lg); padding-left: calc(2rem + var(--space-md)); } .garantia__label { margin-top: 0.6rem; font-family: var(--font-mono); font-size: 0.68rem; font-weight: 500; text-transform: uppercase; letter-spacing: 0.25em; color: var(--color-secondary-text); } .garantia__contraste, .garantia__mecanismo { font-size: 0.95rem; } .garantia .boton-secundario { margin-top: var(--space-sm); align-self: flex-start; } @media (max-width: 640px) { .garantia__head { grid-template-columns: auto 1fr auto; } .garantia__index { display: none; } .garantia__body { padding-left: 0; } } } /* Banner de cookies (antes en un <style> inline de _includes/banner.html). Barra inferior de cristal del lenguaje Aura: fondo claro translúcido, blur y hairline superior. En @layer componentes; el antiguo selector button{} desnudo se restringe a .cookie-buttons. */ @layer componentes { .cookie-banner { position: fixed; bottom: 0; left: 0; right: 0; background: rgba(252, 251, 249, 0.95); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border-top: 1px solid var(--color-border); color: var(--color-text); padding: 1rem; z-index: 1000; display: none; } .cookie-content { max-width: 1200px; margin: 0 auto; display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap; } .cookie-content p { margin: 0; flex: 1; min-width: 280px; font-size: 0.9rem; } .cookie-content a { color: var(--color-accent); text-decoration: underline; } .cookie-buttons { display: flex; gap: 0.5rem; } .cookie-buttons button { padding: 0.55rem 1.1rem; border: none; border-radius: var(--radius-pill); cursor: pointer; font-weight: 600; font-size: 0.85rem; transition: background-color 0.2s, box-shadow 0.2s, border-color 0.2s; } .button-accept { background: var(--color-accent); color: var(--color-bg-base); } .button-accept:hover { background: var(--color-secondary); box-shadow: 0 4px 20px rgba(0, 212, 196, 0.35); } .button-reject { background: transparent; color: var(--color-text); border: 1px solid var(--color-border); } .button-reject:hover { background: rgba(13, 23, 21, 0.05); border-color: rgba(13, 23, 21, 0.25); } @media (max-width: 600px) { .cookie-content { text-align: center; } .cookie-buttons { width: 100%; justify-content: center; } } } /* Buscador del sitio: botón del menú, <dialog> y la página /buscar/ (_includes/buscador-*.html, buscar.html, js/buscador.js). Kit de metodo-web; colores y radios con los tokens de base.css. */ @layer componentes { .buscador-boton { display: inline-flex; align-items: center; gap: 0.5em; color: inherit; text-decoration: none; } /* Menú de escritorio: solo la lupa, con área táctil de 40px que no altera la altura del menú. */ .nav-menu .buscador-boton { display: inline-grid; place-items: center; width: 40px; height: 40px; margin-block: -8px; padding: 0; border-radius: 50%; color: var(--color-text); &:hover { color: var(--color-accent); background: var(--color-accent-light); } } /* Menú móvil: la lupa al tamaño del texto serif del overlay. */ .nav-overlay .buscador-boton svg { width: 0.8em; height: 0.8em; } html:has(.buscador[open]) { overflow: hidden; } .buscador { width: min(720px, 100% - 32px); max-height: min(680px, 100dvh - 96px); margin: 72px auto auto; padding: 0; border: 1px solid var(--color-border); border-radius: var(--radius-large); background: var(--color-bg-base); color: var(--color-text-dark); box-shadow: var(--shadow-hover); overflow: hidden; &[open] { display: flex; flex-direction: column; } &::backdrop { background: rgba(13, 23, 21, 0.45); backdrop-filter: blur(4px); } @media (max-width: 767px) { width: 100%; max-width: 100%; height: 100dvh; max-height: 100dvh; margin: 0; border: 0; border-radius: 0; } .buscador-panel { overflow-y: auto; padding: 8px 20px 24px; } } /* Los estilos globales de form/input (tarjeta de cristal en universales.css) se anulan aquí: la caja del buscador es una sola línea sin tarjeta. */ .buscador-form { display: flex; align-items: center; gap: 12px; margin: 0; padding: 14px 20px; border: 0; border-bottom: 1px solid var(--color-border); border-radius: 0; background: none; box-shadow: none; overflow: visible; color: var(--color-text-muted); &::before { content: none; } input { flex: 1; width: auto; min-width: 0; min-height: 0; margin: 0; padding: 6px 0; border: 0; border-radius: 0; background: none; box-shadow: none; font: inherit; font-size: 1.15rem; line-height: 1.4; color: var(--color-text-dark); &:focus, &:focus-visible { outline: none; box-shadow: none; } &::-webkit-search-cancel-button { cursor: pointer; } } &:has(input:focus-visible) { box-shadow: inset 0 -2px 0 var(--color-accent); } } .buscador-form__cerrar { flex: none; padding: 6px 12px; border: 1px solid var(--color-border); border-radius: var(--radius-pill); background: none; font: inherit; font-size: 0.85rem; color: var(--color-text-muted); cursor: pointer; &:hover { color: var(--color-text-dark); border-color: var(--color-text-dark); } } .buscador-panel__etiqueta { margin: 20px 0 10px; font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.2em; text-transform: uppercase; color: var(--color-text-muted); } .buscador-panel__estado { margin: 16px 0 8px; font-size: 0.85rem; color: var(--color-text-muted); &:empty { display: none; } } .buscador-chips, .buscador-enlaces, .buscador-resultados { list-style: none; margin: 0; padding: 0; } .buscador-chips { display: flex; flex-wrap: wrap; gap: 8px; a { display: inline-block; padding: 6px 14px; border: 1px solid var(--color-border); border-radius: var(--radius-pill); font-size: 0.95rem; line-height: 1.4; color: var(--color-text-dark); text-decoration: none; &:hover { border-color: var(--color-accent); color: var(--color-secondary-text); } } } .buscador-enlaces { display: grid; gap: 6px; a { color: var(--color-secondary-text); text-decoration: none; &::after { content: " →"; } &:hover { text-decoration: underline; } } } /* Filtros por tipo: radios; js/buscador.js oculta los resultados de otros tipos. */ .buscador-filtros { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 8px; padding: 0; border: 0; &[hidden] { display: none; } label { padding: 4px 12px; border: 1px solid var(--color-border); border-radius: var(--radius-pill); font-size: 0.85rem; cursor: pointer; &[hidden] { display: none; } &:has(:checked) { background: var(--color-text-dark); border-color: var(--color-text-dark); color: var(--color-bg-base); } &:has(:focus-visible) { outline: 2px solid var(--color-accent); outline-offset: 2px; } } input { position: absolute; opacity: 0; pointer-events: none; } span { opacity: 0.7; } } .buscador-resultados { display: grid; grid-template-columns: minmax(0, 1fr); /* una palabra larga no ensancha la lista (WebKit) */ gap: 4px; [hidden] { display: none; } } :is(.buscador-resultado, .buscador-promo) a { display: grid; gap: 4px; padding: 12px 14px; margin-inline: -14px; border-radius: var(--radius-default); color: var(--color-text-dark); text-decoration: none; &:hover, &:focus-visible { background: var(--color-bg-surface); } } .buscador-resultado__tipo { font-family: var(--font-mono); font-size: 0.7rem; letter-spacing: 0.2em; text-transform: uppercase; color: var(--color-secondary-text); } :is(.buscador-resultado__titulo, .buscador-resultado__extracto) { overflow-wrap: anywhere; } .buscador-resultado__titulo { font-size: 1.05rem; font-weight: 700; line-height: 1.3; } .buscador-resultado__extracto { font-size: 0.95rem; line-height: 1.55; color: var(--color-text); mark { background: var(--color-accent-light); color: inherit; padding: 0 2px; border-radius: 2px; } } .buscador-promo { margin-bottom: 8px; a { margin-inline: 0; border: 1px solid var(--color-border); background: var(--color-bg-surface); &:hover, &:focus-visible { border-color: var(--color-accent); } .buscador-resultado__titulo::after { content: " →"; color: var(--color-secondary-text); } } } :is(.buscador-cta, .buscador-vacio) { padding: 16px 18px; border-radius: var(--radius-default); background: var(--color-bg-surface); } .buscador-cta { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; margin: 8px 0; p { flex: 1 1 260px; margin: 0; font-size: 0.95rem; } .boton { white-space: nowrap; } } .buscador-vacio { display: grid; gap: 12px; margin-top: 16px; &[hidden] { display: none; } p { margin: 0; } .boton { justify-self: start; } } .buscador-vacio__titulo { font-size: 1.15rem; font-weight: 700; } .buscador-todos-envoltura { margin: 12px 0 0; &:has(> [hidden]) { display: none; } } .buscador-todos { color: var(--color-secondary-text); text-decoration: none; &::after { content: " →"; } &:hover { text-decoration: underline; } } /* /buscar/ */ .buscador-pagina { width: min(840px, 100% - 30px); margin: calc(var(--space-2xl) + 4rem) auto var(--space-2xl); h1 { margin: 0 0 24px; } .buscador-form { border: 1px solid var(--color-border); border-radius: var(--radius-default); background: var(--color-bg-base); } } .buscador-pagina__sin-js { margin-top: 16px; } }

