/*
Theme Name: TSS Theme
Theme URI: https://tecnicserveissegria.cat
Author: Invelon
Description: Tema de bloques (FSE) a medida para Tècnic Serveis Segrià. SOLO diseño. Replica el aspecto del sitio Wix original: cabecera/hero oscuros, azul de acento, y contenido real.
Requires at least: 6.6
Tested up to: 7.0
Requires PHP: 8.2
Version: 0.8.0
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: tss-theme
*/

/*
 * ⚠️ SUBIR ESTA VERSIÓN EN CADA CAMBIO DE CSS O DE JS.
 *
 * `functions.php` la usa como parámetro `?ver=` al encolar la hoja de estilos y los scripts, así
 * que ES el rompe-cachés. Si no se sube, quien ya visitó la web sigue sirviéndose el CSS viejo
 * desde su caché y NO ve los cambios — comprobado en el navegador: el servidor ya tenía el CSS
 * nuevo y el navegador seguía pintando el anterior.
 */

/*
 * FUENTE DE VERDAD de la paleta. `theme.json` REPLICA estos mismos valores en su `palette`
 * (JSON no admite comentarios, así que la explicación vive aquí): si se cambia un color hay que
 * cambiarlo en los dos sitios. theme.json es lo que pinta el contenido de bloques —las páginas
 * legales, por ejemplo— y se había quedado con la paleta anterior al cambio de marca (teal
 * #0e4d64 y naranja #f39c12), así que los enlaces de las páginas legales salían teal y al pasar
 * el ratón se volvían NARANJAS, en un sitio cuyo acento es azul.
 */
:root{
  --tss-dark:#0f1319;       /* cabecera / hero (como Wix) */
  --tss-dark2:#171d26;
  --tss-blau:#116dff;       /* azul Wix (acento/botones) */
  --tss-blau-fosc:#0045a5;
  /* Azul de marca ACLARADO, solo para TEXTO sobre el fondo oscuro. El --tss-blau da 4,13:1
     sobre --tss-dark y no llega al 4,5:1 que exige AA para texto normal; este sube a 4,62:1.
     Es el mismo azul, un paso más claro: sirve para cumplir sin salirse de la marca.
     Para botones y bloques de color se sigue usando --tss-blau (el contraste de un elemento
     no textual se mide distinto). */
  --tss-blau-clar:#2278ff;
  --tss-text:#20303c;
  --tss-gris:#6b7280;
  --tss-gris-clar:#f5f7fa;
  --tss-vora:#e5e9ef;
  --tss-radi:10px;
  --tss-ombra:0 12px 34px rgba(15,19,25,.12);
  --tss-max:1160px;
  /* Estados de aviso como variables y no como hex sueltos: el mismo par de colores estaba
     escrito a mano en cinco reglas de este fichero y otra vez en class-public-page.php del
     plugin de presupuestos. Si se ajustaba el tono había que acordarse de todos los sitios, y
     olvidar uno desincronizaba los dos formularios del sitio sin que se notara. */
  --tss-error:#a23b32;
  --tss-error-fons:#fdecea;
  --tss-error-vora:#f3c9c4;
  --tss-ok:#1f7a44;
  --tss-ok-fons:#e6f5ec;
  --tss-ok-vora:#bfe3cd;
}

body{ color:var(--tss-text); line-height:1.6; -webkit-font-smoothing:antialiased; }
a{ text-decoration:none; }
h1,h2,h3,h4{ line-height:1.15; color:var(--tss-dark); font-weight:800; }
.tss-wrap{ max-width:var(--tss-max); margin-inline:auto; padding-inline:24px; }

/* ---------- Botones ---------- */
/* La transición NOMBRA sus propiedades a propósito: con el atajo `transition:.18s`
   (= `transition: all`) se animaba también el `outline` del foco, así que el usuario de
   teclado se quedaba sin indicador durante los primeros 180 ms. El anillo de foco debe
   aparecer al instante, siempre. */
.tss-btn{ display:inline-flex; align-items:center; justify-content:center; gap:8px; padding:14px 26px; border-radius:8px; font-weight:700; font-size:1rem; line-height:1.2; white-space:nowrap; transition:background-color .18s ease-out, color .18s ease-out, border-color .18s ease-out, transform .18s ease-out; cursor:pointer; border:none; }
.tss-btn:active{ transform:translateY(1px); }
/* Estado de envío: el botón se deshabilita mientras se procesa, para no enviar dos veces. */
.tss-btn[disabled], .tss-btn[aria-busy="true"]{ opacity:.65; cursor:progress; transform:none; }
.tss-btn-blau{ background:var(--tss-blau); color:#fff; }
.tss-btn-blau:hover{ background:var(--tss-blau-fosc); color:#fff; transform:translateY(-2px); }
.tss-btn-ghost{ background:transparent; color:#fff; border:2px solid rgba(255,255,255,.35); }
.tss-btn-ghost:hover{ background:rgba(255,255,255,.10); color:#fff; }
/* Secundario para FONDO CLARO. Faltaba: solo existía el «ghost», que es blanco y solo sirve
   sobre el hero oscuro. Sin una variante clara, cualquier acción secundaria acababa en azul
   sólido, y dos botones azules juntos no dan jerarquía: el usuario no sabe cuál es la acción
   principal («una sola llamada a la acción primaria por pantalla»). */
.tss-btn-suau{ background:transparent; color:var(--tss-blau); border:2px solid var(--tss-vora); font-weight:600; }
.tss-btn-suau:hover{ border-color:var(--tss-blau); background:rgba(17,109,255,.06); color:var(--tss-blau-fosc); }

/* ---------- Cabecera ---------- */
.tss-header{ position:sticky; top:0; z-index:50; background:var(--tss-dark); }
.tss-logo{ display:inline-block; width:170px; height:50px; background:url('assets/img/logo-tss-blanco.png') left center/contain no-repeat; text-indent:-9999px; overflow:hidden; white-space:nowrap; }
.tss-nav{ display:flex; align-items:center; gap:30px; }
.tss-nav-links{ display:flex; gap:26px; list-style:none; margin:0; padding:0; }
/* `nowrap`: el menú necesita 741px y los enlaces de texto no lo llevaban, así que en la banda
   de anchos justo por encima del corte de móvil (860px) "QUIÉNES SOMOS" se partía en dos líneas
   — y un enlace clicable partido parece un error de maquetación (verificado con el navegador). */
/* `padding` vertical para dar área de toque: los enlaces medían 20px de alto, el 45% del
   mínimo de 44. El menú se oculta por debajo de 860px, pero entre 861px y ~1200px se ve y se
   usa CON EL DEDO: tablets en horizontal, portátiles táctiles, iPad Pro. No cambia nada del
   aspecto —tipografía, `nowrap` y el `gap:26px` se quedan igual— y no estira la cabecera,
   cuya altura la marcan el logo (50px) y el botón. */
.tss-nav-links a{ display:inline-flex; align-items:center; padding:12px 0; color:#e8edf3; font-weight:600; font-size:.92rem; letter-spacing:.03em; text-transform:uppercase; white-space:nowrap; }
.tss-nav-links a:hover{ color:var(--tss-blau); }

/* ---------- Hero (oscuro, como Wix) ---------- */
.tss-hero{ background:var(--tss-dark); color:#fff; padding:96px 0 104px; position:relative; overflow:hidden; text-align:center; }
.tss-hero::before{ content:""; position:absolute; inset:0; background:radial-gradient(circle at 70% 20%,rgba(17,109,255,.20),transparent 55%); }
.tss-hero .tss-wrap{ position:relative; z-index:1; max-width:900px; }
/* Azul aclarado: a 1rem/800 este texto NO cuenta como "grande" para WCAG (grande = 24px
   normal o 18,66px en negrita), así que le aplica el 4,5:1, y el azul de marca se quedaba en
   4,13:1 sobre el hero oscuro. Es la primera línea que se lee del sitio. */
.tss-hero .tss-tagline{ color:var(--tss-blau-clar); font-weight:800; letter-spacing:.08em; text-transform:uppercase; font-size:1rem; margin-bottom:16px; }
.tss-hero h1{ color:#fff; font-size:clamp(2.1rem,5.2vw,3.6rem); margin-bottom:20px; }
.tss-hero p{ font-size:1.15rem; color:#c3ccd6; max-width:640px; margin:0 auto 34px; }
.tss-phones{ display:flex; gap:16px; flex-wrap:wrap; justify-content:center; }
.tss-phones .tss-btn{ font-size:1.15rem; padding:16px 30px; }

/* ---------- Secciones ---------- */
.tss-section{ padding:80px 0; }
.tss-section--gris{ background:var(--tss-gris-clar); }
.tss-sechead{ max-width:720px; margin:0 auto 50px; text-align:center; }
.tss-sechead .tss-eyebrow{ color:var(--tss-blau); font-weight:800; letter-spacing:.08em; text-transform:uppercase; font-size:.82rem; }
.tss-sechead h2{ font-size:clamp(1.8rem,3.6vw,2.4rem); margin:10px 0 14px; }
.tss-sechead p{ color:var(--tss-gris); font-size:1.05rem; }

/* ---------- Servicios (3) ---------- */
.tss-cards{ display:grid; grid-template-columns:repeat(3,1fr); gap:26px; }
/* Una sola señal de hover (elevación), no tres a la vez: antes subía 6px, ponía sombra Y
   apagaba el borde, que es el "todo a la vez" que delata una tarjeta generada. */
.tss-card{ background:#fff; border:1px solid var(--tss-vora); border-radius:var(--tss-radi); padding:34px 28px; transition:box-shadow .18s ease-out, transform .18s ease-out; }
.tss-card:hover{ transform:translateY(-3px); box-shadow:var(--tss-ombra); }
.tss-card .tss-ico{ display:inline-flex; align-items:center; justify-content:center; width:56px; height:56px; border-radius:14px; background:rgba(17,109,255,.10); color:var(--tss-blau); font-size:1.6rem; margin-bottom:18px; }
.tss-card h3{ font-size:1.2rem; margin-bottom:10px; color:var(--tss-dark); }
.tss-card p{ color:var(--tss-gris); font-size:.98rem; }

/* ---------- Serveis: panal hexagonal (como Wix) ---------- */
.tss-hex-intro{ max-width:840px; margin:0 auto 44px; text-align:center; color:var(--tss-gris); font-size:1.05rem; }
.tss-hex-intro strong{ color:var(--tss-dark); }
.tss-hex-grid{ --hh:214px; display:flex; flex-direction:column; align-items:center; }
.tss-hex-row{ display:flex; justify-content:center; }
.tss-hex-row + .tss-hex-row{ margin-top:calc(var(--hh) * -0.255); }
/* `transition: transform` y no el atajo `transition:.2s`: el hexágono es un <a>, así que con
   el atajo (= `transition: all`) se animaba también el `outline` del foco y quien navega con
   teclado se quedaba sin indicador — el mismo fallo que en los botones, y aquí en la rejilla
   de servicios, que es la navegación principal de la portada. */
/* La FOTO va en el fondo del propio hexágono y el VELO de color en `::before`. Antes la foto
   estaba dentro del `background` del ::before junto al degradado, lo que obligaba a repetir la
   URL en la regla del hover; separándolos, el hover solo toca el velo. */
.tss-hex{ width:186px; height:var(--hh); margin:5px; position:relative; clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%); background-color:var(--tss-dark2); background-position:center; background-size:cover; background-repeat:no-repeat; display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center; color:#fff; overflow:hidden; transition:transform .2s ease-out; }
/* El velo SÍ es animable ahora (es un degradado de color sólido, sin imagen dentro). */
.tss-hex::before{ content:""; position:absolute; inset:0; background:linear-gradient(rgba(15,19,25,.30),rgba(15,19,25,.72)); transition:background-color .2s ease-out; }
.tss-hex > *{ position:relative; z-index:1; }
/* Propiedades SUELTAS, nunca el atajo `background`.
   Aquí había `background:center/contain no-repeat`, y el atajo pone a `none` todo lo que no
   menciona — incluida `background-image`. Como `.tss-hex .ico` (0,2,0) tiene más especificidad
   que `.ico-manteniment` (0,1,0), borraba el icono de cada servicio: los siete iconos del panal
   NUNCA se han pintado (medido: `background-image` calculado = none en los 7). En el Wix del
   cliente sí están. Es el mismo tipo de error que el `transition:all` de los botones: un atajo
   que pisa en silencio lo que declara otra regla. */
.tss-hex .ico{ width:56px; height:56px; margin-bottom:12px; background-position:center; background-size:contain; background-repeat:no-repeat; filter:drop-shadow(0 2px 5px rgba(0,0,0,.55)); }
/* Banda tras la etiqueta, como en el Wix del cliente: deja la foto visible y a la vez garantiza
   el contraste del texto blanco. Sin ella habría que oscurecer TODA la foto para que el texto
   cumpliera, y entonces no se distinguiría qué foto es — que es justo el problema que se está
   arreglando. Con el velo (~.51 a esta altura) más esta banda, el peor caso posible (una zona de
   foto blanca) queda en 5,2:1 sobre blanco, por encima del 4,5:1 de AA. */
.tss-hex .lbl{ font-weight:800; font-size:.82rem; text-transform:uppercase; letter-spacing:.02em; padding:7px 16px; line-height:1.25; width:100%; background:rgba(15,19,25,.70); }
.tss-hex:hover{ transform:scale(1.04); }
/* `:active` imprescindible: `:hover` NO se dispara en pantalla táctil, y esta rejilla ES la
   navegación principal de servicios de la portada. En móvil, tocar un hexágono no producía
   ningún cambio visible hasta que cargaba la página de destino: con conexión lenta son
   segundos de duda sobre si el toque se registró. La transición sigue acotada a `transform`
   (ver arriba) a propósito: volver al atajo `all` reintroduciría el bug del anillo de foco. */
.tss-hex:active{ transform:scale(.97); }
.tss-hex:hover::before{ background:linear-gradient(rgba(17,109,255,.35),rgba(17,109,255,.62)); }

/* ---- Una foto por servicio (extraídas del Wix del cliente) ----
   Cada hexágono tiene la SUYA. Antes los siete compartían `foto-fontanero.jpg`: la rejilla es la
   navegación principal de la portada y con la misma foto repetida era indistinguible. Las siete
   juntas pesan 161 KB (los originales del Wix sumaban 55 MB). */
.tss-hex--manteniment{   background-image:url('assets/img/hex/manteniment.webp'); }
.tss-hex--installacions{ background-image:url('assets/img/hex/installacions.webp'); }
.tss-hex--gas{           background-image:url('assets/img/hex/gas.webp'); }
.tss-hex--fontaneria{    background-image:url('assets/img/hex/fontaneria.webp'); }
.tss-hex--obres{         background-image:url('assets/img/hex/obres.webp'); }
.tss-hex--blanca{        background-image:url('assets/img/hex/blanca.webp'); }
.tss-hex--urgencies{     background-image:url('assets/img/hex/urgencies.webp'); }
/* Urgencias en ROJO, como en el Wix: es la acción distinta del resto y el color la separa. El
   velo rojo va casi opaco pero deja asomar la foto, así el hexágono no queda como una mancha
   plana. Antes el rojo estaba en el `background` del <a> y el ::before se ocultaba, lo que
   impedía tener foto debajo. */
.tss-hex--urgencies::before{ background:linear-gradient(160deg,rgba(200,26,44,.88),rgba(124,15,28,.94)); }
.tss-hex--urgencies:hover::before{ background:linear-gradient(160deg,rgba(224,32,52,.90),rgba(150,18,34,.95)); }
/* Iconos del panal, comprobados uno a uno abriéndolos (no por su número de fichero):
   serv-1 llave+destornillador · serv-2 ladrillos · serv-3 caja de herramientas · serv-4 grifo ·
   serv-5 CASA · serv-7 LLAMA.
   `gas` y `blanca` estaban CRUZADOS: Gas mostraba la casa y Gama Blanca la llama. */
.ico-manteniment{ background-image:url('assets/img/serv/serv-1.png'); }
.ico-obres{ background-image:url('assets/img/serv/serv-2.png'); }
.ico-installacions{ background-image:url('assets/img/serv/serv-3.png'); }
.ico-fontaneria{ background-image:url('assets/img/serv/serv-4.png'); }
.ico-gas{ background-image:url('assets/img/serv/serv-7.png'); }
.ico-blanca{ background-image:url('assets/img/serv/serv-5.png'); }
/* Urgencias: solo la SIRENA, recortada de la imagen del Wix.
   `serv-6.png` no es un icono: es el panel entero de urgencias del Wix, con el rótulo «SERVEI
   URGÈNCIES» y sus tres viñetas INCRUSTADOS como píxeles. Aplastado a 56x56 era una manchita
   ilegible, y además ese texto no se puede seleccionar, ni traducir, ni leer un lector de
   pantalla. Se usa solo la sirena y el texto lo pone el HTML (`.lbl`), que sí es texto de verdad.
   Se deja en rojo a propósito, como en el Wix: es la única acción urgente del panal. */
.ico-urgencies{ background-image:url('assets/img/serv/sirena.png'); }
/* La sirena se pinta en BLANCO: el fichero del Wix es rojo y sobre el hexágono rojo desaparecía
   (comprobado en la captura). `brightness(0) invert(1)` la pasa a blanco sin tener que crear otro
   fichero. El selector lleva `.tss-hex` porque `.tss-hex .ico` ya declara un `filter` con la misma
   especificidad (0,2,0) y, si no, ganaría ese y se perdería el cambio de color. */
.tss-hex--urgencies .ico{ filter:brightness(0) invert(1) drop-shadow(0 2px 5px rgba(0,0,0,.45)); }
@media(max-width:860px){
  .tss-hex-row{ flex-wrap:wrap; }
  .tss-hex-row + .tss-hex-row{ margin-top:0; }
}

/* ---------- Qui som ---------- */
.tss-quisom-grid{ display:grid; grid-template-columns:1fr 1fr; gap:48px; align-items:center; }
.tss-quisom-text p{ margin-bottom:16px; font-size:1.05rem; }
/* Ahora es un <img> con loading="lazy" (ver TemplateText::quisom()), no un fondo CSS. El
   object-fit reproduce exactamente el `center/cover` que hacía el background, y el borde
   redondeado y la sombra se quedan en el propio elemento: mismo aspecto, 422 KB que ya no
   compiten con el hero. `display:block` evita el hueco bajo la imagen en línea. */
.tss-quisom-photo{ display:block; width:100%; height:100%; min-height:320px; object-fit:cover; border-radius:var(--tss-radi); box-shadow:var(--tss-ombra); }
/* Azul OSCURO de marca, no el claro: el fondo de esta insignia es el azul al 10% compuesto
   sobre el gris de la sección (#dee9fa), y ahí el azul de marca da 3,68:1 — el peor contraste
   del sitio, y en un texto de 13,6px que además es un dato de confianza («años de
   experiencia»). Con el azul oscuro sube a 7,16:1. */
.tss-badge{ display:inline-block; margin-top:8px; background:rgba(17,109,255,.10); color:var(--tss-blau-fosc); font-weight:700; font-size:.85rem; padding:8px 15px; border-radius:30px; }
/* Misma corrección para el «eyebrow» de ESTA sección y solo de esta: es la única con fondo
   gris, y sobre gris el azul de marca cae a 4,20:1. Sobre blanco da 4,51:1 y sí cumple, así
   que los demás se dejan como están: se cambia lo que falla, no lo que ya pasa. */
.tss-section--gris .tss-sechead .tss-eyebrow{ color:var(--tss-blau-fosc); }

/* ---------- Banda foto ---------- */
.tss-band{ position:relative; min-height:340px; display:flex; align-items:center; background:url('assets/img/foto-fontanero.jpg') center/cover; }
.tss-band::before{ content:""; position:absolute; inset:0; background:linear-gradient(90deg,rgba(15,19,25,.9),rgba(15,19,25,.5)); }
.tss-band .tss-wrap{ position:relative; z-index:1; color:#fff; max-width:640px; }
.tss-band h2{ color:#fff; font-size:clamp(1.6rem,3vw,2.2rem); margin-bottom:14px; }
.tss-band p{ color:#dbe2ea; }

/* ---------- Pressupost (CTA azul) ---------- */
.tss-cta{ background:var(--tss-blau); color:#fff; text-align:center; }
.tss-cta h2{ color:#fff; font-size:clamp(1.6rem,3vw,2.2rem); max-width:820px; margin:0 auto 12px; }
/* Blanco puro, NO un azul clarito: medido en el navegador, #dceaff sobre el azul de marca da
   3,71:1 y no llega al 4,5:1 que exige AA para texto normal. En blanco sube a 4,51:1 y cumple.
   Es el tipo de fallo que no se ve a ojo: el texto "parece" legible, pero no lo es para todos. */
.tss-cta p{ color:#fff; margin-bottom:24px; }
.tss-cta .tss-btn-blau{ background:#fff; color:var(--tss-blau); }
.tss-cta .tss-btn-blau:hover{ background:var(--tss-dark); color:#fff; }

/* ---------- Contacte ---------- */
.tss-contacte-grid{ display:grid; grid-template-columns:1fr 1fr; gap:44px; align-items:start; }
.tss-contact-item{ display:flex; gap:14px; margin-bottom:18px; align-items:flex-start; }
.tss-contact-item .tss-dot{ width:46px; height:46px; flex:none; border-radius:12px; background:rgba(17,109,255,.10); display:flex; align-items:center; justify-content:center; color:var(--tss-blau); font-weight:800; font-size:1.1rem; }
.tss-contact-actions{ display:flex; gap:12px; flex-wrap:wrap; margin-top:10px; }

/* ---------- Footer ---------- */
.tss-footer{ background:var(--tss-dark); color:#aeb8c4; padding:56px 0 28px; font-size:.93rem; }
.tss-footer a{ color:#aeb8c4; }
.tss-footer a:hover{ color:#fff; }
/* h2 en el HTML (ver TemplateText::footer(): un h4 aquí saltaba niveles en todas las páginas),
   pero con el MISMO tamaño visual de antes: el nivel semántico y el tamaño son cosas distintas. */
.tss-footer h2{ color:#fff; margin-bottom:12px; font-size:1rem; font-weight:800; }
/* Separación REAL entre enlaces, no solo más padding: con `padding:3px 0` los enlaces medían
   29,8px y quedaban pegados sin ningún hueco entre ellos, así que tocar cerca del borde entre
   «Fontaneria» y «Urgències» activaba el que no se quería. El `gap` de la columna es lo que
   crea la separación (mínimo 8px de la guía) y el padding sube el alto hacia los 44px. */
.tss-footer-cols > div{ display:flex; flex-direction:column; align-items:flex-start; gap:8px; }
/* `line-height` explícito + 11px de relleno = 44px exactos de alto. Con el line-height
   heredado (1.6 -> 21,76px) los enlaces se quedaban en 43,8 y no se llegaba al número. */
.tss-footer a{ display:block; padding:11px 0; line-height:22px; }
/* OJO con la especificidad, medido en el navegador: aquí NO se puede usar
   `.tss-footer a:not(.tss-logo)`. `:not()` cuenta con la especificidad de su argumento, así que
   ese selector vale (0,2,1) y pasa a ganarle a `.tss-footer-bottom a` (0,1,1) — que hasta
   entonces ganaba solo por ir después. Resultado: los tres enlaces legales se volvían bloques a
   todo el ancho y partían la línea de los «·». Las excepciones se declaran por separado, con su
   propia especificidad, y no metiendo un `:not()` en la regla general. */
.tss-footer .tss-logo{ display:inline-block; padding:0; }
.tss-footer .tss-logo{ margin-bottom:14px; }
.tss-footer .tss-placeholder{ display:inline; }

.tss-placeholder{ color:var(--tss-blau); font-style:italic; }
/* Dato legal que falta. Estilo PROPIO y no heredado: `.tss-placeholder` solo recibe el fondo
   amarillo dentro de `.tss-pagina`, y las páginas legales usan otra plantilla, así que el aviso
   salía en azul cursiva y se confundía con un enlace (medido en producción). Y este aviso existe
   justamente para que NO se pueda pasar por alto que una página legal está incompleta.
   #7a5c00 sobre #fff3cd da 5,65:1, por encima del 4,5:1 de AA. */
.tss-pendiente-legal{ background:#fff3cd; color:#7a5c00; font-style:normal; font-weight:700; padding:1px 6px; border-radius:3px; box-decoration-break:clone; }

/* ---------- Página de servicio + carrusel (Galería editable) ---------- */
.tss-pagina{ padding:56px 24px 80px; }
.tss-pagina .wp-block-post-title{ color:var(--tss-dark); font-size:clamp(1.6rem,3.6vw,2.2rem); margin:0 0 28px; border-bottom:3px solid var(--tss-blau); display:inline-block; padding-bottom:8px; }
.tss-pagina p{ color:var(--tss-text); line-height:1.7; margin-bottom:16px; }
.tss-pagina h2{ margin-top:36px; margin-bottom:12px; font-size:1.3rem; }
.tss-pagina ul{ margin:0 0 16px 20px; }
.tss-pagina li{ margin-bottom:8px; line-height:1.6; }
.tss-pagina table{ width:100%; border-collapse:collapse; margin:16px 0; }
.tss-pagina th,.tss-pagina td{ padding:8px 10px; border:1px solid var(--tss-vora); text-align:left; font-size:.92rem; }
.tss-pagina th{ background:var(--tss-gris-clar); }
.tss-pagina .tss-placeholder{ background:#fff3cd; padding:1px 4px; border-radius:3px; }

.tss-servicio{ padding:56px 24px 72px; }
.tss-servicio .wp-block-post-title{ color:var(--tss-dark); font-size:clamp(1.8rem,4vw,2.6rem); margin:0 0 8px; border-bottom:3px solid var(--tss-blau); display:inline-block; padding-bottom:6px; text-transform:uppercase; }
.tss-servicio p{ color:var(--tss-text); font-size:1.05rem; max-width:820px; }
.tss-car-wrap{ position:relative; margin-top:28px; }
.tss-servicio .wp-block-gallery{ display:flex !important; flex-wrap:nowrap !important; gap:14px; overflow-x:auto; scroll-snap-type:x mandatory; padding-bottom:10px; margin:0; }
.tss-servicio .wp-block-gallery .wp-block-image{ flex:0 0 min(86%,700px); scroll-snap-align:center; margin:0; }
.tss-servicio .wp-block-gallery .wp-block-image img{ width:100%; height:440px; object-fit:cover; border-radius:var(--tss-radi); }
.tss-car-btn{ position:absolute; top:calc(50% - 22px); width:44px; height:44px; border:none; border-radius:50%; background:rgba(15,19,25,.75); color:#fff; font-size:1.6rem; line-height:1; cursor:pointer; z-index:2; transition:background-color .18s ease-out, transform .12s ease-out; }
.tss-car-btn:hover{ background:var(--tss-blau); }
/* Igual que en la rejilla: sin `:active` el carrusel no daba ninguna respuesta al toque. */
.tss-car-btn:active{ background:var(--tss-blau); transform:scale(.94); }
.tss-car-prev{ left:8px; } .tss-car-next{ right:8px; }
@media(max-width:860px){ .tss-servicio .wp-block-gallery .wp-block-image img{ height:280px; } }

/* ---------- Responsive ---------- */
@media(max-width:860px){
  .tss-nav-links{ display:none; }
  .tss-cards{ grid-template-columns:1fr; }
  .tss-quisom-grid{ grid-template-columns:1fr; gap:28px; }
  .tss-contacte-grid{ grid-template-columns:1fr; }
  .tss-hero{ padding:64px 0 72px; }
  .tss-section{ padding:56px 0; }
  .tss-footer-cols{ grid-template-columns:1fr!important; gap:24px; }
  /* Cabecera móvil: el logo + CTA + selector deben caber en una línea sin apretarse
     ni partir el texto del botón (se veía "Llama / ahora" en 2 líneas). */
  .tss-header .tss-wrap{ gap:10px!important; }
  .tss-logo{ width:132px; height:38px; }
  .tss-nav{ gap:10px; }
  /* Compacto para que quepa en la cabecera, pero con 44px de alto exactos: medido con el
     navegador se quedaba en 34px, por debajo del objetivo táctil recomendado. El alto lo da
     `min-height` y NO el padding vertical — con los dos a la vez se iba a 62px. */
  .tss-nav > .tss-btn{ padding:0 14px; font-size:.85rem; min-height:44px; }
  /* Ya NO se ajusta aquí el relleno de los enlaces del pie.
     Esta regla ponía `padding:8px 0` y, al tener la misma especificidad que `.tss-footer a`
     pero ir después, la pisaba: los enlaces medían 39,8px en móvil —justo donde más importa el
     área táctil— mientras en escritorio sí llegaban a 44 (medido con el navegador). La regla
     general ya deja los 44px en los dos anchos, así que sobra la excepción. */
}

/* Selector de idioma: bandera + código, en una píldora por idioma (bloque tss/idiomas).
   Sustituye a los dos enlaces de texto separados por una raya, que se leían como parte del menú.
   Con la bandera se identifica de un vistazo sin tener que leer. */
.tss-idiomas{ display:flex!important; align-items:center; gap:6px; list-style:none!important; margin:0!important; padding:0!important; }
.tss-idiomas li{ list-style:none!important; margin:0!important; }
.tss-idiomas a{
  display:flex; align-items:center; gap:6px;
  /* 44px de alto real: es un objetivo táctil, y en el móvil queda pegado al menú. */
  min-height:44px; padding:0 10px; border-radius:8px;
  color:#a9b7c4; font-size:.8rem; font-weight:700; letter-spacing:.03em;
  transition:background-color .18s ease-out, color .18s ease-out;
}
.tss-idiomas a:hover{ background:rgba(255,255,255,.10); color:#fff; }
/* El idioma activo NO se distingue solo por el color: lleva además el fondo azul de marca y
   `aria-current` en el HTML, que es lo que anuncia un lector de pantalla. */
.tss-idioma--actual a{ background:var(--tss-blau); color:#fff; }
.tss-idioma--actual a:hover{ background:var(--tss-blau-fosc, #0045a5); color:#fff; }
.tss-idioma__bandera{
  width:21px; height:14px; display:block; border-radius:2px;
  /* Filo sutil: sobre la cabecera oscura, el amarillo de las dos banderas se funde con el borde. */
  box-shadow:0 0 0 1px rgba(255,255,255,.35);
}
.tss-idioma__codigo{ line-height:1; }

@media (max-width:640px){
  /* En el móvil manda el espacio: se queda la bandera, que es lo que se reconoce sin leer.
     El nombre del idioma sigue estando en el `aria-label`, así que no se pierde para nadie. */
  .tss-idiomas a{ padding:0 8px; }
  .tss-idioma__codigo{ display:none; }
}

/* ---------- Anuncios (render público, plugin tss-anuncios) ---------- */
/* Barra superior: cinta fina sobre la cabecera, con el anuncio de mayor prioridad. */
.tss-anuncio-bar{ background:var(--tss-blau); color:#fff; }
/* El relleno de la cinta baja de 9px a 6px para compensar que el CTA pasa a medir 44px de
   alto: la cinta se queda en 56px en total, que sigue siendo una cinta fina. */
.tss-anuncio-bar__wrap{ display:flex; align-items:center; justify-content:center; gap:16px; flex-wrap:wrap; padding-top:6px; padding-bottom:6px; text-align:center; }
.tss-anuncio-bar__texto{ font-weight:600; font-size:.95rem; }
/* 44px de alto reales (antes 31,75px, un 28% por debajo). Este CTA aparecerá SOBRE la cabecera
   de todas las páginas en cuanto el cliente publique un anuncio en esa ubicación, y esas
   cintas suelen llevar ofertas con caducidad: conviene que el toque sea fácil. Se arregla
   ahora, antes de que haya un anuncio publicado con el que estrenarlo. */
.tss-anuncio-bar__cta{ display:inline-flex; align-items:center; min-height:44px; background:#fff; color:var(--tss-blau); font-weight:700; font-size:.85rem; padding:0 16px; border-radius:6px; white-space:nowrap; transition:background-color .18s ease-out, color .18s ease-out; }
.tss-anuncio-bar__cta:hover{ background:var(--tss-dark); color:#fff; }
.tss-anuncio-bar__cta:active{ background:var(--tss-dark); color:#fff; }

/* Tarjetas (home_slider, lateral, global): tira de tarjetas centradas. */
.tss-anuncios{ max-width:var(--tss-max); margin-inline:auto; padding:36px 24px 0; display:grid; grid-template-columns:repeat(auto-fit,minmax(280px,1fr)); gap:24px; }
/* Sin sombra permanente, igual que `.tss-card`: en reposo, borde. Había dos lenguajes de
   elevación para el mismo patrón de tarjeta —`.tss-card` se eleva al pasar el ratón y esta
   aparecía siempre elevada y estática—, y encima al revés de lo que toca: la que parecía
   elevada (señal de "esto responde") es precisamente la que NO es clicable como bloque
   (confirmado en Render.php: el enlace es solo el CTA). La elevación se reserva para lo que
   reacciona. */
.tss-anuncio-card{ background:#fff; border:1px solid var(--tss-vora); border-radius:var(--tss-radi); overflow:hidden; display:flex; flex-direction:column; }
.tss-anuncio-card__img{ height:170px; background-size:cover; background-position:center; }
.tss-anuncio-card__cuerpo{ padding:22px 24px; display:flex; flex-direction:column; gap:10px; flex:1; }
.tss-anuncio-card__titulo{ font-size:1.2rem; color:var(--tss-dark); }
.tss-anuncio-card__texto{ color:var(--tss-gris); font-size:.98rem; }
.tss-anuncio-card__cta{ align-self:flex-start; margin-top:auto; }
@media(max-width:860px){ .tss-anuncios{ grid-template-columns:1fr; } }

/* ---------- Formulario de contacto (tss-core, ContactForm) ---------- */
.tss-contact-form-box{ background:var(--tss-gris-clar); padding:28px; border-radius:var(--tss-radi); }
.tss-contact-form-box__titulo{ margin-bottom:14px; font-weight:800; color:var(--tss-dark); }
.tss-contact-form{ display:flex; flex-direction:column; gap:14px; }
.tss-field{ display:flex; flex-direction:column; gap:5px; font-size:.9rem; font-weight:600; color:var(--tss-dark); }
/* `font-size:1rem` EXPLÍCITO, nunca `font:inherit`.
   `.tss-field` fija .9rem para la etiqueta, así que con `font:inherit` el campo heredaba ese
   .9rem = 14,4px. Safari en iOS hace zoom automático a cualquier campo con menos de 16px: al
   tocar «Nombre» la página saltaba y se quedaba desencuadrada, y en un formulario de contacto
   que se rellena casi siempre desde el móvil eso es la primera impresión del sitio.
   `min-height:44px` es la misma área de toque del resto del sitio. */
.tss-field input, .tss-field textarea{ font-family:inherit; font-size:1rem; font-weight:400; padding:11px 13px; min-height:44px; border:1px solid var(--tss-vora); border-radius:8px; background:#fff; color:var(--tss-text); transition:border-color .15s ease-out; }
/* Mismo anillo de foco que el resto del sitio (3px + 2px de separación): antes el formulario
   usaba 2px sin separación, y dos tratamientos distintos de foco en la misma página hacen que
   se note que las piezas vienen de sitios diferentes. */
.tss-field input:focus-visible, .tss-field textarea:focus-visible{ outline:3px solid var(--tss-blau); outline-offset:2px; border-color:var(--tss-blau); }
.tss-field textarea{ resize:vertical; min-height:110px; }
/* El texto de la etiqueta y su marcador van juntos en este <span>. `.tss-field` es un flex en
   columna, así que un hijo directo ocupa una fila entera: con el asterisco suelto salía en su
   propia línea debajo del texto (visto en el navegador). */
.tss-field__label{ display:block; }
.tss-field__req{ color:var(--tss-blau); font-weight:700; margin-left:3px; }
.tss-field__opt{ color:var(--tss-gris); font-weight:400; font-size:.82rem; margin-left:5px; }
/* Error JUNTO al campo (no solo un aviso genérico arriba) y con el borde marcado. */
.tss-field__error{ display:none; font-weight:600; font-size:.82rem; color:var(--tss-error); }
.tss-field--error .tss-field__error{ display:block; }
.tss-field--error input, .tss-field--error textarea{ border-color:var(--tss-error); }
/* El borde de error gana también con el campo enfocado: `.tss-field input:focus-visible` tiene
   más especificidad que `.tss-field--error input`, así que al entrar a corregir el campo el
   borde volvía a azul y se perdía la señal de error justo cuando hace falta. El foco se sigue
   viendo por su anillo (`outline`), que es su trabajo. */
.tss-field--error input:focus-visible, .tss-field--error textarea:focus-visible{ border-color:var(--tss-error); }
/* `row` explícito: la casilla va AL LADO del texto, no encima. */
.tss-consent{ display:flex; flex-direction:row; align-items:flex-start; gap:10px; font-size:.85rem; color:#4b5563; line-height:1.5; font-weight:400; }
.tss-consent__texto{ flex:1; }
/* 24x24 como mínimo: WCAG 2.5.8 (nivel AA) exige ese tamaño de objetivo, y la casilla se había
   quedado en 17px. El `min-width` evita que flex la comprima por debajo. */
.tss-consent input{ margin-top:1px; flex-shrink:0; accent-color:var(--tss-blau); width:24px; height:24px; min-width:24px; }
/* Error del consentimiento con su propia clase: no se puede reutilizar `.tss-field--error`
   porque `.tss-field` cambia la dirección del flex y volvería a apilar la casilla. */
.tss-consent.tss-error .tss-consent__texto{ color:var(--tss-error); }
.tss-consent .tss-field__error{ margin-top:4px; }
/* Azul oscuro: el formulario va sobre --tss-gris-clar y ahí el azul de marca da 4,20:1, por
   debajo del 4,5:1 de AA. Y este enlace concreto es el de la política de privacidad que el
   usuario acepta, así que tiene que poder leerlo. Con el oscuro sube a 8,17:1. */
.tss-consent a{ color:var(--tss-blau-fosc); text-decoration:underline; }
.tss-contact-form .tss-btn{ align-self:flex-start; border:none; cursor:pointer; }
.tss-hp{ position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden; }
.tss-form-aviso{ padding:13px 16px; border-radius:8px; margin-bottom:16px; font-size:.95rem; }
.tss-form-aviso--ok{ background:var(--tss-ok-fons); color:var(--tss-ok); border:1px solid var(--tss-ok-vora); }
.tss-form-aviso--error{ background:var(--tss-error-fons); color:var(--tss-error); border:1px solid var(--tss-error-vora); }

/* ---------- Iconos SVG (guía de diseño: SVG, no emojis) ---------- */
.tss-ico-svg{ width:22px; height:22px; display:block; flex:none; }
.tss-contact-item .tss-dot .tss-ico-svg{ width:22px; height:22px; }
.tss-btn .tss-ico-svg{ width:20px; height:20px; }
.tss-btn-whatsapp{ background:#25d366; color:#fff; }
.tss-btn-whatsapp:hover{ background:#1da851; color:#fff; }
.tss-footer-zona{ display:block; color:#8a97a7; }
/* `row-reverse`: el botón PRIMARIO va primero en el HTML (para el lector de pantalla y el
   orden de tabulación, que deben empezar por la acción importante), pero visualmente «volver»
   se coloca a la izquierda, que es donde se espera. */
.tss-servicio-acciones{ display:flex; flex-direction:row-reverse; justify-content:flex-end; flex-wrap:wrap; gap:12px; margin-top:32px; }
/* Fila inferior del pie: `inline-block` y no `inline`, para que el relleno vertical cuente y
   los enlaces dejen de medir 18px de alto. Siguen en la misma línea, así que los "·" no se
   parten. Son precisamente Aviso legal, Privacidad y Cookies: los tres enlaces obligatorios y
   los más pequeños de todo el sitio. Con este relleno pasan a ~44px. */
.tss-footer-bottom a{ display:inline-block; padding:11px 8px; line-height:22px; }
.tss-footer-bottom a:hover{ color:#fff; }
/* (Aquí había un apaño para darle 44px de área de toque al selector de idioma antiguo, que eran
   dos enlaces de texto: un ::after invisible que extendía la zona sensible sin mover el subrayado
   del idioma activo. El selector nuevo, `.tss-idiomas`, mide 44px de verdad con `min-height`, así
   que el apaño sobra y se ha quitado.) */

/* ---------- Accesibilidad: foco visible por teclado (guía de diseño) ---------- */
a:focus-visible, button:focus-visible, .tss-btn:focus-visible,
input:focus-visible, textarea:focus-visible, select:focus-visible{
  outline:3px solid var(--tss-blau);
  outline-offset:2px;
  border-radius:4px;
}

/* ---------- Accesibilidad: respetar reduced-motion (guía de diseño) ---------- */
@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
    scroll-behavior:auto !important;
  }
}
