
  /* El `@import` a Google Fonts se retira: Playfair y Manrope ya van
   auto-alojadas en tokens.css y la landing no hace peticiones externas. Es el
   único cambio sobre el CSS de este entregable. */

  /* ============================================================
     Componente aislado bajo .rh-pillars para poder integrarse
     en cualquier web sin colisionar con estilos existentes.
     ============================================================ */

  .rh-pillars, .rh-pillars * { box-sizing: border-box; }

  .rh-pillars {
    --rh-navy-900: #001a33;
    --rh-navy-700: #003866;
    --rh-white: #ffffff;
    --rh-line: rgba(255, 255, 255, .38);
    --rh-line-soft: rgba(255, 255, 255, .16);
    --rh-text-dim: rgba(255, 255, 255, .72);
    --rh-text-faint: rgba(255, 255, 255, .5);
    --font-display: 'Playfair Display', Georgia, serif;
    --font-body: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    --rh-ease: cubic-bezier(.22, .61, .36, 1);

    position: relative;
    isolation: isolate;
    background:
      radial-gradient(ellipse 70% 60% at 82% 78%, var(--rh-navy-700) 0%, transparent 62%),
      var(--rh-navy-900);
    color: var(--rh-white);
    font-family: var(--font-body);
    padding: clamp(2.5rem, 6vw, 5rem) clamp(1.25rem, 5vw, 4rem);
    overflow: hidden;
    display: grid;
    /* Dos columnas flexibles iguales (1fr … 1fr) a los lados del diagrama:
       así el diagrama queda centrado en el espacio disponible exactamente
       igual que antes, pero la izquierda —el conector— siempre mide lo
       mismo que ese hueco de centrado, así que la línea llega justo hasta
       el borde del diagrama (el anillo exterior) sin dejar hueco muerto. */
    grid-template-columns: auto 1fr min(640px, 100%) 1fr;
    align-items: center;
    gap: 0;
    min-height: 640px;
  }

  @media (prefers-reduced-motion: reduce) {
    .rh-pillars * { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
  }

  /* ---------- Título ---------- */

  .rh-titleblock {
    display: flex;
    align-items: center;
    gap: clamp(1rem, 2.5vw, 2rem);
    height: 100%;
  }

  .rh-title {
    font-family: var(--font-display);
    font-weight: 500;
    font-size: clamp(2rem, 4.2vw, 3.4rem);
    line-height: 1.25;
    letter-spacing: 0.005em;
    margin: 0;
    white-space: nowrap;
    writing-mode: vertical-rl;
    transform: rotate(180deg);
  }

  .rh-title-connector {
    /* Sin "width:100%" a propósito: como elemento de grid se estira por
       defecto (justify-self: stretch) para llenar su columna, y ese
       estirado YA descuenta el margin-left. Si se fuerza width:100% además
       del margen, el margen se suma aparte y la línea se desborda dentro
       de la columna del diagrama, "atravesando" varios anillos. */
    height: 1px;
    background: var(--rh-line);
    align-self: center;
    margin-left: clamp(1rem, 2.5vw, 2rem);
  }

  /* ---------- Diagrama ---------- */

  .rh-diagram-wrap {
    position: relative;
    width: 100%;
  }

  .rh-diagram {
    position: relative;
    width: min(100%, 640px);
    aspect-ratio: 1 / 1;
  }

  .rh-rings-svg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
  }

  .rh-ring {
    fill: none;
    stroke: var(--rh-line-soft);
    stroke-width: 1;
    vector-effect: non-scaling-stroke;
    transition: opacity .5s var(--rh-ease), stroke-width .5s var(--rh-ease), filter .5s var(--rh-ease);
  }

  .rh-diagram.is-active .rh-ring:not(.is-active) { opacity: .18; }

  /* El anillo 1 contiene siempre el texto del panel, así que no se atenúa
     tanto como el resto (para que el panel nunca quede sin contorno
     visible), pero tampoco a opacidad plena: los anillos con radio cercano
     (p.ej. el 2, justo al lado) quedarían leyéndose como "dos anillos
     encendidos" al iluminarse junto a este. */
  .rh-diagram.is-active .rh-ring--inner:not(.is-active) { opacity: .4; }

  .rh-ring.is-active {
    stroke: var(--rh-white);
    stroke-width: 2;
    filter: drop-shadow(0 0 6px rgba(255, 255, 255, .85)) drop-shadow(0 0 14px rgba(255, 255, 255, .35));
  }

  /* ---------- Nodos (botones de pilar) ---------- */

  .rh-node {
    all: unset;
    position: absolute;
    z-index: 3;
    top: var(--y);
    left: var(--x);
    transform: translate(-50%, -50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .5rem;
    cursor: pointer;
    padding: .35rem;
    border-radius: 999px;
    opacity: 1;
    transition: opacity .4s var(--rh-ease), transform .3s var(--rh-ease);
  }

  /* Los iconos solo se muestran en la pantalla principal. Al entrar en la
     pantalla de un pilar se ocultan los OTROS 7 —el del pilar activo se
     mantiene visible, como referencia de dónde está dentro del conjunto.
     Se ocultan con opacity en vez de display:none para que el tabulado
     por teclado entre pilares se mantenga aunque no se vean. */
  .rh-diagram.is-active .rh-node:not(.is-active) {
    opacity: 0;
    pointer-events: none;
  }

  .rh-node-icon {
    width: clamp(38px, 6.2vw, 52px);
    height: clamp(38px, 6.2vw, 52px);
    border-radius: 50%;
    background: var(--rh-white);
    color: var(--rh-navy-900);
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    transition: box-shadow .3s var(--rh-ease), transform .3s var(--rh-ease);
  }

  .rh-node-icon svg { width: 55%; height: 55%; }

  .rh-node:hover .rh-node-icon,
  .rh-node:focus-visible .rh-node-icon {
    transform: scale(1.08);
  }

  /* En escritorio (donde el hover tiene sentido) los iconos reposan al 80%
     de opacidad y suben al 100% al pasar el cursor por encima. */
  @media (hover: hover) and (pointer: fine) {
    .rh-node-icon {
      opacity: .8;
      transition: box-shadow .3s var(--rh-ease), transform .3s var(--rh-ease), opacity .3s var(--rh-ease);
    }

    .rh-node:hover .rh-node-icon,
    .rh-node:focus-visible .rh-node-icon,
    .rh-diagram.is-active .rh-node.is-active .rh-node-icon {
      opacity: 1;
    }
  }

  .rh-diagram.is-active .rh-node.is-active .rh-node-icon {
    box-shadow: 0 0 0 6px rgba(255, 255, 255, .14), 0 0 16px rgba(255, 255, 255, .55);
  }

  /* El texto de cada icono es dinámico: se ve antes de pulsar, y al pulsar
     ese icono (queda "is-active") se oculta su etiqueta, dejando solo el
     icono como referencia de qué pilar está abierto. */
  .rh-node.is-active .rh-node-label {
    display: none;
  }

  .rh-node:focus-visible {
    outline: 2px solid var(--rh-white);
    outline-offset: 4px;
  }

  .rh-node-label {
    font-size: clamp(.72rem, 1.15vw, .9rem);
    font-weight: 700;
    letter-spacing: .01em;
    white-space: nowrap;
    text-shadow: 0 1px 6px rgba(0, 0, 0, .5);
  }

  /* ---------- Panel central ---------- */

  /* El tamaño del panel se fija en JS (variable --ring1-diameter) a partir
     del radio real del anillo 1, para que coincidan exactamente y el
     panel NUNCA dibuje su propio borde/círculo: el límite visual que se ve
     es el propio anillo 1 (uno de los 8 círculos del SVG), no una novena
     línea añadida aparte. */
  .rh-center {
    position: absolute;
    z-index: 2;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: var(--ring1-diameter, 60%);
    height: var(--ring1-diameter, 60%);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    /* El padding va en % (no en px fijos) para que, sea cual sea el
       tamaño real del anillo 1, la esquina del rectángulo de texto nunca
       pueda salirse del círculo: un % de este valor garantiza igual
       proporción de seguridad en cualquier resolución (mismo razonamiento
       que en móvil, ver esa media query). En escritorio el anillo 1 es
       más pequeño en relación al diagrama que en móvil, así que ~11% del
       diagrama ya deja un margen de seguridad amplio respecto al 14.6%
       mínimo necesario. */
    padding: 11%;
    /* El panel no debe interceptar clics fuera de su propio texto/scroll. */
    pointer-events: none;
    /* Red de seguridad: si aun así algo llegara a sobrar (caso extremo),
       que lo recorte el propio borde circular en vez de que el anillo se
       dibuje por encima del texto. */
    overflow: hidden;
  }

  .rh-center-intro {
    font-family: var(--font-body);
    font-weight: 300;
    font-size: clamp(1.4rem, 3.4vw, 2.1rem);
    line-height: 1.2;
    margin: 0;
  }

  .rh-center-hint {
    display: inline-block;
    margin-top: .6em;
    max-width: 100%;
    overflow-wrap: break-word;
    font-family: var(--font-body);
    font-weight: 400;
    font-size: clamp(.725rem, 1.6vw, .925rem);
    line-height: 1.3;
    color: #5ca6ff;
  }

  .rh-panel {
    display: none;
    flex-direction: column;
    align-items: center;
    /* Centrado por defecto: con el anillo 1 ya dimensionado para que el
       texto quepa entero, lo normal es que sobre espacio y debe repartirse
       arriba y abajo, no quedar todo pegado arriba. Si algún caso extremo
       no cupiera (pantallas diminutas), se cambia a flex-start desde JS
       (clase .has-overflow) para permitir scroll sin recortar el inicio
       del texto —centrar contenido que desborda con scroll corta el
       principio en vez de dejarlo alcanzable—. */
    justify-content: center;
    gap: calc(.3rem * var(--rh-fit, 1));
    width: 100%;
    height: 100%;
    align-self: stretch;
    min-height: 0;
    overflow-y: auto;
    /* El scroll sigue funcionando (rueda, gesto táctil, teclado); solo se
       oculta la barra visual para no interferir con el círculo. */
    scrollbar-width: none;
  }

  .rh-panel.is-visible { display: flex; pointer-events: auto; }

  .rh-panel::-webkit-scrollbar { display: none; }

  /* Excepción: en Acción Social sí se muestra la barra de scroll (a
     petición expresa), a diferencia del resto de pilares donde queda
     oculta. */
  .rh-panel.rh-panel--show-scrollbar {
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, .35) transparent;
  }

  .rh-panel.rh-panel--show-scrollbar::-webkit-scrollbar {
    display: block;
    width: 4px;
  }

  .rh-panel.rh-panel--show-scrollbar::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, .35);
    border-radius: 4px;
  }

  /* Si el contenido no cabe entero, se avisa con un desvanecido inferior en
     vez de cortar el texto en seco; el contenido sigue siendo accesible
     haciendo scroll (rueda, gesto táctil o teclado). También se pasa a
     alinear arriba (ver JS) para que el scroll llegue de verdad al inicio. */
  .rh-panel.has-overflow {
    justify-content: flex-start;
    mask-image: linear-gradient(to bottom, #000 82%, transparent 100%);
    -webkit-mask-image: linear-gradient(to bottom, #000 82%, transparent 100%);
  }

  /* El desvanecido solo tiene sentido mientras queda contenido por debajo
     al que hacer scroll: es un aviso de "hay más texto", no una cortina
     permanente. Al llegar al final del scroll (clase .at-bottom, ver JS)
     se quita del todo, para que las últimas líneas se lean con opacidad
     completa en vez de quedar siempre desvanecidas. */
  .rh-panel.has-overflow.at-bottom {
    mask-image: none;
    -webkit-mask-image: none;
  }

  /* Ninguna palabra se parte nunca: el texto solo envuelve en los espacios.
     Cuando una palabra larga (p.ej. "Internacionalización") no cabe a lo
     ancho, no se corta con guion ni se rompe a mitad: es el ajuste
     automático --rh-fit el que reduce el tamaño hasta que la palabra entra
     entera (ver fitPanel() en el JS). */
  .rh-panel-title,
  .rh-panel-estrella,
  .rh-stat-value,
  .rh-stat-label {
    overflow-wrap: normal;
    word-break: normal;
    hyphens: none;
    max-width: 100%;
  }

  /* Último recurso, solo si el ajuste automático llegara a su suelo y aun
     así la palabra no cupiera (pantallas minúsculas): antes que dejar que el
     texto se salga del círculo, se permite partirla. En la práctica no
     debería activarse nunca. */
  .rh-panel.allow-break .rh-panel-title,
  .rh-panel.allow-break .rh-panel-estrella,
  .rh-panel.allow-break .rh-stat-value,
  .rh-panel.allow-break .rh-stat-label {
    overflow-wrap: break-word;
  }

  /* --rh-fit es el factor de ajuste automático que calcula el JS para que el
     contenido de CADA pilar quepa entero dentro del círculo sin barra de
     desplazamiento (ver fitPanel()). Vale 1 siempre que el texto ya cabe
     —el caso de escritorio—, así que allí el resultado es idéntico al de
     antes; en móvil baja solo lo justo. */
  .rh-panel-title {
    font-family: var(--font-body);
    font-weight: 700;
    font-size: clamp(1.05rem, 2.1vw, 1.35rem);
    line-height: 1.15;
    margin: 0;
  }

  .rh-panel-estrella {
    font-weight: 400;
    font-size: clamp(.9rem, 1.7vw, 1.1rem);
    line-height: 1.35;
    color: var(--rh-text-dim);
    margin: 0;
  }

  /* Fila de datos destacados: uno junto al otro, separados por una línea
     vertical, con la cifra a un tamaño claramente mayor que el resto del
     panel (igual que en el boceto). */
  .rh-panel-stats {
    display: flex;
    align-items: stretch;
    flex-wrap: nowrap;
    justify-content: center;
    gap: calc(.3rem * var(--rh-fit, 1)) 0;
    margin-top: calc(clamp(.75rem, 2.2vw, 1.25rem) * var(--rh-fit, 1));
    width: 100%;
  }

  /* Cuando hay 3 datos de apoyo (p.ej. Internacionalización), se permite
     que la fila envuelva en pantallas estrechas en vez de comprimirse
     hasta ser ilegible. */
  .rh-panel-stats.rh-panel-stats--triple {
    flex-wrap: wrap;
    /* Más separación entre filas que entre columnas: sin líneas divisorias
       en este caso (ver más abajo), el aire entre filas es lo único que
       distingue un dato del siguiente cuando envuelven. */
    gap: calc(.6rem * var(--rh-fit, 1)) 0;
  }

  /* "flex-start" (no "center") a propósito: cuando una etiqueta es más
     larga que la de al lado y envuelve más líneas (p.ej. "tesis defendidas
     (95% con...)" junto a "doctorandos"), centrar cada columna por separado
     deja las cifras a alturas distintas. Alineando arriba, todas las
     cifras quedan siempre a la misma altura sin importar cuánto envuelva
     la etiqueta de al lado. */
  .rh-stat {
    flex: 1 1 0;
    min-width: calc(4.8rem * var(--rh-fit, 1));
    padding: 0 calc(.6rem * var(--rh-fit, 1));
    border-left: 1px solid var(--rh-line);
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
  }

  /* En escritorio los 3 datos caben en una sola fila. Solo se marca la
     separación entre el 1º y el 2º (como en el boceto original); el 3º no
     lleva línea a su izquierda para no duplicar el divisor. En móvil se
     quita también la del 2º (ver media query): ahí puede envolver de forma
     impredecible y el divisor queda "colgado" en el dato equivocado. */
  .rh-panel-stats--triple .rh-stat {
    flex: 1 1 auto;
    min-width: calc(4.4rem * var(--rh-fit, 1));
  }

  .rh-panel-stats--triple .rh-stat:nth-child(3) { border-left: none; }

  .rh-stat:first-child { border-left: none; }

  /* A partir de 4 datos (p.ej. Internacionalización ampliada) el hack del
     3er elemento a ancho completo ya no tiene sentido: se pasa a una
     cuadrícula regular de 2 columnas, sin líneas divisorias, con las
     cifras alineadas arriba igual que en el resto de casos. */
  .rh-panel-stats--grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: calc(.7rem * var(--rh-fit, 1)) calc(.6rem * var(--rh-fit, 1));
  }

  .rh-panel-stats--grid .rh-stat {
    border-left: none;
    min-width: 0;
    padding: 0 calc(.3rem * var(--rh-fit, 1));
  }

  /* Con un número impar de datos (p.ej. 3 ó 5), el último quedaría solo en
     su fila ocupando solo la mitad izquierda: en vez de eso, se le da el
     ancho completo y se centra, para que no parezca descolocado. */
  .rh-panel-stats--grid.rh-panel-stats--odd .rh-stat:last-child {
    grid-column: 1 / -1;
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  /* Excepción puntual (Acción Social): línea divisoria entre el 1º y 2º
     dato, como en el diseño original de "3 datos" pero aplicada aquí
     sobre el layout de cuadrícula. */
  .rh-panel-stats--grid.rh-panel-stats--divide-first .rh-stat:nth-child(2) {
    border-left: 1px solid var(--rh-line);
  }

  /* Excepción puntual (Internacionalización): una única línea vertical
     continua de arriba a abajo entre las dos columnas, en vez de un
     borde repetido por fila (que dejaba huecos entre filas). Se usa un
     pseudo-elemento en vez de border-left para que no se corte nunca. */
  .rh-panel-stats--grid.rh-panel-stats--divide-all {
    position: relative;
  }

  .rh-panel-stats--grid.rh-panel-stats--divide-all::before {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: calc(50% + 4px);
    width: 1px;
    background: var(--rh-line);
  }

  .rh-stat-value {
    display: block;
    font-weight: 400;
    font-size: clamp(1.4rem, 3.4vw, 2rem);
    line-height: 1.05;
    color: #5ca6ff;
  }

  .rh-stat-label {
    display: block;
    font-size: 15px;
    line-height: 1.22;
    color: var(--rh-text-faint);
    margin-top: calc(.2rem * var(--rh-fit, 1));
  }

  /* ---------- Botón cerrar ---------- */

  .rh-close {
    all: unset;
    position: absolute;
    z-index: 4;
    top: 2%;
    right: 2%;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    display: none;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    color: var(--rh-white);
    border: 1px solid var(--rh-line);
    transition: background .25s var(--rh-ease), transform .25s var(--rh-ease);
  }

  .rh-close.is-visible { display: flex; }

  .rh-close:hover { background: rgba(255, 255, 255, .1); transform: rotate(90deg); }

  .rh-close:focus-visible {
    outline: 2px solid var(--rh-white);
    outline-offset: 3px;
  }

  .rh-close svg { width: 14px; height: 14px; }

  /* ---------- Responsive: móvil ---------- */

  @media (max-width: 720px) {
    .rh-pillars {
      grid-template-columns: 1fr;
      grid-template-rows: auto auto auto;
      gap: 1.25rem;
      min-height: 0;
      padding: 2rem 1.1rem 2.75rem;
    }

    .rh-titleblock {
      flex-direction: column;
      align-items: flex-start;
      gap: .75rem;
      height: auto;
    }

    .rh-title {
      writing-mode: horizontal-tb;
      transform: none;
      font-size: clamp(1.9rem, 8vw, 2.5rem);
      line-height: 1.15;
      white-space: normal;
      max-width: 12ch;
    }

    .rh-title-connector {
      display: none;
    }

    .rh-right-spacer { display: none; }

    .rh-node-label { display: none; }

    .rh-node { gap: 0; }

    /* En móvil el círculo dispone de menos espacio absoluto que en
       escritorio, así que la base de espaciado (antes de cualquier ajuste
       de --rh-fit) ya parte más ajustada aquí. */
    .rh-panel {
      gap: calc(.2rem * var(--rh-fit, 1));
    }

    .rh-panel-stats {
      margin-top: calc(.5rem * var(--rh-fit, 1));
    }

    /* Tamaños fijos para los textos del panel en móvil (en vez de la escala
       fluida de escritorio): título 18px/bold, frase 16px/regular, cifra
       20px. Se mantienen multiplicados por --rh-fit para conservar la red
       de seguridad que evita el desbordamiento en el pilar con más texto o
       en pantallas muy estrechas; con el anillo 1 ya agrandado, en la
       práctica --rh-fit se queda en 1 y el tamaño real es el indicado. */
    /* Tamaños fijos e iguales en todos los pilares: título 18px/bold,
       frase 16px/regular, cifra 20px. Ya NO dependen de --rh-fit (ese
       factor solo comprime espaciados si el contenido no cabe, nunca la
       letra), para que ningún pilar se vea con texto más pequeño que
       otro. */
    .rh-panel-title {
      font-size: 18px;
      font-weight: 700;
    }

    .rh-panel-estrella {
      font-size: 15px;
      font-weight: 400;
    }

    .rh-stat-value {
      font-size: 20px;
    }

    .rh-stat-label {
      font-size: 15px;
    }

    /* El panel mantiene el mismo tamaño (el del anillo 1) en todos los
       anchos, para que el límite del contenido no se desalinee del SVG. En
       móvil el círculo es más pequeño en píxeles reales, así que un padding
       fijo (el de escritorio) deja el texto demasiado cerca del borde y
       puede llegar a las esquinas del cuadrado que hay debajo del círculo
       (ver overflow:hidden en la regla base). Con % (que se resuelve
       contra .rh-diagram, el mismo contenedor del que depende
       --ring1-diameter) el padding guarda siempre la misma proporción
       respecto al diámetro real, sea cual sea el tamaño de pantalla: 11%
       de .rh-diagram equivale a ≈15.7% del diámetro del círculo, por
       encima del 14.6% mínimo necesario para que ninguna esquina del
       texto pueda salirse de él. */
    .rh-center { padding: 11%; }

    /* Con 3 datos, en móvil el reparto deja de depender del envuelto (que
       era impredecible: a veces 1+1+1, a veces 2+1 con el tercero estirado).
       Se pasa a una rejilla explícita de 2 columnas: los dos primeros datos
       SIEMPRE en paralelo y, por "align-items: start", con sus cifras
       exactamente a la misma altura aunque una etiqueta ocupe más líneas
       que la otra; el tercero ocupa la fila de abajo entera, centrado. */
    .rh-panel-stats--triple {
      display: grid;
      grid-template-columns: 1fr 1fr;
      align-items: start;
      gap: calc(.5rem * var(--rh-fit, 1)) 0;
    }

    .rh-panel-stats--triple .rh-stat {
      min-width: 0;
      padding: 0 calc(.35rem * var(--rh-fit, 1));
    }

    .rh-panel-stats--triple .rh-stat:nth-child(3) {
      grid-column: 1 / -1;
      max-width: 100%;
    }

    /* Sin líneas divisorias entre datos en este caso: con dos filas, el
       divisor vertical marcaría una separación que ya expresa la rejilla. */
    .rh-panel-stats--triple .rh-stat { border-left: none; }
  }

  /* Teléfonos muy estrechos (≤360px): un último ajuste de aire interno
     para que quepa incluso el caso con 3 datos de apoyo. */
  @media (max-width: 360px) {
    .rh-panel { gap: calc(.2rem * var(--rh-fit, 1)); }
    .rh-panel-stats { gap: calc(.15rem * var(--rh-fit, 1)) 0; }
    .rh-stat-label { margin-top: calc(.1rem * var(--rh-fit, 1)); }
  }
