/* Los tokens de Vesta (colores, radios, sombras, tipografía, movimiento)
   vienen de ../compartido/vesta.css, que index.html carga antes que este archivo.

   Distribución responsiva (diseño «Generador fracciones» de Vesta, con la
   misma base que numeros-dienes y valor-posicional):
   - Menos de 1024px: filas. Controles arriba y la figura a todo lo ancho.
   - 1024px o más:    panel lateral de 444px. Controles en columna y la
                      figura siempre a la vista junto a ellos.
   - Menos de 640px:  márgenes de 16px.
   El DOM es uno solo; solo cambia este CSS. */
:root {
  /* Paleta de las figuras (no es del sistema de diseño: son los colores
     de las fracciones, deben coincidir con COLORS del script). */
  --morado: #8080f0;
  --azul: #2ed9d9;
  --naranja: #f48600;
  --rojo: #e8384f;
  --verde: #7cbf33;
  --amarillo: #ffd500;
  --rosa: #f06eaa;
}
*,
*::before,
*::after {
  box-sizing: border-box;
}
body {
  margin: 0;
  background: var(--surface-subtle);
  color: var(--text-body);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
a {
  color: var(--text-link);
}
a:hover {
  color: var(--text-link-hover);
}
:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
@media (prefers-reduced-motion: reduce) {
  * {
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
  }
}

/* Oculta un control sin sacarlo del DOM: el script lee y escucha TODOS
   los controles al cargar (incluidos #ancho o #colorPersonalizado aunque
   no estén visibles), así que nunca se eliminan, solo se esconden. */
[data-hide-when] {
  display: none !important;
}
.visuallyHidden {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.page {
  max-width: 1280px;
  margin: 0 auto;
  min-height: 100vh;
  padding: 32px 40px 48px;
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  background: var(--surface-page);
  box-shadow: var(--shadow-sm);
}

/* ---- Cabecera + acción principal ---- */
.header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-bottom: var(--space-5);
  border-bottom: 1px solid var(--border-subtle);
}
/* Ícono + título (el resto de .headerMarca y .icono está en
   ../compartido/cabecera.css): ocupan el espacio junto al botón. */
.headerMarca {
  flex: 1 1 280px;
}
.headerText {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
  flex: 1 1 auto;
}
.header h1 {
  margin: 0;
  font-family: var(--font-serif-display);
  font-variation-settings: "opsz" 120;
  font-weight: 600;
  letter-spacing: -0.02em;
  font-size: 36px;
  line-height: 1.1;
  color: var(--text-heading);
  text-wrap: balance;
}
.header p {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--text-muted);
  text-wrap: pretty;
}

/* ---- Botón (Button de Vesta, primario, tamaño md) ---- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 11px 20px;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  line-height: 1.2;
  white-space: nowrap;
  flex-shrink: 0;
  cursor: pointer;
  transition:
    background var(--duration-fast) var(--ease-standard),
    transform var(--duration-instant) var(--ease-standard),
    box-shadow var(--duration-fast) var(--ease-standard);
}
.btn svg {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
}
.btn-primary {
  background: var(--action-primary);
  border-color: var(--action-primary);
  color: var(--text-inverse);
  box-shadow: var(--shadow-sm);
}
.btn-primary:hover {
  background: var(--action-primary-hover);
  border-color: var(--action-primary-hover);
}
.btn-primary:active {
  transform: translateY(1px);
  box-shadow: none;
}

/* ---- Campos ---- */
.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}
.fieldLabel {
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--text-body);
}
/* Input de Vesta */
.input {
  width: 100%;
  min-height: 48px;
  padding: 12px 14px;
  font-family: var(--font-sans);
  font-size: var(--text-base);
  color: var(--text-body);
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  transition:
    border-color var(--duration-fast) var(--ease-standard),
    box-shadow var(--duration-fast) var(--ease-standard);
}
.input:hover {
  border-color: var(--border-strong);
}
.input:focus {
  outline: none;
  border-color: var(--border-brand);
  box-shadow: var(--ring-focus);
}

/* ---- Control segmentado (el de numeros-dienes) ----
   Botones que manejan un <select> oculto (ver script.js). Con data-animate,
   una píldora (.segInd, la crea el script) se desliza a la opción elegida. */
.seg {
  position: relative;
  display: flex;
  gap: 4px;
  padding: 4px;
  min-width: 0;
  background: var(--neutral-50);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
}
.seg button {
  position: relative;
  flex: 0 0 auto;
  min-height: 40px;
  padding: 8px 14px;
  border: none;
  border-radius: 8px;
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 1.2;
  white-space: nowrap;
  background: transparent;
  color: var(--text-body);
  cursor: pointer;
  transition:
    background var(--duration-fast) var(--ease-out),
    color 220ms var(--ease-out);
}
.seg button:hover:not([aria-pressed="true"]) {
  background: var(--action-secondary);
}
.seg button[aria-pressed="true"] {
  background: var(--action-primary);
  color: var(--text-inverse);
  box-shadow: var(--shadow-xs);
}
.seg[data-animate] button[aria-pressed="true"] {
  background: transparent;
  box-shadow: none;
}
.segInd {
  position: absolute;
  border-radius: 8px;
  background: var(--action-primary);
  box-shadow: var(--shadow-xs);
  pointer-events: none;
  opacity: 0;
}
.segInd.is-ready {
  opacity: 1;
  transition:
    left 220ms var(--ease-out),
    width 220ms var(--ease-out),
    top 220ms var(--ease-out),
    height 220ms var(--ease-out);
}
/* Botones del mismo ancho, repartiéndose la barra. */
.seg.segFill button {
  flex: 1 1 0;
  min-width: 0;
}
/* Forma: solo iconos, de 44px de alto; el nombre va en el tooltip. */
.segForma button {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 8px 10px;
}
.segForma button svg {
  width: 24px;
  height: 24px;
  flex: 0 0 auto;
}

/* ---- Tooltip de Vesta ----
   Nombre de cada forma, ayuda de «Valor del entero», de «Denominador» y
   «Ancho total» (solo con su forma) y de los colores del texto; al pasar
   el cursor o al recibir el foco. Los de «Denominador» y «Ancho total»,
   solo con el cursor, no al seleccionar el campo (pedido del usuario,
   2026-09-27). */
.tipText {
  position: absolute;
  z-index: 40;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  padding: 7px 11px;
  border-radius: var(--radius-sm);
  background: var(--surface-inverse);
  color: var(--text-inverse);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--weight-regular, 400);
  line-height: 1.45;
  white-space: nowrap;
  box-shadow: var(--shadow-md);
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition:
    opacity var(--duration-fast) var(--ease-standard),
    visibility var(--duration-fast) var(--ease-standard);
}
/* Tooltips de dos líneas. */
.tipText.tipMulti {
  width: max-content;
  max-width: 240px;
  white-space: normal;
  text-align: left;
  text-wrap: pretty;
}
.segForma button:hover .tipText,
.segForma button:focus-visible .tipText,
.swatchWrap:hover .tipText,
.swatchWrap:focus-within .tipText,
#valorEnteroField:hover .tipText,
#valorEnteroField:focus-within .tipText,
.page[data-forma="triangulo"] [data-tip-forma="triangulo"]:hover .tipText,
.page[data-forma="rectangulo"] [data-tip-forma="rectangulo"]:hover .tipText {
  opacity: 1;
  visibility: visible;
}
.campoTip {
  position: relative;
}
/* Los de «Denominador» y «Ancho total» se alinean a la derecha del campo:
   centrados, se saldrían de la página (aun ocultos, ocupan lugar y darían
   desplazamiento horizontal). */
[data-tip-forma] .tipText {
  left: auto;
  right: 0;
  transform: none;
}

/* ---- Forma y fracción ---- */
.barra {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--space-5) var(--space-6);
}
/* Forma y fracción lado a lado mientras quepan (a 768px, también con
   «Ancho total»); si no, la fracción baja a otra fila en vez de encogerse
   por debajo de sus columnas. */
.fForma {
  flex: 1 1 300px;
}
.fFraccion {
  flex: 1 1 220px;
  min-width: min-content;
}
/* Numerador, denominador y ancho: columnas de 96px como mínimo, para que
   «Denominador» quepa en una línea. El relleno de 4px (compensado con el
   margen) deja ver el anillo de foco pese al overflow. */
.fraccionFila {
  display: flex;
  gap: var(--space-3);
  padding: 4px;
  margin: -4px;
}
.fraccionFila > .field {
  flex: 1 1 96px;
  min-width: 96px;
}
.fraccionFila label {
  white-space: nowrap;
}
/* «Ancho total» entra deslizándose con el rectángulo y sale con las otras
   formas. Oculto sigue con data-hide-when (lo pone el script), pero aquí
   se queda en pantalla sin ancho, para que la salida también se anime. El
   script lo marca inert mientras está oculto. */
#anchoField {
  max-width: 100%;
  transition:
    flex-grow 300ms var(--ease-out),
    flex-basis 300ms var(--ease-out),
    max-width 300ms var(--ease-out),
    min-width 300ms var(--ease-out),
    margin-left 300ms var(--ease-out),
    opacity 220ms var(--ease-out),
    transform 300ms var(--ease-out);
}
#anchoField[data-hide-when] {
  display: flex !important;
  flex: 0 0 0px;
  min-width: 0;
  max-width: 0;
  margin-left: calc(-1 * var(--space-3));
  opacity: 0;
  transform: translateX(32px);
  overflow: hidden;
}

/* ---- Color de las partes ---- */
.swatches {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  padding: 4px 0;
}
.swatch {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid rgba(9, 47, 107, 0.08);
  border-radius: var(--radius-sm);
  color: #fff;
  cursor: pointer;
  transition: background 220ms var(--ease-out);
}
.swatch svg {
  width: 20px;
  height: 20px;
}
.swatch[data-color="morado"] { background: var(--morado); }
.swatch[data-color="azul"] { background: var(--azul); }
.swatch[data-color="naranja"] { background: var(--naranja); }
.swatch[data-color="rojo"] { background: var(--rojo); }
.swatch[data-color="verde"] { background: var(--verde); }
.swatch[data-color="rosa"] { background: var(--rosa); }
.swatch[data-color="amarillo"] { background: var(--amarillo); }
/* «＋»: gris hasta que se elige; elegido, toma el color personalizado (lo
   pone el script) y la palomita en vez del «+». */
.swatch[data-color="personalizado"] {
  background: var(--neutral-100);
  color: var(--neutral-600);
}
.swatch[data-color="personalizado"]:hover:not([aria-pressed="true"]) {
  background: var(--neutral-200);
}
.swatch[data-color="personalizado"][aria-pressed="true"] {
  color: #fff;
}
.swatch .check,
.swatch[aria-pressed="true"] .mas {
  display: none;
}
.swatch[aria-pressed="true"] .check {
  display: block;
}
.swatch:focus-visible {
  box-shadow:
    0 0 0 2px var(--neutral-0),
    var(--focus-ring);
}
/* Anillo de la muestra elegida: uno solo que se desliza (lo coloca el
   script con offsetLeft/Top, como la píldora de los segmentados). */
.swatchRing {
  position: absolute;
  z-index: 1;
  top: 0;
  left: 0;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-sm);
  box-shadow:
    0 0 0 2px var(--neutral-0),
    0 0 0 4px var(--action-primary);
  pointer-events: none;
  opacity: 0;
}
.swatchRing.is-ready {
  opacity: 1;
  transition: transform 260ms var(--ease-out);
}
/* Campo del color personalizado: el de `ColorSwatchGroup` de Vesta (todo el
   ancho, hueco de 10px y la muestra nativa sin borde). */
.colorField {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 48px;
  padding: 0 16px 0 10px;
  font-size: var(--text-sm);
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  cursor: pointer;
}
.colorField input[type="color"] {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-xs);
  background: none;
  cursor: pointer;
}
.colorField input[type="color"]::-webkit-color-swatch-wrapper {
  padding: 0;
}
.colorField input[type="color"]::-webkit-color-swatch {
  border: none;
  border-radius: 3px;
}
.colorField input[type="color"]::-moz-color-swatch {
  border: none;
  border-radius: 3px;
}
/* «Color personalizado» ocupa el hueco y el hex queda a la derecha. */
.colorField > span:not(.colorHex) {
  flex: 1;
}
.colorHex {
  font-family: var(--font-mono);
  color: var(--text-muted);
}

/* ---- Sección plegable «Etiquetas numéricas» (la de numeros-dienes) ---- */
.plegable {
  display: flex;
  flex-direction: column;
  padding: var(--space-5) 0;
  border-top: 1px solid var(--border-subtle);
  border-bottom: 1px solid var(--border-subtle);
}
.plegableToggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  width: 100%;
  min-height: 44px;
  margin: -8px 0;
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  cursor: pointer;
  font-family: var(--font-sans);
  text-align: left;
  color: var(--text-body);
}
.plegableTitulo {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 12px;
  min-width: 0;
}
.eyebrow {
  font-size: 12px;
  font-weight: var(--weight-semibold);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.chevron {
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
  color: var(--text-muted);
  transition: transform var(--duration-base) var(--ease-out);
}
.plegable.is-open .chevron {
  transform: rotate(180deg);
}
/* Se abre animando la fila de 0fr a 1fr. Mientras está cerrada (o se está
   moviendo), .plegableClip recorta; ya abierta, deja salir los tooltips. */
.plegableBody {
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  visibility: hidden;
  transition:
    grid-template-rows 380ms var(--ease-out),
    opacity 160ms var(--ease-out),
    visibility 0s linear 380ms;
}
.plegable.is-open .plegableBody {
  grid-template-rows: 1fr;
  opacity: 1;
  visibility: visible;
  transition:
    grid-template-rows 380ms var(--ease-out),
    opacity 220ms var(--ease-out) 80ms,
    visibility 0s;
}
.plegableClip {
  min-height: 0;
  overflow: hidden;
}
.plegable.is-settled .plegableClip {
  overflow: visible;
}
/* Sin separación vertical: cada menú plegado mide 0 y el espacio lo ponen
   el propio menú (abajo) y «¿Qué puedes escribir?» (arriba). */
.plegableInner {
  display: flex;
  flex-direction: column;
  padding-top: var(--space-5);
}

/* ---- Interruptor (Switch de Vesta, el de numeros-dienes) ----
   Es un <input type="checkbox"> real (el script lee .checked); la pista
   va a la derecha del texto. */
.switch {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  min-height: 44px;
  cursor: pointer;
  font-size: var(--text-base);
  color: var(--text-body);
  white-space: nowrap;
}
.switch input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  margin: 0;
}
.switchTrack {
  position: relative;
  flex: 0 0 auto;
  width: 46px;
  height: 26px;
  border-radius: var(--radius-pill);
  background: var(--neutral-200);
  transition: background var(--duration-base) var(--ease-standard);
}
.switchTrack::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 20px;
  height: 20px;
  border-radius: var(--radius-pill);
  background: var(--neutral-0);
  box-shadow: var(--shadow-sm);
  transition: left var(--duration-base) var(--ease-out);
}
.switch input:checked ~ .switchTrack {
  background: var(--action-primary);
}
.switch input:checked ~ .switchTrack::after {
  left: 23px;
}
.switch input:focus-visible ~ .switchTrack {
  box-shadow: var(--focus-ring);
}
/* Interruptores contiguos (regla del repo): el segundo sube 9px para que
   entre pista y pista (26px, centrada en su fila de 44px) queden 9px, como
   «Mostrar periodos» / «Mostrar clases» en valor-posicional. */
.switch + .switch {
  margin-top: -9px;
}
.switches {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* ---- Menús de los interruptores ----
   Cada interruptor despliega su menú (grid 0fr ↔ 1fr + fundido). Los
   campos de dentro se muestran siempre: quien los oculta es el menú, así
   la contracción también se anima. */
.menuSwitch {
  display: grid;
  grid-template-rows: 0fr;
  min-width: 0;
  visibility: hidden;
  transition:
    grid-template-rows 380ms var(--ease-out),
    visibility 0s linear 380ms;
}
.menuSwitchInner {
  min-height: 0;
  overflow: hidden;
  opacity: 0;
  transition: opacity 220ms var(--ease-out);
}
.menuSwitchRow {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--space-4);
  /* 4px + los 9px que la fila de 44px deja bajo la pista del interruptor. */
  padding: var(--space-1) 0 var(--space-3);
}
.plegable:has(#showTotalLabel:checked, #showPartLabels:checked) .menuSwitch[data-menu="valor"],
.plegable:has(#showTotalLabel:checked) .menuSwitch[data-menu="total"],
.plegable:has(#showPartLabels:checked) .menuSwitch[data-menu="partes"] {
  grid-template-rows: 1fr;
  visibility: visible;
  transition-delay: 0s;
}
.plegable:has(#showTotalLabel:checked, #showPartLabels:checked) .menuSwitch[data-menu="valor"] .menuSwitchInner,
.plegable:has(#showTotalLabel:checked) .menuSwitch[data-menu="total"] .menuSwitchInner,
.plegable:has(#showPartLabels:checked) .menuSwitch[data-menu="partes"] .menuSwitchInner {
  opacity: 1;
  /* Terminado el despliegue, deja salir los tooltips. */
  animation: desbordeAbierto 0s linear 380ms forwards;
}
@keyframes desbordeAbierto {
  to {
    overflow: visible;
  }
}
.menuSwitchRow > :is(#valorEnteroField, #colorValorTotalField, #labelModeField, #colorValorParteField) {
  display: flex !important;
}
/* «Valor del entero» y «Color del total»: cada menú es una columna, con
   las medidas de «Valor de las partes» y «Color en las partes» (y el mismo
   hueco), así las dos filas se alinean y parten igual si no caben. El menú
   del total, cerrado, no tiene alto pero conserva su ancho: «Valor del
   entero» no cambia de tamaño con solo el valor de cada parte. */
.menuFila {
  display: flex;
  flex-wrap: wrap;
  column-gap: var(--space-4);
}
.menuFila > [data-menu="valor"] {
  flex: 1 1 226px;
}
.menuFila > [data-menu="total"] {
  flex: 0 1 152px;
}
.fValor {
  flex: 1 1 100%;
}
/* 226px: junto a su color (152px) caben en los 394px del panel lateral. */
.fModo {
  flex: 1 1 226px;
}
/* Relleno lateral del diseño (6px): así «Personalizado» cabe en su mitad. */
.fModo .seg button {
  padding: 8px 6px;
}
.fColorValor {
  /* 3 muestras de 40px + 2 huecos de 8px + 4px de anillo por lado. La
     etiqueta va centrada sobre las muestras. */
  flex: 0 1 152px;
  align-items: center;
}

/* ---- Color del número / de la llave ----
   Dos muestras fijas (botones) que copian su color en el <input
   type="color"> que lee el script, y «+», que abre ese mismo selector.
   Con un color propio, «+» lo muestra y lleva el anillo (como «Color de
   los bloques» de numeros-dienes). */
.colorPick {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 4px;
}
.swatchWrap {
  position: relative;
  display: flex;
}
.colorPickSwatch,
.colorPickMas {
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid rgba(9, 47, 107, 0.16);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: box-shadow var(--duration-fast) var(--ease-out);
}
.colorPickSwatch {
  box-shadow: var(--shadow-xs);
}
.colorPickSwatch[aria-pressed="true"],
.colorPickMas.is-selected {
  box-shadow:
    0 0 0 2px var(--neutral-0),
    0 0 0 4px var(--action-primary);
}
.colorPickSwatch:focus-visible {
  outline: none;
  box-shadow:
    0 0 0 2px var(--neutral-0),
    var(--focus-ring);
}
.colorPickMas {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  border-color: rgba(9, 47, 107, 0.08);
  background: var(--neutral-100);
  color: var(--neutral-600);
}
.colorPickMas:hover:not(.is-selected) {
  background: var(--neutral-200);
}
.colorPickMas.is-selected svg {
  display: none;
}
.colorPickMas svg {
  width: 20px;
  height: 20px;
}
/* El <input type="color"> real va encima, invisible. */
.colorPickMas input[type="color"] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: none;
  opacity: 0;
  cursor: pointer;
}
.colorPickMas:has(input:focus-visible) {
  box-shadow: var(--focus-ring);
}
/* El primer tooltip de cada grupo arranca en su muestra; el de «+», que
   es largo, ocupa el ancho del grupo (se ancla a .colorPick). Así no se
   salen de la página, esté el grupo a la izquierda o a la derecha. */
.colorPick {
  position: relative;
}
.colorPick .swatchWrap:first-child .tipText {
  left: 0;
  transform: none;
}
.colorPick .swatchWrap:last-child {
  position: static;
}
.colorPick .swatchWrap:last-child .tipText {
  left: 0;
  right: 0;
  width: auto;
  transform: none;
}

/* ---- «Personalizado»: un campo por parte coloreada ----
   Se despliega (0fr ↔ 1fr) con ese modo; el script pone .is-open. Sin
   altura máxima: con 20 partes crece en filas en vez de esconderlas tras
   una barra de desplazamiento. */
.manualMenu {
  flex: 1 1 100%;
  display: grid;
  grid-template-rows: 0fr;
  min-width: 0;
  margin-top: calc(-1 * var(--space-4));
  opacity: 0;
  transition:
    grid-template-rows 280ms var(--ease-out),
    margin-top 280ms var(--ease-out),
    opacity 220ms var(--ease-out);
}
.manualMenu.is-open {
  grid-template-rows: 1fr;
  margin-top: 0;
  opacity: 1;
}
.manualClip {
  min-height: 0;
  overflow: hidden;
}
.manualBox {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: var(--space-3);
  background: var(--surface-sunken);
  border-radius: var(--radius-md);
}
.manualHead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}
.switchSmall {
  min-height: 44px;
  margin: -8px 0;
  gap: var(--space-2);
  font-size: var(--text-sm);
}
/* Campo con prefijo: «Las N partes» o el número de la parte. */
.manualTodas,
.manualField {
  display: flex;
  align-items: stretch;
  min-width: 0;
  min-height: 40px;
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: 8px;
  overflow: hidden;
}
.manualTodas:focus-within,
.manualField:focus-within {
  border-color: var(--border-brand);
  box-shadow: var(--ring-focus);
}
.manualPrefijo,
.manualField label {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 10px;
  font-size: 12px;
  color: var(--text-muted);
  background: var(--neutral-25);
  border-right: 1px solid var(--border-subtle);
  white-space: nowrap;
}
.manualTodas input,
.manualField input {
  flex: 1 1 auto;
  width: 100%;
  min-width: 0;
  padding: 0 8px;
  border: none;
  outline: none;
  background: transparent;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--text-body);
}
/* Con «Mismo valor» se ve un solo campo; sin él, uno por parte. */
.manualBox:not(.is-same) .manualTodas,
.manualBox.is-same .manualPanel {
  display: none;
}
.manualPanel {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: var(--space-2);
  counter-reset: parte;
}
/* rebuildManualPanel escribe «Parte N» en cada etiqueta; el diseño solo
   muestra el número. El texto se queda (es el nombre accesible del campo)
   y en pantalla lo sustituye un contador. */
.manualField {
  counter-increment: parte;
}
.manualField label {
  flex-basis: 28px;
  padding: 0;
  font-size: 0;
}
.manualField label::before {
  content: counter(parte);
  font-size: 12px;
}

/* Ayuda de LaTeX: <details> nativo, sin script. */
.ayuda {
  min-width: 0;
  margin-top: var(--space-2);
  interpolate-size: allow-keywords;
}
/* Despliegue animado donde el navegador lo admite (Chrome/Edge 131+);
   en el resto, <details> abre sin transición. */
.ayuda::details-content {
  block-size: 0;
  overflow: hidden;
  opacity: 0;
  transition:
    block-size 380ms var(--ease-out),
    opacity 220ms var(--ease-out),
    content-visibility 380ms allow-discrete;
}
.ayuda[open]::details-content {
  block-size: auto;
  opacity: 1;
}
.ayuda summary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  margin: -6px 0;
  list-style: none;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--text-link);
  cursor: pointer;
}
.ayuda summary::-webkit-details-marker {
  display: none;
}
.ayuda summary svg {
  width: 16px;
  height: 16px;
  transition: transform var(--duration-base) var(--ease-out);
}
.ayuda[open] summary svg {
  transform: rotate(180deg);
}
.ayudaBody {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-top: 10px;
  font-size: var(--text-sm);
  color: var(--text-muted);
  text-wrap: pretty;
}
.ayudaBody p {
  margin: 0;
}
.ayudaBody code {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--text-body);
}
.comandos {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.comandos code {
  white-space: nowrap;
  padding: 2px 8px;
  border-radius: var(--radius-xs);
  background: var(--neutral-50);
  border: 1px solid var(--border-subtle);
}

/* ---- Previsualización ---- */
.preview {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-width: 0;
}
/* Callout de Vesta. El script lo muestra con style.display = "block", así
   que el icono va posicionado en vez de usar flex. */
.callout {
  display: none;
  position: relative;
  padding: var(--space-4) var(--space-5) var(--space-4) 52px;
  border-left: 3px solid;
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  font-size: var(--text-base);
  line-height: var(--leading-normal);
}
.callout svg {
  position: absolute;
  top: 19px;
  left: 20px;
  width: 20px;
  height: 20px;
}
.callout strong {
  display: block;
  font-weight: var(--weight-semibold);
  margin-bottom: 2px;
}
.callout.error {
  background: var(--feedback-error-bg);
  color: var(--feedback-error-fg);
  border-color: var(--feedback-error-line);
}
.callout.warning {
  background: var(--feedback-retry-bg);
  color: var(--feedback-retry-fg);
  border-color: var(--feedback-retry-line);
}
.stage {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 360px;
  padding: var(--space-8) var(--space-6);
  background: var(--neutral-0);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}
#svgHolder {
  width: 100%;
  max-width: 100%;
  display: flex;
  justify-content: center;
}
/* Imprescindible: sin esto, un rectángulo ancho (o la llave del entero
   ensanchando el lienzo) desborda la tarjeta. El alto máximo es el del
   diseño en cada distribución (440px aquí, 300px en el celular y 600px
   con el panel lateral), sin pasar del 70% de la ventana. */
#svgHolder svg {
  display: block;
  max-width: 100%;
  max-height: min(440px, 70vh);
  height: auto;
}

/* ---- Pie (mismo estilo que el de la portada, alineado a la derecha) ---- */
.pie {
  margin-top: auto;
  padding-top: var(--space-5);
  border-top: 1px solid var(--border-subtle);
  font-size: var(--text-sm);
  color: var(--text-muted);
  text-align: right;
}
.pie a {
  color: inherit;
  text-underline-offset: 3px;
  transition: color var(--duration-base) var(--ease-out);
}
.pie a:hover {
  color: var(--text-brand);
}
.pie a:focus-visible {
  outline: none;
  border-radius: var(--radius-sm);
  box-shadow: var(--ring-focus);
}

/* ================================================================
   Filas (menos de 1024px)
   ================================================================ */
.layout {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}
.panel {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  min-width: 0;
}

/* Teléfono: márgenes de 16px, botón a todo lo ancho, título de 28px y los
   interruptores a 14px para seguir en una línea (y a 9px de pista a
   pista). */
@media (max-width: 639px) {
  .page {
    padding: 20px 16px 32px;
    gap: var(--space-5);
  }
  .layout,
  .panel {
    gap: var(--space-5);
  }
  .header h1 {
    font-size: 28px;
  }
  .header .btn {
    flex: 1 1 100%;
  }
  .switch {
    font-size: var(--text-sm);
  }
  /* Las ocho muestras (siete colores + «＋», 320px) en una fila: la
     separación baja de 8px solo lo necesario (a 375px queda en 3.3px). Con
     menos de 2px ya no caben y pasan a dos filas con la separación mínima. */
  .swatches {
    column-gap: max(2px, min(var(--space-2), calc((100% - 320px) / 7)));
  }
  .stage {
    min-height: 240px;
    padding: var(--space-5) var(--space-4);
  }
  #svgHolder svg {
    max-height: min(300px, 70vh);
  }
}

/* ================================================================
   Panel lateral (1024px o más)
   ================================================================ */
@media (min-width: 1024px) {
  .layout {
    flex-direction: row;
    align-items: stretch;
  }
  .panel {
    flex: 0 0 444px;
    padding: var(--space-6);
    background: var(--neutral-0);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
  }
  .plegable {
    padding-bottom: 0;
    border-bottom: none;
  }
  .manualPanel {
    grid-template-columns: repeat(auto-fill, minmax(128px, 1fr));
  }
  .preview {
    flex: 1 1 0;
  }
  .stage {
    flex: 1 1 auto;
    min-height: 480px;
  }
  #svgHolder svg {
    max-height: min(600px, 70vh);
  }
}
