/* ═══════════════════════════════════════════════
   FICHERO GENERADO — no editar a mano.

   Lo construye `scripts/construir_css.py` juntando las hojas de `css/ui/`, que
   son las que hay que editar. Si tocas una, vuelve a ejecutarlo:

       .venv/Scripts/python.exe scripts/construir_css.py

   Existe para que una página pida una hoja en vez de doce: el servidor habla
   HTTP/1.1 y cada petición cuesta.
   ═══════════════════════════════════════════════ */


/* ── tokens.css ── */

/* ═══════════════════════════════════════════════
   TOKENS
   Única fuente de verdad para color, tipografía y ritmo.

   La paleta de marca (--brand, --bg, --text, --muted…) vive en
   codelab-brand.css y no se duplica aquí: esto son los tokens semánticos
   que las plantillas venían escribiendo a mano (#94a3b8, #64748b, #475569…).

   Al añadir un color nuevo a una plantilla, mételo aquí primero.
═══════════════════════════════════════════════ */

:root {
  /* ══ RADIOS ══
     Había ocho radios distintos en la app: 6/10/16/24 de la paleta de marca,
     16/18 de aquí, y literales sueltos de 8, 14 y 20. Nadie distingue 16 de 18
     mirando un panel; todo el mundo lo nota al pasar de pantalla, como una
     sensación difusa de que no es la misma aplicación.

     Quedan tres, y ninguno más. Si algo necesita un cuarto, es que el
     componente está mal, no la escala. */
  --ui-radius-control: 8px;   /* controles, distintivos, recuadros interiores */
  --ui-radius-surface: 16px;  /* paneles, tarjetas, cabeceras */
  --ui-radius-pill: 999px;    /* píldoras y avatares */

  /* ══ VELADURAS Y SOMBRAS ══
     En un tema oscuro, «un poco más claro que el fondo» se escribe como blanco
     con poca alfa: había 196 así repartidas por las hojas. Sobre fondo claro
     todas desaparecen —un borde blanco al 8 % sobre blanco no es un borde—, y
     con ellas se van los separadores de tabla, los hover y los bordes de panel.

     Cinco escalones y no veinte: la diferencia entre 0,04 y 0,05 no la ve
     nadie, pero obliga a mantener veinte valores en cada tema. */
  --ui-velo-1: rgba(255, 255, 255, 0.025);
  --ui-velo-2: rgba(255, 255, 255, 0.05);
  --ui-velo-3: rgba(255, 255, 255, 0.08);
  --ui-velo-4: rgba(255, 255, 255, 0.11);
  --ui-velo-5: rgba(255, 255, 255, 0.18);

  --ui-sombra-1: rgba(0, 0, 0, 0.28);
  --ui-sombra-2: rgba(0, 0, 0, 0.42);
  --ui-sombra-3: rgba(0, 0, 0, 0.6);

  /* ── Superficies ── */
  --ui-shadow-soft: 0 10px 24px var(--ui-sombra-1);
  --ui-shadow-strong: 0 14px 34px var(--ui-sombra-2);
  --ui-border-soft: 1px solid rgba(20, 184, 166, 0.12);
  --ui-surface-soft: rgba(10, 30, 31, 0.96);
  --ui-surface-alt: rgba(8, 25, 26, 0.9);
  /* Sin transparencia. Para lo que tiene que tapar de verdad lo que pasa por
     debajo: columnas fijas al desplazar, cabeceras pegajosas. Las dos de
     arriba dejan pasar un 4-10 %, que basta para que se vea el texto
     colándose. */
  --ui-surface-solid: #0C2425;
  --ui-header-gradient: linear-gradient(135deg, #0A1C1D 0%, #0F3D3E 55%, #14675F 130%);

  /* El fondo de la cabecera de página. Es token porque en tema claro no puede
     ser el mismo: una losa casi negra en mitad de una página clara se lee como
     un agujero, no como una cabecera. En claro pasa a ser la banda petróleo
     de marca, que es como Xestio resuelve sus cabeceras de sección. */
  --ui-header-surface: linear-gradient(135deg, #08191A 0%, #0F3D3E 55%, #14675F 145%);
  --ui-header-borde: rgba(20, 184, 166, 0.2);

  /* ── Texto ──
     Los grises que las plantillas repetían a mano. `--ui-text-faint` es el más
     claro que sigue cumpliendo AA (4.5:1) sobre los fondos de la app: para
     texto pequeño no se baja de #94a3b8. */
  --ui-text-strong: #f1f5f9;
  --ui-text: #e2e8f0;
  --ui-text-soft: #cbd5e1;
  --ui-text-faint: #94a3b8;
  /* Solo decorativo o texto grande: NO cumple AA por debajo de 1.2rem. */
  --ui-text-disabled: #64748b;

  /* ── Bordes ── */
  --ui-line-subtle: rgba(255, 255, 255, 0.05);
  --ui-line: rgba(255, 255, 255, 0.09);
  --ui-line-strong: rgba(255, 255, 255, 0.16);

  /* ── Estados semánticos ── */
  --ui-success: #34d399;
  --ui-warning: #fbbf24;
  --ui-danger: #f87171;
  --ui-info: #60a5fa;

  /* ── Tipos de bloque de un tutorial ──
     Los usan el editor y la vista de lectura; tenerlos aquí evita que las dos
     vistas se vayan separando de color con el tiempo. */
  --ui-block-theory: #60a5fa;
  --ui-block-code: #fbbf24;
  --ui-block-exercise: #34d399;
  --ui-block-hint: #a78bfa;
  --ui-block-solution: #fb923c;
  --ui-block-video: #f87171;
  --ui-block-file: #94a3b8;
  --ui-block-quiz: #f472b6;
  --ui-block-resource: #2dd4bf;

  /* ── Tipografía ── */
  --ui-font-mono: 'Fira Code', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* ══ ESCALA ══
     La escala existía y nadie la usaba: las plantillas escribían .68 .70 .72
     .74 .76 .78 .80 .82 .84 .85 .86 .88 .95 rem a mano. Parte de la culpa era
     de la propia escala, que saltaba de .82 a 1rem sin nada en medio: cuando
     hace falta «un poco más pequeño que el cuerpo», no había paso y se
     inventaba uno.

     Ahora va sobre rejilla de píxeles y con el escalón intermedio. `xs` es el
     suelo —12 px— y por debajo no se baja: ahí es donde estaban los plazos de
     entrega y los estados, que es de lo más consultado de la app. */
  --ui-text-xs: 0.75rem;      /* 12px · suelo, solo etiquetas y metadatos */
  --ui-text-sm: 0.8125rem;    /* 13px */
  --ui-text-md: 0.875rem;     /* 14px · el que faltaba */
  --ui-text-base: 1rem;       /* 16px · cuerpo */
  --ui-text-lg: 1.125rem;     /* 18px */
  --ui-text-xl: 1.375rem;     /* 22px */
  --ui-text-2xl: 1.75rem;     /* 28px */
  --ui-leading-prose: 1.75;

  /* ── Ritmo ── */
  --ui-space-1: 4px;
  --ui-space-2: 8px;
  --ui-space-3: 12px;
  --ui-space-4: 16px;
  --ui-space-5: 24px;
  --ui-space-6: 32px;
  --ui-space-7: 48px;

  /* ── Movimiento ── */
  --ui-duration-fast: 120ms;
  --ui-duration: 200ms;
  --ui-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

/* ═══════════════════════════════════════════════
   MODO AULA — tema claro
   Auditoría estética 13/08/2026, A1.

   Codelab solo tenía tema oscuro: `prefers-color-scheme` no aparecía ni una
   vez en las 37 hojas. Eso no es una preferencia estética. Proyectado en un
   aula con luz, o junto a una ventana, el contraste real se hunde muy por
   debajo del que se calcula en pantalla; y ya existía un CSS de impresión
   aparte, señal de que el problema de imprimir sobre negro había aparecido y
   se había parcheado por su cuenta.

   Tres decisiones que conviene no deshacer sin querer:

   1. **El oscuro sigue siendo el de serie.** El tema se elige, no se hereda
      del sistema operativo: a quien ya usa CodeLab no se le cambia la
      aplicación de aspecto sin avisar solo porque su portátil esté en claro.
      Quien quiera el claro lo pide, y se le recuerda.

   2. **La paleta es la de CodeLab, no una paleta clara cualquiera.** El
      petróleo #0F3D3E es la base compartida de Xestio y sí funciona sobre
      blanco —10,6:1—, así
      que en claro es él quien hace de color de acción. El lima #ADFF00 da 1,1:1
      sobre blanco —es invisible como color de texto—, así que no aparece: no
      se ha perdido la marca, se ha usado la parte de la marca que sirve.
      `--brand` no es «el lima», es «el color con el que la app señala»; por eso
      puede cambiar de valor sin que ninguna regla que lo use tenga que
      enterarse.

   3. **El lateral y las cabeceras siguen siendo oscuros en los dos temas.**
      Son la firma de CodeLab y funcionan como isla: más abajo se les
      devuelve el juego de tokens oscuro para que lo que vive dentro siga
      contrastando.
═══════════════════════════════════════════════ */
:root[data-theme="light"] {
  /* ── Base ── */
  --bg: #edf2f2;
  --bg-strong: #ffffff;
  --surface: #ffffff;
  --surface-strong: #f4f9f9;
  --text: #072a2e;
  --muted: #55696c;

  /* ── Marca ──
     El petróleo pasa a ser el color de acción; el lima se retira porque sobre
     blanco no se lee —#ADFF00 da 1,09:1, es invisible—. `--brand-contrast` va
     con él: lo que antes era texto casi negro sobre lima ahora es blanco sobre
     petróleo, 11,9:1.

     El acento y el naranja van OSCURECIDOS respecto al kit, no cambiados de
     familia: el teal oficial #14B8A6 da 2,2:1 sobre este fondo y el naranja
     señal #FF3B00 da 3,16:1; ninguno de los dos vale como texto. Es el mismo
     recurso que la propia norma usa con el amarillo de FocusLab, que tiene su
     `--focuslab-text` para esto. Medidos sobre #edf2f2, el fondo más claro. */
  --brand: var(--xestio-petroleum);
  --brand-dark: #0A2C2D;
  --brand-contrast: #ffffff;
  --brand-hover: #0A2C2D;

  --accent: #0F766E;
  --accent-hover: #0B5A54;
  --accent-orange: #C22D00;

  --line: rgba(7, 42, 46, 0.14);
  --shadow: 0 20px 60px rgba(7, 42, 46, 0.12);

  /* Un fondo liso y no el degradado radial del oscuro: en claro los
     resplandores se convierten en manchas sucias. */
  --body-gradient: linear-gradient(180deg, #edf2f2 0%, #e6eeee 100%);
  --primary-gradient: linear-gradient(135deg, #0F3D3E 0%, #0F766E 100%);
  --primary-gradient-hover: linear-gradient(135deg, #0A2C2D 0%, #0F3D3E 100%);

  /* ── Veladuras ──
     Tinte de marca y no gris neutro: sobre blanco, un gris puro se lee como
     suciedad y un teal muy diluido se lee como intención. */
  --ui-velo-1: rgba(7, 58, 64, 0.035);
  --ui-velo-2: rgba(7, 58, 64, 0.06);
  --ui-velo-3: rgba(7, 58, 64, 0.09);
  --ui-velo-4: rgba(7, 58, 64, 0.13);
  --ui-velo-5: rgba(7, 58, 64, 0.2);

  --ui-sombra-1: rgba(7, 42, 46, 0.08);
  --ui-sombra-2: rgba(7, 42, 46, 0.13);
  --ui-sombra-3: rgba(7, 42, 46, 0.2);

  --ui-border-soft: 1px solid rgba(7, 58, 64, 0.14);
  --ui-surface-soft: #ffffff;
  --ui-surface-alt: #f2f7f7;
  --ui-surface-solid: #ffffff;

  /* La cabecera deja de ser casi negra y pasa a ser la banda petróleo: el
     mismo recurso que usa Xestio para separar secciones sobre fondo claro. */
  --ui-header-surface: linear-gradient(135deg, #0A2C2D 0%, #0F3D3E 55%, #14675F 140%);
  --ui-header-borde: rgba(7, 58, 64, 0.18);

  /* ── Texto ──
     Todos verificados sobre #edf2f2, que es el fondo más claro de la app y por
     tanto el caso peor. `--ui-text-faint` da 5,0:1 y es el suelo. */
  --ui-text-strong: #051f22;
  --ui-text: #0e3438;
  --ui-text-soft: #3c5457;
  --ui-text-faint: #55696c;
  --ui-text-disabled: #7c8e90;

  --ui-line-subtle: rgba(7, 58, 64, 0.08);
  --ui-line: rgba(7, 58, 64, 0.14);
  --ui-line-strong: rgba(7, 58, 64, 0.24);

  /* ── Estados ──
     Los del oscuro son tonos pastel pensados para brillar sobre negro; sobre
     blanco ninguno llega a 4,5:1. Aquí van sus equivalentes oscuros. */
  --ui-success: #0f7a4f;
  --ui-warning: #8a5a00;
  --ui-danger: #c4302b;
  --ui-info: #1d5fa8;

  /* ── Tipos de bloque de un tutorial ── */
  --ui-block-theory: #1d5fa8;
  --ui-block-code: #8a5a00;
  --ui-block-exercise: #0f7a4f;
  --ui-block-hint: #6d4bb8;
  --ui-block-solution: #b45309;
  --ui-block-video: #c4302b;
  --ui-block-file: #55696c;
  --ui-block-quiz: #b03a6d;
  --ui-block-resource: #0a6c73;
}

/* ── Islas de marca ──
   El lateral, las cabeceras de página y el escaparate de acceso conservan el
   fondo oscuro de CodeLab en los dos temas. Como el contenido de dentro
   —iconos, distintivos, subtítulos— se pinta con los mismos tokens que el
   resto de la app, en tema claro se quedaría con colores oscuros sobre fondo
   oscuro. Así que aquí dentro se restituye el juego oscuro.

   Va con `[data-theme="light"]` delante y no suelto: en tema oscuro estos
   valores ya son los que hay, y repetirlos sería otra fuente de verdad. */
:root[data-theme="light"] .sidebar,
:root[data-theme="light"] .page-header-modern,
:root[data-theme="light"] .auth-showcase-shell,
:root[data-theme="light"] .public-header,
:root[data-theme="light"] .feature-callout,
:root[data-theme="light"] .form-panel-header,
:root[data-theme="light"] .stat-card-modern,
:root[data-theme="light"] .continue-card,
:root[data-theme="light"] .fl-hero,
:root[data-theme="light"] .demo-live,
:root[data-theme="light"] .documento-generado,
:root[data-theme="light"] .plan-textarea,
:root[data-theme="light"] .break-body {
  --brand: var(--codelab-accent);
  --brand-contrast: var(--codelab-technical);
  --brand-hover: #93D900;
  --accent: var(--xestio-turquoise);
  --ui-text-strong: #f1f5f9;
  --ui-text: #e2e8f0;
  --ui-text-soft: #cbd5e1;
  --ui-text-faint: #94a3b8;
  --ui-text-disabled: #64748b;
  --ui-velo-1: rgba(255, 255, 255, 0.025);
  --ui-velo-2: rgba(255, 255, 255, 0.05);
  --ui-velo-3: rgba(255, 255, 255, 0.08);
  --ui-velo-4: rgba(255, 255, 255, 0.11);
  --ui-velo-5: rgba(255, 255, 255, 0.18);
  --ui-line-subtle: rgba(255, 255, 255, 0.05);
  --ui-line: rgba(255, 255, 255, 0.09);
  --ui-line-strong: rgba(255, 255, 255, 0.16);
  --ui-success: #34d399;
  --ui-warning: #fbbf24;
  --ui-danger: #f87171;
  --ui-info: #60a5fa;
}

/* Los bloques de código se resuelven en `codelab-brand.css`, en la regla
   global de `pre`: es ella la que fija el fondo casi negro de los dos temas y,
   desde el 14/08/2026, también el color del texto. Aquí no hace falta nada.

   Hubo una versión de este arreglo que metía los `pre` en la lista de islas de
   arriba, y **no funcionaba**: esa regla solo redefine variables, y sirve porque
   las reglas de dentro las leen con `var()`. Un `pre` que no fija `color` lo
   tiene *heredado*, ya calculado, del ancestro; redefinir `--ui-text` encima no
   cambia un color heredado. Conviene recordarlo antes de resolver así el
   siguiente caso. */

/* Quien haya pedido menos movimiento en su sistema, lo recibe en toda la app. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --ui-duration-fast: 0ms;
    --ui-duration: 0ms;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ═══════════════════════════════════════════════
   FOCO VISIBLE — global
   Antes había dos reglas de foco en todo el proyecto: navegar con teclado era
   prácticamente imposible.

   Y luego hubo dos definiciones de la propia regla, con colores distintos:
   esta en teal y otra universal en lima dentro de components.css. Ganaba la
   lima por orden de carga, así que el teal nunca se veía. Queda una sola, y
   vive aquí porque es el suelo del sistema, no un componente.

   `:focus-visible` y no `:focus`: el anillo aparece al navegar con teclado y
   no al hacer clic con el ratón, que es lo que llevaba a que lo quitaran.

   Sin `border-radius`: fijarlo aquí le cambiaba la forma al elemento enfocado
   —una píldora se cuadraba al recibir el foco—. El contorno ya sigue por sí
   solo la forma de aquello que rodea.
═══════════════════════════════════════════════ */
:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

/* Salto al contenido: invisible hasta que se tabula. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 999;
  padding: 0.6rem 1rem;
  background: var(--brand);
  color: var(--brand-contrast);
  font-weight: 700;
  border-radius: 0 0 var(--ui-radius-control) 0;
}
.skip-link:focus {
  left: 0;
}



/* ── layout.css ── */

/* ── Auth page wrapper (replaces container) ─── */
.public-auth-main {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

.auth-shell {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.auth-panel-grid {
  flex: 1;
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(420px, 0.9fr);
  min-height: 100vh;
}

.auth-card-shell,
.auth-showcase-shell {
  border-radius: 0;
  overflow: hidden;
}

/* ── Form card (right side) ─── */
.auth-card-shell {
  background: rgba(6, 11, 12, 0.98);
  border-left: 1px solid color-mix(in srgb, var(--accent) 15%, transparent);
  box-shadow: -8px 0 40px var(--ui-sombra-2);
  display: flex;
  align-items: center;
  justify-content: center;
}

.auth-card-body {
  width: 100%;
  max-width: 400px;
  padding: 2.5rem 2rem;
}

/* ── Showcase (left side) ─── */
.auth-showcase-shell {
  background-image: url('https://images.pexels.com/photos/574071/pexels-photo-574071.jpeg?auto=compress&cs=tinysrgb&w=1920&h=1280&dpr=1');
  background-size: cover;
  background-position: center;
  color: #ffffff;
  position: relative;
  overflow: hidden;
}

/* Overlay de marca — oscuro developer con acento teal */
.auth-showcase-shell::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(150deg,
    rgba(4, 10, 12, 0.93) 0%,
    rgba(6, 28, 38, 0.84) 50%,
    color-mix(in srgb, var(--brand-dark) 70%, transparent) 100%);
  z-index: 0;
}

/* Brillo teal ambiental — firma visual CodeLab */
.auth-showcase-shell::after {
  content: '';
  position: absolute;
  bottom: -15%;
  left: -5%;
  width: 320px;
  height: 320px;
  background: radial-gradient(circle, color-mix(in srgb, var(--accent) 20%, transparent), transparent 60%);
  pointer-events: none;
  z-index: 0;
}

.auth-showcase-body {
  padding: 3rem 2.5rem;
  position: relative;
  z-index: 1;
  height: 100%;
}

/* ── Feature list ─── */
.auth-feature-list {
  display: grid;
  gap: 0.85rem;
  margin-top: 1.35rem;
}

.auth-feature-item {
  display: flex;
  align-items: flex-start;
  gap: 0.85rem;
  padding: 1rem 1.1rem;
  border-radius: var(--ui-radius-surface);
  background: var(--ui-velo-2);
  border: 1px solid var(--ui-velo-4);
  transition: background 0.2s ease, border-color 0.2s ease;
}

.auth-feature-item:hover {
  background: var(--ui-velo-4);
  border-color: color-mix(in srgb, var(--accent) 30%, transparent);
}

/* Colored left accent per item */
.auth-feature-item:nth-child(1) {
  border-left: 3px solid var(--brand);
}

.auth-feature-item:nth-child(2) {
  border-left: 3px solid var(--accent);
}

.auth-feature-item:nth-child(3) {
  border-left: 3px solid var(--accent-orange);
}

.auth-feature-item .material-symbols-rounded {
  color: var(--brand);
  margin-top: 0.1rem;
  flex-shrink: 0;
}

.auth-feature-item:nth-child(2) .material-symbols-rounded {
  color: var(--accent);
}

.auth-feature-item:nth-child(3) .material-symbols-rounded {
  color: var(--accent-orange);
}

.auth-feature-copy strong,
.auth-showcase-shell h1,
.auth-showcase-shell p,
.auth-showcase-shell .eyebrow {
  color: #ffffff;
}

.auth-showcase-shell .eyebrow {
  background: color-mix(in srgb, var(--brand) 15%, transparent);
  border-color: color-mix(in srgb, var(--brand) 30%, transparent);
  color: var(--brand);
}

.auth-showcase-shell h1 {
  font-size: clamp(1.6rem, 2.5vw, 2.1rem);
  letter-spacing: -0.03em;
  line-height: 1.25;
}

/* ── Public note strip ─── */
.public-note-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 1.1rem;
}

.public-note-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.42rem 0.82rem;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-velo-3);
  border: 1px solid var(--ui-velo-4);
  font-size: var(--ui-text-sm);
  font-weight: 700;
  color: #ffffff;
}

.public-note-chip .material-symbols-rounded {
  font-size: var(--ui-text-base);
  color: var(--brand);
}

/* ── Auth card heading + footer text ─── */
.auth-card-title {
  color: #ffffff;
  font-size: var(--ui-text-xl);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin-bottom: 1.5rem;
}

.auth-trust-text {
  margin: 0.8rem 0 0;
  text-align: center;
  color: rgba(255, 255, 255, 0.4);
  font-size: var(--ui-text-xs);
  font-weight: 600;
  letter-spacing: 0.03em;
}

.auth-footer-note {
  margin: 1.25rem 0 0;
  text-align: center;
  color: var(--muted, var(--ui-text-faint));
  font-size: var(--ui-text-md);
}

.auth-footer-note a {
  color: var(--accent);
  text-decoration: none;
  font-weight: 600;
}

.auth-footer-note a:hover {
  color: var(--brand);
}

/* ── Mini brand strip at bottom of card ─── */
.auth-card-shell {
  position: relative;
}

.auth-mini-footer {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 0.75rem 1rem;
  border-top: 1px solid color-mix(in srgb, var(--accent) 10%, transparent);
  background: rgba(4, 8, 9, 0.7);
  color: rgba(255, 255, 255, 0.3);
  font-size: var(--ui-text-xs);
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.auth-mini-footer .material-symbols-rounded {
  font-size: var(--ui-text-md);
  color: var(--accent);
  opacity: 0.65;
}

/* ── Forgot password link ─── */
.auth-link-subtle {
  color: rgba(255, 255, 255, 0.4);
  font-size: var(--ui-text-sm);
  text-decoration: none;
  transition: color 0.2s ease;
}

.auth-link-subtle:hover {
  color: var(--accent);
}

/* ── Showcase integration note ─── */
.auth-showcase-integration-note {
  margin-top: 1.5rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--ui-velo-4);
  color: rgba(255, 255, 255, 0.42);
  font-size: var(--ui-text-sm);
  line-height: 1.5;
}

@media (max-width: 991.98px) {
  .auth-panel-grid {
    grid-template-columns: 1fr;
    min-height: unset;
  }

  .auth-showcase-shell {
    min-height: 320px;
  }

  .auth-card-shell {
    border-left: none;
    border-top: 1px solid color-mix(in srgb, var(--accent) 15%, transparent);
    box-shadow: 0 -4px 24px var(--ui-sombra-1);
  }

  .auth-card-body {
    max-width: 100%;
    padding: 2rem 1.5rem 2.5rem;
  }
}

/* ── Cabecera de página sencilla ──
   `.page-section` / `.page-header` / `.page-title` se usaban en las pantallas
   de administración pero nunca llegaron a existir en el CSS: por eso salían
   sin estilo, con el título a pelo y la tabla en blanco. Se definen aquí para
   que toda esa sección herede la estética del resto sin reescribirla. */
.page-section {
  margin-bottom: 2rem;
}
.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.25rem;
  padding-bottom: 0.9rem;
  border-bottom: 1px solid var(--ui-velo-3);
}
.page-title {
  margin: 0;
  font-family: var(--xestio-font);
  font-size: var(--ui-text-xl);
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--ui-text);
}
.page-subtitle {
  margin: 0.25rem 0 0;
  font-size: var(--ui-text-md);
  color: var(--ui-text-faint);
}



/* ── components.css ── */

.auth-card-title {
  margin-bottom: 0.75rem;
  color: var(--text);
  letter-spacing: -0.02em;
}

.auth-card-intro {
  color: var(--muted);
  margin-bottom: 1.25rem;
  font-size: var(--ui-text-base);
}

.auth-form-actions {
  display: grid;
  gap: 0.75rem;
  margin-top: 1.35rem;
}

.auth-footer-note {
  margin-top: 1.25rem;
  margin-bottom: 0;
  color: var(--muted);
  font-size: var(--ui-text-md);
}

.auth-footer-note a {
  color: var(--brand);
  font-weight: 600;
  text-decoration: none;
}

.auth-footer-note a:hover {
  color: var(--accent);
  text-decoration: underline;
}

/* ── Link color inside auth card (forgot password, etc.) ─── */
.auth-card-body a:not(.btn) {
  color: var(--accent);
  font-weight: 600;
  text-decoration: none;
}

.auth-card-body a:not(.btn):hover {
  color: var(--brand);
  text-decoration: underline;
}

/* ── Showcase vertical centering ─── */
.auth-showcase-body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 100%;
  height: 100%;
}

.auth-help-block {
  margin-top: 1rem;
  padding: 0.9rem 1rem;
  border-radius: var(--ui-radius-surface);
  background: color-mix(in srgb, var(--brand-dark) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 14%, transparent);
}

.auth-help-block p:last-child {
  margin-bottom: 0;
}

.auth-feature-copy strong {
  display: block;
  font-size: var(--ui-text-base);
  margin-bottom: 0.2rem;
}

.auth-feature-copy div {
  color: rgba(255, 255, 255, 0.72);
  font-size: var(--ui-text-md);
  line-height: 1.5;
}

/* Control de práctica evaluable dentro de la ficha de clase */
.practica-control {
  margin-top: .6rem;
  padding: .6rem .8rem;
  border: 1px dashed var(--ui-velo-4);
  border-radius: var(--ui-radius-control);
  font-size: var(--ui-text-sm);
}
.practica-control > summary {
  display: flex;
  align-items: center;
  gap: .4rem;
  cursor: pointer;
  list-style: none;
  color: var(--ui-text-faint);
}
.practica-control > summary::-webkit-details-marker { display: none; }
.practica-control > summary:hover { color: var(--ui-text); }
.practica-control > summary .material-symbols-rounded { font-size: 16px; color: var(--brand); }
.practica-control[open] > summary { margin-bottom: .8rem; color: var(--ui-text); }

/* ═══════════════════════════════════════════════
   AULA: tutoriales por módulo → UF → tema
   En plano, con decenas de tutoriales, era ilegible.
═══════════════════════════════════════════════ */
.aula-modulo { margin-bottom: 1.5rem; }
.aula-modulo:last-child { margin-bottom: 0; }
.aula-modulo-titulo {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  margin: 0 0 .75rem;
  font-family: var(--xestio-font);
  font-size: var(--ui-text-base); font-weight: 700; color: var(--ui-text);
}
.aula-unidad-titulo {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  margin: 1rem 0 .5rem;
  font-size: var(--ui-text-sm); font-weight: 700; color: var(--ui-text-soft);
}
.aula-cod {
  font-family: 'Fira Code', monospace;
  font-size: var(--ui-text-xs); font-weight: 700;
  color: var(--brand);
  background: color-mix(in srgb, var(--brand) 7%, transparent);
  border: 1px solid color-mix(in srgb, var(--brand) 25%, transparent);
  border-radius: var(--ui-radius-control); padding: .1rem .45rem;
}
.aula-cod-uf {
  color: var(--ui-info);
  background: rgba(125, 211, 252, 0.07);
  border-color: rgba(125, 211, 252, 0.25);
}
.aula-cuenta {
  margin-left: auto;
  font-size: var(--ui-text-xs); font-family: monospace;
  color: var(--ui-text-faint);
  background: var(--ui-velo-2);
  border-radius: var(--ui-radius-pill); padding: .1rem .5rem;
}
.aula-tema {
  margin-left: .35rem;
  padding-left: .8rem;
  border-left: 2px solid rgba(125, 211, 252, 0.15);
  margin-bottom: .5rem;
}
.aula-tema > summary {
  display: flex; align-items: center; gap: .5rem;
  cursor: pointer; list-style: none;
  padding: .3rem 0;
  font-size: var(--ui-text-md); color: var(--ui-text-faint);
}
.aula-tema > summary::-webkit-details-marker { display: none; }
.aula-tema > summary:hover { color: var(--ui-text); }
.aula-tema[open] > summary { color: var(--ui-text); }
.aula-tema-nombre { font-weight: 600; }

/* ── «Continúa por aquí» ──
   La única pieza del aula que compite por el primer golpe de vista, así que
   se le da el peso: superficie propia, el título grande y el resto en voz
   baja. Es un <a> entero, no una tarjeta con un botón dentro: el objetivo de
   pulsación es toda la caja, que en móvil es la diferencia entre acertar y
   no. */
.aula-continuar {
  display: grid;
  grid-template-areas:
    "etiqueta ir"
    "titulo   ir"
    "pie      ir";
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--ui-space-1) var(--ui-space-4);
  margin-bottom: var(--ui-space-4);
  padding: var(--ui-space-4) var(--ui-space-5);
  border: 1px solid var(--ui-line);
  border-left: 3px solid var(--brand);
  border-radius: var(--ui-radius-surface);
  background: var(--ui-surface-soft);
  text-decoration: none;
  transition: border-color var(--ui-duration-fast) var(--ui-ease-out),
              background var(--ui-duration-fast) var(--ui-ease-out);
}
.aula-continuar:hover,
.aula-continuar:focus-visible {
  background: var(--ui-surface-alt);
  border-color: var(--ui-line-strong);
}
.aula-continuar-etiqueta {
  grid-area: etiqueta;
  display: flex;
  align-items: center;
  gap: var(--ui-space-2);
  font-size: var(--ui-text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--brand);
}
.aula-continuar-etiqueta .material-symbols-rounded { font-size: 18px; }
.aula-continuar-titulo {
  grid-area: titulo;
  font-size: var(--ui-text-lg);
  font-weight: 700;
  color: var(--ui-text);
}
.aula-continuar-pie {
  grid-area: pie;
  display: flex;
  align-items: center;
  gap: var(--ui-space-2);
  flex-wrap: wrap;
  font-size: var(--ui-text-sm);
  color: var(--ui-text-faint);
}
/* La barra solo aparece en los temas con pasos: donde no los hay, el avance
   no tiene medias tintas y dibujarla insinuaría una precisión inexistente. */
.aula-continuar-barra {
  display: block;
  width: 120px;
  height: 6px;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-velo-2);
  overflow: hidden;
}
.aula-continuar-barra > span {
  display: block;
  height: 100%;
  background: var(--brand);
}
.aula-continuar-ir {
  grid-area: ir;
  display: flex;
  align-items: center;
  gap: var(--ui-space-1);
  font-size: var(--ui-text-sm);
  font-weight: 600;
  color: var(--brand);
  white-space: nowrap;
}
.aula-continuar-ir .material-symbols-rounded { font-size: 18px; }
@media (max-width: 575.98px) {
  /* En móvil la flecha se lleva una columna entera para nada: el título ya
     ocupa dos líneas y la caja completa es pulsable. */
  .aula-continuar {
    grid-template-areas: "etiqueta" "titulo" "pie";
    grid-template-columns: minmax(0, 1fr);
  }
  .aula-continuar-ir { display: none; }
}

/* ── Desplegables de acciones ocasionales del aula docente ──
   «Escribir un aviso» y «Añadir contenido» estaban abiertos siempre y se
   llevaban la primera pantalla. Plegados, el resumen tiene que parecer un
   botón: si parece un título, nadie lo pulsa. */
.tablon-escribir > summary,
.biblioteca-panel > summary {
  display: flex;
  align-items: center;
  gap: var(--ui-space-2);
  padding: var(--ui-space-2) var(--ui-space-4);
  margin-bottom: var(--ui-space-3);
  border: 1px solid var(--ui-line);
  border-radius: var(--ui-radius-control);
  background: var(--ui-surface-soft);
  font-size: var(--ui-text-sm);
  font-weight: 600;
  color: var(--ui-text);
  cursor: pointer;
  list-style: none;
}
.tablon-escribir > summary::-webkit-details-marker,
.biblioteca-panel > summary::-webkit-details-marker { display: none; }
.tablon-escribir > summary:hover,
.biblioteca-panel > summary:hover,
.tablon-escribir > summary:focus-visible,
.biblioteca-panel > summary:focus-visible {
  border-color: var(--ui-line-strong);
  background: var(--ui-surface-alt);
}
.tablon-escribir > summary .material-symbols-rounded,
.biblioteca-panel > summary .material-symbols-rounded {
  font-size: 18px;
  color: var(--brand);
}
.tablon-escribir[open] > summary,
.biblioteca-panel[open] > summary {
  border-color: var(--brand);
}

/* ── Aviso del tablón: contexto y cuerpo plegado ── */
.post-contexto {
  display: inline-flex;
  align-items: center;
  gap: var(--ui-space-1);
  padding: 1px var(--ui-space-2);
  border-radius: var(--ui-radius-pill);
  border: 1px solid color-mix(in srgb, var(--brand) 32%, transparent);
  background: color-mix(in srgb, var(--brand) 12%, transparent);
  font-size: var(--ui-text-xs);
  font-weight: 600;
  color: var(--brand);
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.post-contexto .material-symbols-rounded { font-size: 14px; flex-shrink: 0; }

.post-cuerpo > summary {
  display: inline-flex;
  align-items: center;
  gap: var(--ui-space-1);
  margin: var(--ui-space-1) 0;
  font-size: var(--ui-text-xs);
  font-weight: 600;
  color: var(--ui-text-faint);
  cursor: pointer;
  list-style: none;
}
.post-cuerpo > summary::-webkit-details-marker { display: none; }
.post-cuerpo > summary:hover,
.post-cuerpo > summary:focus-visible { color: var(--ui-text); }
.post-cuerpo > summary .material-symbols-rounded {
  font-size: 16px;
  transition: transform var(--ui-duration-fast) var(--ui-ease-out);
}
.post-cuerpo[open] > summary .material-symbols-rounded { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
  .post-cuerpo > summary .material-symbols-rounded { transition: none; }
}

/* ── Cómo va la clase ── */
.seguimiento-senales {
  display: flex;
  align-items: center;
  gap: var(--ui-space-3);
  flex-wrap: wrap;
  margin-top: var(--ui-space-1);
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
}
.seguimiento-avance {
  display: inline-flex;
  align-items: center;
  gap: var(--ui-space-2);
}
.seguimiento-barra {
  display: block;
  width: 64px;
  height: 6px;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-velo-2);
  overflow: hidden;
}
.seguimiento-barra > span {
  display: block;
  height: 100%;
  background: var(--brand);
}
.seguimiento-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--ui-space-1);
  padding: 1px var(--ui-space-2);
  border-radius: var(--ui-radius-pill);
  border: 1px solid color-mix(in srgb, currentColor 32%, transparent);
  background: color-mix(in srgb, currentColor 12%, transparent);
  font-weight: 600;
}
.seguimiento-chip .material-symbols-rounded { font-size: 14px; }
.seguimiento-chip.is-warn { color: var(--ui-warning); }
.seguimiento-chip.is-bad { color: var(--ui-danger); }
.seguimiento-nota {
  margin: var(--ui-space-3) 0 0;
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
}

/* ── Diálogo de compartir en otras aulas ── */
.aula-compartir-cual { font-size: var(--ui-text-sm); }
.aula-compartir-lista option {
  /* Nombres de curso largos: sin esto se cortan y dos aulas del mismo curso
     se vuelven indistinguibles justo donde hay que elegir. */
  white-space: normal;
  padding: var(--ui-space-1) var(--ui-space-2);
}
.aula-compartir-ayuda {
  margin: var(--ui-space-2) 0 0;
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
}

/* ── Atajos a las secciones del aula ──
   Anclas, no pestañas: nada se esconde, así que el buscador del navegador
   sigue encontrando toda la página. */
.aula-atajos {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ui-space-2);
  margin-bottom: var(--ui-space-4);
}
.aula-atajos a {
  display: inline-flex;
  align-items: center;
  gap: var(--ui-space-2);
  padding: var(--ui-space-2) var(--ui-space-4);
  border: 1px solid var(--ui-line-subtle);
  border-radius: var(--ui-radius-pill);
  font-size: var(--ui-text-sm);
  font-weight: 600;
  color: var(--ui-text-soft);
  text-decoration: none;
}
.aula-atajos a:hover,
.aula-atajos a:focus-visible {
  color: var(--ui-text);
  border-color: var(--ui-line-strong);
  background: var(--ui-surface-soft);
}
.aula-atajos .material-symbols-rounded { font-size: 18px; }
.aula-atajos-cuenta {
  padding: 1px var(--ui-space-2);
  border-radius: var(--ui-radius-pill);
  background: var(--ui-velo-2);
  font-size: var(--ui-text-xs);
  font-weight: 600;
  color: var(--ui-text-faint);
}
/* Que el salto no deje el título pegado al borde de arriba. */
#contenidos, #tablon, #material { scroll-margin-top: var(--ui-space-5); }

/* Marca del tema por el que va el alumnado, la misma que anuncia la tarjeta
   de continuar: sin ella, el <details> abierto no explica por qué lo está. */
.aula-tema-aqui {
  padding: 1px var(--ui-space-2);
  border-radius: var(--ui-radius-pill);
  background: var(--ui-velo-2);
  font-size: var(--ui-text-xs);
  font-weight: 600;
  color: var(--brand);
  text-transform: none;
  letter-spacing: 0;
}

/* ── «Ver como alumno»: aviso de que esto no es el aula del docente ──
   Tiene que verse a la primera. Un docente que no se dé cuenta de que está en
   la vista de alumnado puede tomar la ausencia de controles por una avería. */
.aviso-vista-alumno {
  display: flex;
  align-items: center;
  gap: .9rem;
  margin: 1.2rem 0 0;
  padding: .85rem 1.1rem;
  border: 1px solid rgba(56, 189, 248, .35);
  border-left: 3px solid #38bdf8;
  border-radius: 0 var(--ui-radius-control) var(--ui-radius-control) 0;
  background: rgba(56, 189, 248, .08);
  font-size: var(--ui-text-md);
  color: var(--ui-text-soft);
}
.aviso-vista-alumno > .material-symbols-rounded {
  font-size: 22px;
  color: var(--ui-info);
  flex: 0 0 auto;
}
.aviso-vista-alumno > div { flex: 1 1 auto; }
.aviso-vista-alumno strong { color: var(--ui-text); }
.aviso-vista-alumno-nota {
  display: block;
  margin-top: .2rem;
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
}
.aviso-vista-alumno .btn-sm { flex: 0 0 auto; }

/* ═══════════════════════════════════════════════
   ACCESIBILIDAD DE BASE
   Auditoría 12/08/2026, T4. Había once reglas de `:focus` en toda la hoja, y
   ninguna cubría los botones de solo icono del aula: quien navega con teclado
   no veía dónde estaba. Esto es el suelo, no un adorno.
═══════════════════════════════════════════════ */

/* La regla base de `:focus-visible` vive en tokens.css: aquí estaba duplicada
   y solo quedan las excepciones por componente. */

/* Sobre fondo de marca el verde no contrasta consigo mismo. */
.btn-primary:focus-visible,
.btn-header-primary:focus-visible,
.sidebar-link.active:focus-visible {
  outline-color: #ffffff;
}

/* Área táctil mínima en los botones pequeños de acción.
   Los del aula —publicar, abrir, retirar— eran iconos de 14 px pegados unos a
   otros: en pantalla táctil el objetivo quedaba muy por debajo de lo usable, y
   el destructivo era el último de la fila. */
.btn-sm .material-symbols-rounded {
  font-size: 16px;
}

.stack-item .btn-sm,
.aula-tema .btn-sm {
  min-width: 38px;
  min-height: 38px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* El botón que borra datos de alumnado se separa del resto: fallar la
   puntería no puede costar las entregas y las notas de una clase. */
.stack-item .btn-outline-danger {
  margin-left: 0.5rem;
}

@media (pointer: coarse) {
  .stack-item .btn-sm,
  .aula-tema .btn-sm {
    min-width: 44px;
    min-height: 44px;
  }
}

/* ── Deshabilitado ──
   Auditoría 14/08/2026. En las 37 hojas no había ni una regla `:disabled`: lo
   único que separaba un botón muerto de uno vivo era el `opacity: .65` que trae
   Bootstrap de serie. Sobre el fondo oscuro de Codelab ese 65 % apenas se
   distingue, así que el botón parecía pulsable, se pulsaba, y no pasaba nada
   —que es la peor forma de decir «esto ahora no se puede»—.

   Van las tres señales juntas y no solo la opacidad, porque una sola es
   ambigua: color de texto apagado, superficie hundida y `not-allowed`. El
   cursor es el que resuelve la duda antes de hacer clic.

   `--ui-text-disabled` está documentado en tokens.css como el único gris que NO
   cumple AA por debajo de 1,2rem. Aquí es correcto justamente por eso: un
   control deshabilitado no debe leerse como contenido activo. */
.btn:disabled,
.btn.disabled,
.btn-icon:disabled,
button:disabled,
[aria-disabled="true"] {
  color: var(--ui-text-disabled);
  background: var(--ui-velo-1);
  border-color: var(--ui-line-subtle);
  cursor: not-allowed;
  box-shadow: none;
  opacity: 1; /* la opacidad de Bootstrap sobra: aquí se dice con color */
}

/* Un control deshabilitado no reacciona al puntero: si se ilumina al pasar por
   encima, vuelve a prometer algo que no va a cumplir. */
.btn:disabled:hover,
.btn.disabled:hover,
.btn-icon:disabled:hover,
button:disabled:hover,
[aria-disabled="true"]:hover {
  color: var(--ui-text-disabled);
  background: var(--ui-velo-1);
  border-color: var(--ui-line-subtle);
  transform: none;
}

/* ── Pulsado ──
   Había 101 reglas `:hover` y **una** `:active`. En móvil `:hover` no existe,
   así que pulsar no producía ninguna respuesta visual: el único acuse de recibo
   era que la página cambiara, y hasta entonces la duda es si el toque ha
   entrado. Con conexión lenta eso se traduce en pulsar tres veces.

   Un hundimiento de 1 px y la veladura un escalón más marcada. Sale por
   `transform`, que va al compositor y no provoca reflujo; y con
   `prefers-reduced-motion` la duración ya cae a 0 desde tokens.css, así que el
   estado sigue viéndose pero sin animación. */
.btn:active:not(:disabled):not(.disabled),
.btn-icon:active:not(:disabled),
.sidebar-link:active,
.stack-item:active {
  transform: translateY(1px);
  transition-duration: var(--ui-duration-fast);
}

/* ── Suelo tipográfico ──
   Eran 37 declaraciones de 9, 10 y 11 px escritas a mano en las plantillas, y
   entre ellas los plazos de entrega y los estados, que son de lo más
   consultado. Se levantaron con un `max(12px, …)` sobre estas tres clases:
   un parche honesto, pero que dejaba fuera todo lo demás.

   Ahora el suelo es la propia escala —`--ui-text-xs` son 12 px y por debajo no
   hay escalón—, así que esto ya no compensa nada: solo dice que estos tres
   sitios son metadatos. */
.stack-item-subtitle,
.header-stat-chip,
.form-text {
  font-size: var(--ui-text-xs);
}

/* ── Fórmulas LaTeX (app/services/formulas.py) ──
   Llegan como <img> con un SVG de trazos negros: una imagen no hereda el
   color del texto, así que sobre el fondo oscuro desaparecían. En oscuro se
   invierten; el giro de tono deja los colores, si los hubiera, en su sitio. */
img.math {
  display: inline-block;
  max-width: 100%;
  filter: invert(0.92) hue-rotate(180deg);
}
:root[data-theme="light"] img.math {
  filter: none;
}
.math-display {
  text-align: center;
  margin: 1rem 0;
  overflow-x: auto;
}
code.math-error {
  white-space: pre-wrap;
}



/* ── visibility.css ── */

/* ═══════════════════════════════════════════════
   SEMÁFORO DE VISIBILIDAD
   Responde «¿lo ve el alumnado?» y, si no, por qué.
   Se despliega con <details> nativo — sin JavaScript.
═══════════════════════════════════════════════ */

.vis-panel {
  border: 1px solid var(--vis-accent, var(--ui-velo-4));
  border-left: 3px solid var(--vis-accent, var(--ui-velo-4));
  border-radius: var(--ui-radius-control);
  background: var(--ui-surface-soft);
  margin-bottom: 1rem;
  overflow: hidden;
}

.vis-panel-ok {
  --vis-accent: color-mix(in srgb, var(--brand) 45%, transparent);
  --vis-fg: var(--codelab-accent);
}
.vis-panel-warn {
  --vis-accent: rgba(251, 191, 36, 0.5);
  --vis-fg: #fbbf24;
}
.vis-panel-fail {
  --vis-accent: rgba(248, 113, 113, 0.55);
  --vis-fg: #f87171;
}

/* ── Cabecera clicable ── */
.vis-summary {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.7rem 0.95rem;
  cursor: pointer;
  list-style: none;
  user-select: none;
  transition: background 0.15s ease;
}
.vis-summary::-webkit-details-marker {
  display: none;
}
.vis-summary:hover {
  background: var(--ui-velo-1);
}
.vis-panel > .vis-summary:focus-visible {
  outline: 2px solid var(--vis-accent);
  outline-offset: -2px;
}

.vis-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--vis-fg, var(--ui-text-faint));
  flex-shrink: 0;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--vis-fg, var(--ui-text-faint)) 18%, transparent);
}

.vis-headline {
  font-weight: 600;
  font-size: var(--ui-text-md);
  color: var(--ui-text);
  flex: 1;
  min-width: 0;
}

.vis-scope {
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 40%;
}

.vis-toggle {
  font-size: var(--ui-text-xs);
  color: var(--vis-fg, var(--ui-text-faint));
  white-space: nowrap;
  border: 1px solid var(--vis-accent);
  border-radius: var(--ui-radius-pill);
  padding: 2px 10px;
}
.vis-panel[open] .vis-toggle::after {
  content: ' ▴';
}
.vis-panel:not([open]) .vis-toggle::after {
  content: ' ▾';
}

/* ── Lista de comprobaciones ── */
.vis-checks {
  list-style: none;
  margin: 0;
  padding: 0.25rem 0.95rem 0.85rem;
  border-top: 1px solid var(--ui-velo-2);
}

.vis-check {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--ui-velo-2);
}
.vis-check:last-child {
  border-bottom: none;
}

.vis-check-icon {
  font-size: 18px;
  flex-shrink: 0;
  margin-top: 1px;
}
.vis-check-ok .vis-check-icon {
  color: var(--brand);
}
.vis-check-warn .vis-check-icon {
  color: var(--ui-warning);
}
.vis-check-fail .vis-check-icon {
  color: var(--ui-danger);
}

.vis-check-body {
  flex: 1;
  min-width: 0;
}
.vis-check-label {
  display: block;
  font-size: var(--ui-text-md);
  color: var(--ui-text-soft);
}
.vis-check-fail .vis-check-label,
.vis-check-warn .vis-check-label {
  color: var(--ui-text);
  font-weight: 600;
}
.vis-check-detail {
  display: block;
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
  margin-top: 2px;
  line-height: 1.5;
}

.vis-check-fix {
  flex-shrink: 0;
  margin: 0;
}

/* ── Variante compacta para listas ── */
.vis-inline {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
  white-space: nowrap;
}

@media (max-width: 575.98px) {
  .vis-summary {
    flex-wrap: wrap;
  }
  .vis-scope {
    max-width: 100%;
    order: 3;
    flex-basis: 100%;
  }
  .vis-check {
    flex-wrap: wrap;
  }
  .vis-check-fix {
    margin-left: 2.2rem;
  }
}



/* ── today.css ── */

/* ═══════════════════════════════════════════════
   «¿QUÉ TOCA AHORA?»
   Franja de contexto + clases de hoy + pendientes.
   Un solo protagonista por pantalla: lo accionable arriba.
═══════════════════════════════════════════════ */

/* ── Franja de contexto ── */
.now-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1.4rem;
  padding: 0.85rem 1.1rem;
  margin-bottom: 1.25rem;
  border-radius: var(--ui-radius-surface);
  background: var(--ui-surface-soft);
  border: 1px solid var(--ui-velo-3);
}

.now-fact {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  font-size: var(--ui-text-md);
  color: var(--ui-text-faint);
  text-decoration: none;
}
a.now-fact:hover {
  color: var(--ui-text);
}
/* La cifra en color de acento y no en el color del texto: es el dato por el
   que se entra a mirar la tira, y en negro sobre blanco quedaba al mismo peso
   que la palabra que lo acompaña. Los estados de aviso y de directo la pisan,
   que para eso son excepciones. */
.now-fact-value {
  font-size: var(--ui-text-xl);
  font-weight: 700;
  line-height: 1;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
/* Un cero no es una noticia: se apaga para que la vista vaya a los que no lo
   son. Lo pone la plantilla cuando el recuento es cero. */
.now-fact-cero .now-fact-value {
  color: var(--ui-text-faint);
}
.now-fact-alert .now-fact-value {
  color: var(--ui-warning);
}
.now-fact-live .now-fact-value {
  color: var(--ui-danger);
}
.now-sep {
  width: 1px;
  align-self: stretch;
  background: var(--ui-velo-3);
}
.now-empty {
  font-size: var(--ui-text-md);
  color: var(--ui-text-faint);
}

/* ── Lista de clases / tarjetas accionables ── */
.now-list {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

/* Raíl de color a la izquierda, como las tarjetas de Gesttation. El color lo
   trae cada fila en `--fila-color` —la modalidad de la clase, que ya viene en
   el dato—, así que la lista se recorre distinguiendo presencial de online sin
   leer una palabra. Sin ese dato cae en el acento, que es lo que pasa en las
   filas de entregas.

   El raíl va en `box-shadow` interior y no en `border-left`: así no desplaza
   el contenido ni pelea con el borde de la fila. */
.now-row {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 0.7rem 0.9rem 0.7rem 1.05rem;
  border-radius: var(--ui-radius-control);
  background: var(--ui-surface-alt);
  border: 1px solid var(--ui-velo-2);
  box-shadow: inset 3px 0 0 var(--fila-color, var(--accent));
  text-decoration: none;
  color: inherit;
  transition: border-color var(--ui-duration), background var(--ui-duration);
}
.now-row:hover {
  background: color-mix(in srgb, var(--fila-color, var(--accent)) 10%, var(--ui-surface-alt));
  border-color: color-mix(in srgb, var(--fila-color, var(--accent)) 40%, transparent);
}
.now-row:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--accent) 60%, transparent);
  outline-offset: 2px;
}

/* La hora toma el color de la modalidad: es el mismo recurso que el raíl,
   repetido donde la vista se posa primero. */
.now-time {
  font-family: ui-monospace, "JetBrains Mono", "Fira Code", monospace;
  font-size: var(--ui-text-md);
  font-weight: 700;
  color: var(--fila-color, var(--ui-text-soft));
  min-width: 3.4rem;
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}
.now-time-empty {
  color: var(--ui-text-faint);
}

.now-body {
  flex: 1;
  min-width: 0;
}
.now-title {
  display: block;
  font-weight: 600;
  font-size: var(--ui-text-base);
  color: var(--ui-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.now-meta {
  display: block;
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
  margin-top: 2px;
}

.now-badge {
  flex-shrink: 0;
  font-size: var(--ui-text-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 3px 9px;
  border-radius: var(--ui-radius-pill);
  border: 1px solid currentColor;
}
.now-badge-live {
  color: var(--ui-danger);
}
.now-badge-overdue {
  color: var(--ui-danger);
}
.now-badge-today {
  color: var(--ui-warning);
}
.now-badge-soon {
  color: var(--ui-warning);
}
.now-badge-normal {
  color: var(--ui-text-faint);
}

/* ── Tarjeta «Continuar» del alumnado ── */
.continue-card {
  display: flex;
  align-items: center;
  gap: 1.2rem;
  padding: 1.25rem 1.4rem;
  margin-bottom: 1.25rem;
  border-radius: var(--ui-radius-surface);
  background: linear-gradient(135deg, #0A1C1D 0%, #0F3D3E 60%, var(--accent) 130%);
  border: 1px solid color-mix(in srgb, var(--accent) 22%, transparent);
  text-decoration: none;
  color: inherit;
  transition: border-color 0.15s ease;
}
.continue-card:hover {
  border-color: color-mix(in srgb, var(--accent) 50%, transparent);
}
.continue-card:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--accent) 60%, transparent);
  outline-offset: 2px;
}

.continue-body {
  flex: 1;
  min-width: 0;
}
.continue-eyebrow {
  display: block;
  font-size: var(--ui-text-xs);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 0.35rem;
}
.continue-title {
  display: block;
  font-size: var(--ui-text-lg);
  font-weight: 700;
  color: var(--ui-text-strong);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.continue-step {
  display: block;
  font-size: var(--ui-text-sm);
  color: var(--ui-text-soft);
  margin-top: 3px;
}

.continue-track {
  height: 5px;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-velo-4);
  overflow: hidden;
  margin-top: 0.75rem;
}
.continue-fill {
  height: 100%;
  border-radius: var(--ui-radius-pill);
  background: var(--brand);
}
.continue-progress-label {
  display: block;
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
  margin-top: 0.35rem;
}

.continue-cta {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.6rem 1.15rem;
  border-radius: var(--ui-radius-control);
  background: var(--brand);
  color: var(--brand-contrast);
  font-weight: 700;
  font-size: var(--ui-text-md);
}

@media (max-width: 575.98px) {
  .now-strip {
    gap: 0.5rem 1rem;
  }
  .now-sep {
    display: none;
  }
  .continue-card {
    flex-direction: column;
    align-items: stretch;
    gap: 0.9rem;
  }
  .continue-cta {
    justify-content: center;
  }
  .now-row {
    flex-wrap: wrap;
  }
}



/* ── reader.css ── */

/* ═══════════════════════════════════════════════
   LECTOR DE TUTORIAL — vista única del alumnado

   Sustituye a read.html (documento Markdown) y student_view.html (pasos en
   paneles): antes el alumno caía en una u otra según si content_md estaba
   relleno, sin saber por qué. Ahora es un solo documento con un solo índice,
   donde el contenido Markdown y los pasos son secciones del mismo texto.

   Mobile-first: una columna por defecto, índice lateral a partir de 992px.
═══════════════════════════════════════════════ */

.reader {
  display: block;
  max-width: 100%;
}

/* ── Barra de progreso real (pasos hechos, no scroll) ── */
.reader-progress {
  position: sticky;
  top: 0;
  z-index: 40;
  height: 4px;
  background: var(--ui-line-subtle);
  border-radius: var(--ui-radius-pill);
  overflow: hidden;
  margin-bottom: var(--ui-space-5);
}
.reader-progress-fill {
  height: 100%;
  width: 0;
  background: var(--brand);
  border-radius: var(--ui-radius-pill);
  transition: width var(--ui-duration) var(--ui-ease-out);
}

/* ── Cabecera editorial ── */
.reader-breadcrumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  font-size: var(--ui-text-sm);
  color: var(--ui-text-faint);
  margin-bottom: var(--ui-space-4);
}
.reader-breadcrumb a {
  color: var(--ui-text-faint);
  text-decoration: none;
}
.reader-breadcrumb a:hover {
  color: var(--ui-text);
}
.reader-breadcrumb .sep {
  opacity: 0.5;
}
.reader-breadcrumb .current {
  color: var(--ui-text-soft);
}

.reader-header {
  padding-bottom: var(--ui-space-5);
  border-bottom: 1px solid var(--ui-line-subtle);
  margin-bottom: var(--ui-space-6);
}
.reader-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ui-space-2);
  margin-bottom: var(--ui-space-3);
}
.reader-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 10px;
  border: 1px solid var(--ui-line);
  border-radius: var(--ui-radius-pill);
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
  white-space: nowrap;
}
.reader-chip .material-symbols-rounded {
  font-size: 13px;
}

.reader-title {
  font-size: clamp(1.6rem, 1.1rem + 2.2vw, 2.4rem);
  font-weight: 800;
  line-height: 1.15;
  color: var(--ui-text-strong);
  margin: 0 0 var(--ui-space-3);
}
.reader-description {
  font-size: var(--ui-text-lg);
  color: var(--ui-text-faint);
  line-height: var(--ui-leading-prose);
  margin: 0 0 var(--ui-space-4);
}
.reader-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ui-space-2);
}

/* ── Resumen de progreso ── */
.reader-progress-summary {
  display: flex;
  align-items: center;
  gap: var(--ui-space-3);
  padding: 0.7rem 1rem;
  margin-bottom: var(--ui-space-5);
  border-radius: var(--ui-radius-control);
  background: var(--ui-surface-soft);
  border: 1px solid var(--ui-line-subtle);
  font-size: var(--ui-text-sm);
  color: var(--ui-text-faint);
}
.reader-progress-summary strong {
  color: var(--ui-text);
}
.reader-progress-summary .material-symbols-rounded {
  font-size: 18px;
  color: var(--brand);
}

/* ── Índice ── */
.reader-index {
  margin-bottom: var(--ui-space-6);
  border: 1px solid var(--ui-line-subtle);
  border-radius: var(--ui-radius-control);
  background: var(--ui-surface-soft);
  overflow: hidden;
}
.reader-index > summary {
  display: flex;
  align-items: center;
  gap: var(--ui-space-2);
  padding: 0.75rem 1rem;
  cursor: pointer;
  font-weight: 600;
  font-size: var(--ui-text-sm);
  color: var(--ui-text-soft);
  list-style: none;
}
.reader-index > summary::-webkit-details-marker {
  display: none;
}
.reader-index > summary::after {
  content: '▾';
  margin-left: auto;
  color: var(--ui-text-faint);
}
.reader-index[open] > summary::after {
  content: '▴';
}

.reader-index-list {
  list-style: none;
  margin: 0;
  padding: 0 0.6rem 0.7rem;
}
.reader-index-item {
  display: flex;
  align-items: center;
  gap: var(--ui-space-3);
  padding: 0.45rem 0.6rem;
  border-radius: var(--ui-radius-control);
  text-decoration: none;
  color: var(--ui-text-faint);
  font-size: var(--ui-text-sm);
  transition: background var(--ui-duration-fast), color var(--ui-duration-fast);
}
.reader-index-item:hover {
  background: var(--ui-velo-2);
  color: var(--ui-text);
}
.reader-index-item.is-current {
  color: var(--brand);
  background: color-mix(in srgb, var(--brand) 6%, transparent);
}
.reader-index-num {
  font-family: var(--ui-font-mono);
  font-size: var(--ui-text-xs);
  font-weight: 700;
  color: var(--ui-text-disabled);
  min-width: 1.6rem;
  flex-shrink: 0;
}
.reader-index-item.is-done .reader-index-num {
  color: var(--brand);
}
.reader-index-text {
  flex: 1;
  min-width: 0;
}
.reader-index-check {
  font-size: var(--ui-text-base);
  flex-shrink: 0;
  color: var(--brand);
}
.reader-index-sub {
  padding-left: 2.2rem;
  font-size: var(--ui-text-xs);
}

/* ── Cuerpo del documento ── */
.reader-section {
  margin-bottom: var(--ui-space-7);
  scroll-margin-top: var(--ui-space-5);
}

.reader-step-header {
  display: flex;
  align-items: flex-start;
  gap: var(--ui-space-3);
  padding-top: var(--ui-space-5);
  border-top: 1px solid var(--ui-line-subtle);
  margin-bottom: var(--ui-space-4);
}
.reader-section:first-of-type .reader-step-header {
  border-top: none;
  padding-top: 0;
}
.reader-step-num {
  font-family: var(--ui-font-mono);
  font-size: var(--ui-text-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--brand);
  padding-top: 6px;
  min-width: 2.6rem;
  flex-shrink: 0;
}
.reader-step-main {
  flex: 1;
  min-width: 0;
}
.reader-step-title {
  font-size: var(--ui-text-xl);
  font-weight: 700;
  color: var(--ui-text-strong);
  margin: 0 0 var(--ui-space-2);
  line-height: 1.25;
}
.reader-step-summary {
  color: var(--ui-text-faint);
  font-size: var(--ui-text-base);
  line-height: 1.65;
  margin: 0 0 var(--ui-space-2);
}

/* ── Casilla «Hecho» ── */
.reader-done-form {
  flex-shrink: 0;
  margin: 0;
}
.reader-done-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0.35rem 0.8rem;
  border-radius: var(--ui-radius-pill);
  border: 1px solid var(--ui-line-strong);
  background: transparent;
  color: var(--ui-text-faint);
  font-size: var(--ui-text-xs);
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--ui-duration-fast), color var(--ui-duration-fast),
    border-color var(--ui-duration-fast);
}
.reader-done-btn:hover {
  color: var(--ui-text);
  border-color: var(--brand);
}
.reader-done-btn .material-symbols-rounded {
  font-size: 16px;
}
.reader-done-btn.is-done {
  background: color-mix(in srgb, var(--brand) 10%, transparent);
  border-color: color-mix(in srgb, var(--brand) 45%, transparent);
  color: var(--brand);
}

/* ── Bloques ── */
.reader-block {
  margin-bottom: var(--ui-space-4);
}
.reader-block-label {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--ui-text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 2px 8px;
  border-radius: var(--ui-radius-control);
  margin-bottom: 0.45rem;
  color: var(--rb-color, var(--ui-text-faint));
  /* Fallback primero: color-mix() no existe antes de Chrome 111 y en aulas
     hay equipos viejos. Sin él, el fondo se quedaría sin declarar. */
  background: var(--ui-velo-2);
  background: color-mix(in srgb, var(--rb-color, var(--ui-text-faint)) 12%, transparent);
}
.reader-block-label .material-symbols-rounded {
  font-size: 13px;
}

.reader-block-body {
  background: var(--ui-velo-1);
  border: 1px solid var(--ui-line);
  border-radius: var(--ui-radius-control);
  padding: 1.1rem 1.35rem;
  font-size: var(--ui-text-base);
  line-height: 1.78;
  color: var(--ui-text-soft);
}
.reader-block-body > *:last-child {
  margin-bottom: 0;
}

/* Color por tipo de bloque, desde los tokens */
.rb-theory   { --rb-color: var(--ui-block-theory); }
.rb-code     { --rb-color: var(--ui-block-code); }
.rb-exercise { --rb-color: var(--ui-block-exercise); }
.rb-hint     { --rb-color: var(--ui-block-hint); }
.rb-solution { --rb-color: var(--ui-block-solution); }
.rb-video    { --rb-color: var(--ui-block-video); }
.rb-file     { --rb-color: var(--ui-block-file); }
.rb-quiz     { --rb-color: var(--ui-block-quiz); }
.rb-resource { --rb-color: var(--ui-block-resource); }

.rb-exercise .reader-block-body,
.rb-hint .reader-block-body,
.rb-solution .reader-block-body {
  /* Sin color-mix() se queda el fondo y borde neutros de .reader-block-body:
     pierde el matiz de color pero sigue legible. */
  background: color-mix(in srgb, var(--rb-color) 4%, transparent);
  border-color: color-mix(in srgb, var(--rb-color) 18%, transparent);
}
.rb-code .reader-block-body {
  padding: 0;
  overflow: hidden;
}

/* Texto enriquecido dentro de un bloque */
.reader-block-body h1,
.reader-block-body h2,
.reader-block-body h3,
.reader-block-body h4 {
  color: var(--ui-info);
  font-weight: 700;
  margin: 1.3rem 0 0.5rem;
}
.reader-block-body h1 { font-size: var(--ui-text-xl); }
.reader-block-body h2 { font-size: var(--ui-text-lg); }
.reader-block-body h3 { font-size: var(--ui-text-base); }
.reader-block-body p { margin-bottom: 0.75rem; }
.reader-block-body a { color: var(--brand); text-underline-offset: 3px; }
.reader-block-body strong { color: var(--ui-text-strong); }
.reader-block-body code:not(pre code) {
  background: var(--ui-velo-3);
  color: var(--ui-block-code);
  padding: 1px 6px;
  border-radius: var(--ui-radius-control);
  font-size: 0.87em;
  font-family: var(--ui-font-mono);
}
.reader-block-body pre {
  margin: 0;
  padding: 1rem 1.2rem;
  overflow-x: auto;
  background: #0b1220;
  border-radius: var(--ui-radius-control);
}
.rb-code .reader-block-body pre {
  border-radius: 0;
}

/* Cabecera de un bloque de código */
.reader-code-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ui-space-3);
  padding: 0.5rem 1rem;
  background: var(--ui-velo-1);
  border-bottom: 1px solid var(--ui-line-subtle);
  font-size: var(--ui-text-xs);
}
.reader-code-title {
  color: var(--ui-text-soft);
  font-weight: 600;
}
.reader-code-lang {
  font-family: var(--ui-font-mono);
  color: var(--ui-block-code);
  text-transform: uppercase;
}

/* Pista y solución: <details> nativo, cerrado por defecto */
.reader-reveal {
  /* Fallback antes del color-mix: si se descarta, el bloque se quedaría sin
     borde ninguno y no se vería que hay algo plegado. */
  border: 1px solid var(--ui-line);
  border: 1px solid color-mix(in srgb, var(--rb-color) 22%, transparent);
  border-radius: var(--ui-radius-control);
  background: var(--ui-velo-1);
  background: color-mix(in srgb, var(--rb-color) 4%, transparent);
  overflow: hidden;
}
.reader-reveal > summary {
  display: flex;
  align-items: center;
  gap: var(--ui-space-2);
  padding: 0.7rem 1.1rem;
  cursor: pointer;
  font-size: var(--ui-text-md);
  font-weight: 600;
  color: var(--rb-color);
  list-style: none;
}
.reader-reveal > summary::-webkit-details-marker {
  display: none;
}
.reader-reveal > summary::after {
  content: 'Mostrar';
  margin-left: auto;
  font-size: var(--ui-text-xs);
  font-weight: 400;
  opacity: 0.75;
}
.reader-reveal[open] > summary::after {
  content: 'Ocultar';
}
.reader-reveal-body {
  padding: 0 1.1rem 1rem;
  font-size: var(--ui-text-base);
  line-height: 1.78;
  color: var(--ui-text-soft);
}

/* Vídeo responsive */
.reader-video {
  position: relative;
  padding-bottom: 56.25%;
  height: 0;
  border-radius: var(--ui-radius-control);
  overflow: hidden;
}
.reader-video iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* ── Dudas del alumno sobre un paso ── */
.reader-ask {
  margin: var(--ui-space-3) 0 var(--ui-space-4);
  border: 1px dashed var(--ui-line);
  border-radius: var(--ui-radius-control);
  background: var(--ui-velo-1);
}
.reader-ask > summary {
  display: flex;
  align-items: center;
  gap: var(--ui-space-2);
  padding: 0.55rem 0.95rem;
  cursor: pointer;
  font-size: var(--ui-text-sm);
  color: var(--ui-text-faint);
  list-style: none;
}
.reader-ask > summary::-webkit-details-marker {
  display: none;
}
.reader-ask > summary:hover {
  color: var(--ui-text);
}
.reader-ask > summary .material-symbols-rounded {
  font-size: 16px;
  color: var(--ui-block-hint);
}
.reader-ask-body {
  padding: 0 0.95rem 0.9rem;
}

.reader-duda {
  border-left: 2px solid var(--ui-block-hint);
  padding: 0.4rem 0 0.4rem 0.8rem;
  margin-bottom: 0.75rem;
}
.reader-duda.is-answered {
  border-left-color: var(--ui-success);
}
.reader-duda-q {
  margin: 0 0 0.35rem;
  font-size: var(--ui-text-md);
  color: var(--ui-text-soft);
}
.reader-duda-a {
  display: flex;
  gap: 0.4rem;
  margin: 0;
  font-size: var(--ui-text-md);
  color: var(--ui-text);
}
.reader-duda-a .material-symbols-rounded {
  font-size: 15px;
  color: var(--ui-success);
  flex-shrink: 0;
  margin-top: 2px;
}
.reader-duda-espera {
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
  font-style: italic;
}

/* Ficheros */
.reader-files {
  margin-top: var(--ui-space-4);
  padding-top: var(--ui-space-3);
  border-top: 1px dashed var(--ui-line);
}
.reader-files-label {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: var(--ui-text-xs);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--ui-text-faint);
  margin-bottom: var(--ui-space-2);
}
.reader-file-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0.4rem 0.85rem;
  margin: 0 var(--ui-space-2) var(--ui-space-2) 0;
  border-radius: var(--ui-radius-control);
  border: 1px solid var(--ui-line);
  background: var(--ui-velo-1);
  color: var(--ui-text-soft);
  font-size: var(--ui-text-sm);
  text-decoration: none;
  transition: border-color var(--ui-duration-fast), color var(--ui-duration-fast);
}
.reader-file-btn:hover {
  border-color: var(--brand);
  color: var(--ui-text);
}
.reader-file-btn.is-enunciado {
  border-color: rgba(248, 113, 113, 0.4);
  color: var(--ui-danger);
}
.reader-file-btn .material-symbols-rounded {
  font-size: 15px;
}

/* ── Navegación anterior / siguiente ── */
.reader-prevnext {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--ui-space-3);
  margin-top: var(--ui-space-7);
  padding-top: var(--ui-space-5);
  border-top: 1px solid var(--ui-line-subtle);
}
.reader-prevnext-item {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 0.85rem 1.1rem;
  border-radius: var(--ui-radius-control);
  border: 1px solid var(--ui-line);
  text-decoration: none;
  transition: border-color var(--ui-duration-fast);
}
.reader-prevnext-item:hover {
  border-color: var(--brand);
}
.reader-prevnext-item.is-next {
  text-align: right;
}
.reader-prevnext-label {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: var(--ui-text-xs);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--ui-text-faint);
}
.reader-prevnext-item.is-next .reader-prevnext-label {
  justify-content: flex-end;
}
.reader-prevnext-title {
  font-size: var(--ui-text-md);
  font-weight: 600;
  color: var(--ui-text);
}

/* ── Mapa del curso (barra lateral en escritorio) ── */
.reader-course-map {
  border: 1px solid var(--ui-line-subtle);
  border-radius: var(--ui-radius-control);
  background: var(--ui-surface-soft);
  overflow: hidden;
}
.reader-course-map-head {
  display: flex;
  align-items: center;
  gap: var(--ui-space-2);
  padding: 0.75rem 1rem;
  font-size: var(--ui-text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ui-text-faint);
  border-bottom: 1px solid var(--ui-line-subtle);
}
.reader-course-map-head a {
  color: inherit;
  text-decoration: none;
}
/* Acordeón de tres niveles: Módulo → Unidad formativa → Tema. La sangría
   izquierda crece con la profundidad; el resto de la fila comparte estilo. */
.reader-map-module > summary,
.reader-map-unit > summary,
.reader-map-chapter > summary {
  display: flex;
  align-items: center;
  gap: var(--ui-space-2);
  cursor: pointer;
  list-style: none;
  -webkit-user-select: none;
  user-select: none;
}
.reader-map-module > summary::-webkit-details-marker,
.reader-map-unit > summary::-webkit-details-marker,
.reader-map-chapter > summary::-webkit-details-marker {
  display: none;
}
.reader-map-module > summary:hover,
.reader-map-unit > summary:hover,
.reader-map-chapter > summary:hover {
  background: var(--ui-velo-1);
}

/* Punta de flecha dibujada con bordes: gira al abrir y no depende de que la
   fuente de iconos haya cargado. */
.reader-map-module > summary::before,
.reader-map-unit > summary::before,
.reader-map-chapter > summary::before {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
  opacity: 0.5;
  transition: transform 150ms ease;
}
.reader-map-module[open] > summary::before,
.reader-map-unit[open] > summary::before,
.reader-map-chapter[open] > summary::before {
  transform: rotate(45deg);
}
@media (prefers-reduced-motion: reduce) {
  .reader-map-module > summary::before,
  .reader-map-unit > summary::before,
  .reader-map-chapter > summary::before {
    transition: none;
  }
}

/* El nombre se queda con el espacio sobrante y parte las palabras largas: en
   280 px un código de UF sin cortar desbordaba la barra. */
.reader-map-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}

.reader-map-module > summary {
  padding: 0.5rem 0.9rem;
  font-size: var(--ui-text-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--ui-text-soft);
  text-transform: uppercase;
}
.reader-map-unit > summary {
  padding: 0.4rem 0.9rem 0.4rem 1.4rem;
  font-size: var(--ui-text-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--ui-text-faint);
}
.reader-map-chapter > summary {
  padding: 0.4rem 0.9rem 0.4rem 1.95rem;
  font-size: var(--ui-text-sm);
  color: var(--ui-text-soft);
}
.reader-map-count {
  flex: none;
  font-family: var(--ui-font-mono);
  font-size: var(--ui-text-xs);
  color: var(--ui-text-disabled);
}
.reader-map-topics {
  list-style: none;
  margin: 0;
  padding: 0 0 0.3rem;
}
.reader-map-topic {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0.35rem 0.9rem 0.35rem 2.5rem;
  font-size: var(--ui-text-sm);
  color: var(--ui-text-faint);
  text-decoration: none;
}
a.reader-map-topic:hover {
  background: var(--ui-velo-2);
  color: var(--ui-text);
}
.reader-map-topic.is-current {
  color: var(--brand);
  font-weight: 600;
}
.reader-map-topic.is-locked {
  color: var(--ui-text-disabled);
  cursor: default;
}
.reader-map-topic .material-symbols-rounded {
  font-size: 14px;
}

/* ── Avisos de la clase sobre este tema ── */
.reader-avisos {
  border: 1px solid var(--ui-line-subtle);
  border-left: 3px solid var(--brand);
  border-radius: var(--ui-radius-control);
  background: var(--ui-surface-soft);
  padding: var(--ui-space-4);
}
.reader-avisos > h2 {
  display: flex;
  align-items: center;
  gap: var(--ui-space-2);
  margin: 0 0 var(--ui-space-3);
  font-size: var(--ui-text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ui-text-faint);
}
.reader-avisos > h2 .material-symbols-rounded { font-size: 18px; color: var(--brand); }
.reader-aviso + .reader-aviso {
  margin-top: var(--ui-space-3);
  padding-top: var(--ui-space-3);
  border-top: 1px solid var(--ui-line-subtle);
}
.reader-aviso > h3 {
  margin: 0 0 var(--ui-space-1);
  font-size: var(--ui-text-md);
  font-weight: 700;
  color: var(--ui-text);
}
.reader-aviso > p {
  margin: 0 0 var(--ui-space-1);
  font-size: var(--ui-text-sm);
  color: var(--ui-text-soft);
  white-space: pre-line;
}
.reader-aviso > a {
  display: inline-flex;
  align-items: center;
  gap: var(--ui-space-1);
  font-size: var(--ui-text-sm);
  color: var(--brand);
}
.reader-aviso > a .material-symbols-rounded { font-size: 15px; }
.reader-aviso-fecha {
  display: block;
  margin-top: var(--ui-space-1);
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
}

/* ── Escritorio: índice a la derecha ── */
@media (min-width: 992px) {
  .reader {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 280px;
    gap: var(--ui-space-6);
    align-items: start;
  }
  .reader-main {
    min-width: 0;
    max-width: 78ch;
  }
  .reader-aside {
    position: sticky;
    top: var(--ui-space-4);
    display: flex;
    flex-direction: column;
    gap: var(--ui-space-4);
    max-height: calc(100vh - 2 * var(--ui-space-4));
    overflow-y: auto;
  }
  /* Sin esto, el mapa del curso NO se recorta: se **encoge**. Es un hijo de un
     flex en columna con altura tope, así que el navegador le quita alto hasta
     que todo cabe, y como la tarjeta lleva `overflow: hidden` para redondear
     las esquinas, los temas que sobran desaparecen sin dejar barra que mover.
     En un curso real eso enseñaba tres temas de diecinueve y escondía justo el
     que se estaba leyendo. */
  .reader-aside > * {
    flex: 0 0 auto;
  }
  /* El mapa scrollea por su cuenta para que «En este tutorial» siga a un
     golpe de vista y no al final de noventa temas. */
  .reader-course-map-scroll {
    max-height: min(52vh, 520px);
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  .reader-index {
    margin-bottom: 0;
  }
  .reader-prevnext {
    grid-template-columns: 1fr 1fr;
  }
}

/* En escritorio el índice está siempre a la vista; en móvil se pliega. */
@media (min-width: 992px) {
  .reader-index > summary {
    cursor: default;
  }
  .reader-index > summary::after {
    display: none;
  }
}

/* ═══════════════════════════════════════════════
   ENTREGA DE UNA PRÁCTICA EVALUABLE
   Vive junto al enunciado, no en otra pantalla. El plazo no oculta nada:
   se puede entregar tarde y queda marcado.
═══════════════════════════════════════════════ */
.entrega-panel {
  max-width: 70ch;
  margin: 2.5rem auto 3rem;
  padding: 1.25rem 1.4rem;
  border: 1px solid color-mix(in srgb, var(--brand) 28%, transparent);
  border-radius: var(--ui-radius-control);
  background: color-mix(in srgb, var(--brand) 3%, transparent);
}
.entrega-cabecera {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}
.entrega-cabecera h2 {
  margin: 0;
  font-size: var(--ui-text-base);
  font-weight: 700;
  color: var(--ui-text);
}
.entrega-cabecera .material-symbols-rounded { color: var(--brand); }
.entrega-plazo {
  margin-left: auto;
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
  white-space: nowrap;
}
.entrega-plazo.is-vencido { color: var(--ui-warning); }
.entrega-estado {
  margin-bottom: 1rem;
  padding: .75rem .9rem;
  border-radius: var(--ui-radius-control);
  background: var(--ui-velo-2);
  font-size: var(--ui-text-md);
}
.entrega-comentario {
  margin-top: .5rem;
  padding-left: .75rem;
  border-left: 2px solid var(--brand);
  white-space: pre-wrap;
}

/* ── Cierre del tema ──
   Marcar el tema y preguntar: las dos cosas que antes solo existían dentro de
   un paso, así que en un tema escrito en Markdown no existían en absoluto.
   Van al final del documento, separadas del cuerpo por una línea, para que se
   lean como el final de la lectura y no como un bloque más. */
.tema-cierre {
  margin-top: var(--ui-space-5);
  padding-top: var(--ui-space-4);
  border-top: 1px solid var(--ui-line);
}

.tema-cierre-marca {
  display: flex;
  align-items: center;
  gap: var(--ui-space-3);
  flex-wrap: wrap;
  margin-bottom: var(--ui-space-3);
}

/* El botón es el destino de una acción deliberada: se le da tamaño de dedo,
   no de icono de barra de herramientas. */
.tema-cierre-marca .reader-done-btn {
  font-size: var(--ui-text-base);
  padding: 0.6rem 1.1rem;
  min-height: 44px;
}

.tema-cierre-nota {
  font-size: var(--ui-text-sm);
  color: var(--ui-text-faint);
  line-height: 1.5;
  flex: 1 1 16rem;
}



/* ── progress-matrix.css ── */

/* ═══════════════════════════════════════════════
   MATRIZ DE PROGRESO — alumnos × pasos
   Responde «¿quién ha hecho el ejercicio 3?», que hasta ahora no tenía
   respuesta en ninguna pantalla.
═══════════════════════════════════════════════ */

.pm-wrap {
  overflow-x: auto;
  border-radius: var(--ui-radius-control);
  border: 1px solid var(--ui-line-subtle);
}

.pm-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--ui-text-sm);
  min-width: 420px;
}

.pm-table th,
.pm-table td {
  padding: 0.5rem 0.6rem;
  text-align: left;
  border-bottom: 1px solid var(--ui-line-subtle);
  white-space: nowrap;
}
.pm-table tbody tr:last-child td {
  border-bottom: none;
}
.pm-table tbody tr:hover {
  background: var(--ui-velo-1);
}

.pm-table thead th {
  position: sticky;
  top: 0;
  background: var(--ui-surface-alt);
  font-size: var(--ui-text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ui-text-faint);
  z-index: 1;
}

/* La columna del alumno se queda fija al desplazar en horizontal. */
.pm-name {
  position: sticky;
  left: 0;
  background: var(--ui-surface-soft);
  color: var(--ui-text);
  font-weight: 600;
  min-width: 11rem;
  max-width: 14rem;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pm-table thead .pm-name {
  z-index: 2;
}

.pm-step-col {
  text-align: center;
  width: 2.6rem;
  font-family: var(--ui-font-mono);
}

.pm-cell {
  text-align: center;
}
.pm-cell .material-symbols-rounded {
  font-size: 18px;
}
.pm-done {
  color: var(--brand);
}
.pm-pending {
  color: var(--ui-text-disabled);
}

/* ── Avance por tramos ──────────────────────────────────────────────
   Antes todas las barras se pintaban del mismo lima al 55 % de opacidad: un
   8 % y un 92 % se leían igual salvo por la longitud, y para comparar una
   clase de catorce había que medir barras con la vista.

   Ahora el color va por tramos. Dos reglas que la escala tiene que cumplir:

   1. Es monótona. Una sola familia —el teal de acento— subiendo de
      luminosidad. Si la escala cambia de color a mitad de recorrido deja de
      ordenarse sola: el ojo no sabe si el nuevo tono es «más» o es «otro».
   2. El 100 % tiene color propio. Terminar no es «mucho avance», es otro
      estado, y merece el lima de marca, que aquí no aparece en ningún otro
      tramo.

   El número va dentro de la barra, así que un objeto da los dos datos. */
.pm-score {
  min-width: 8rem;
}
.pm-bar {
  position: relative;
  height: 18px;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-velo-3);
  overflow: hidden;
}
.pm-bar-fill {
  height: 100%;
  background: var(--accent);
  transition: width var(--ui-duration) var(--ui-ease-out);
}

.pm-bar-cero  .pm-bar-fill { background: transparent; }
.pm-bar-bajo  .pm-bar-fill { background: color-mix(in srgb, var(--accent) 30%, transparent); }
.pm-bar-medio .pm-bar-fill { background: color-mix(in srgb, var(--accent) 50%, transparent); }
.pm-bar-alto  .pm-bar-fill { background: color-mix(in srgb, var(--accent) 75%, transparent); }

/* Terminado: color reservado, y el texto se oscurece porque sobre el lima a
   plena saturación el blanco no llega ni a 2:1. */
.pm-bar-lleno .pm-bar-fill { background: var(--brand); }
.pm-bar-lleno .pm-bar-label { color: var(--brand-contrast); }
.pm-bar-label {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--ui-text-xs);
  font-weight: 700;
  color: var(--ui-text);
  font-variant-numeric: tabular-nums;
}

/* ── Quien no ha empezado ────────────────────────────────────────────
   Antes se marcaba con un `●` delante del nombre. Para encontrar a los cinco
   que no han empezado en una clase de catorce había que recorrer la columna
   punto por punto: el marcador está en el sitio correcto pero es demasiado
   pequeño para leerse de un barrido.

   Se atenúa la fila entera, que es lo que hace que salte a la vista sin
   leerla. Dos cuidados:

   · el nombre no se atenúa. Es lo único que hay que poder leer de esa fila,
     y bajarlo de contraste sería castigar precisamente a quien hay que mirar;
   · queda el marcador en texto para quien navega con lector de pantalla,
     donde una opacidad no significa nada.

   0,55 sobre las celdas deja los iconos en ~4,8:1, por encima del mínimo. */
.pm-row-stalled td {
  opacity: 0.55;
}
.pm-row-stalled .pm-name {
  color: var(--ui-warning);
  font-weight: 700;
}
.pm-row-stalled .pm-name::after {
  content: ' · sin empezar';
  font-weight: 400;
  font-size: var(--ui-text-xs);
  color: var(--ui-warning);
}

/* ── Rejilla por temas ──
   Un tema no cabe en 2,6 rem como un número de paso: la columna se ensancha y
   el título se escribe en vertical, que es lo que permite ver diez temas sin
   que la tabla se salga de la pantalla. */
.pm-tema-col {
  width: 2.9rem;
  vertical-align: bottom;
  padding-bottom: 0.5rem;
}
.pm-tema-titulo {
  display: block;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  max-height: 11rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
  font-size: var(--ui-text-sm);
  color: var(--ui-text-soft);
  margin: 0 auto;
}

/* Tema empezado pero sin terminar: se dice cuánto lleva, que es más útil que
   un icono a medias. */
.pm-parcial {
  font-family: var(--ui-font-mono);
  font-size: var(--ui-text-xs);
  color: var(--ui-warning);
  font-variant-numeric: tabular-nums;
}

/* El detalle por pasos, plegado bajo la rejilla de temas. */
.pm-detalle > summary {
  cursor: pointer;
  font-size: var(--ui-text-md);
  color: var(--ui-text-faint);
  padding: 0.35rem 0;
}
.pm-detalle > summary:hover {
  color: var(--ui-text);
}



/* ── reorder.css ── */

/* ═══════════════════════════════════════════════
   REORDENAR — asas de arrastre del editor
   El arrastre es un extra: los botones subir/bajar siguen siendo la vía
   accesible con teclado y la que funciona sin JavaScript.
═══════════════════════════════════════════════ */

.drag-handle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 22px;
  align-self: stretch;
  color: var(--ui-text-disabled);
  cursor: grab;
  touch-action: none; /* el navegador no debe robar el gesto para hacer scroll */
  border-radius: var(--ui-radius-control);
  transition: color var(--ui-duration-fast), background var(--ui-duration-fast);
}
.drag-handle:hover {
  color: var(--ui-text-faint);
  background: var(--ui-velo-2);
}
.drag-handle:active {
  cursor: grabbing;
}
.drag-handle .material-symbols-rounded {
  font-size: 18px;
}
.drag-handle-sm {
  width: 16px;
}
.drag-handle-sm .material-symbols-rounded {
  font-size: 14px;
}

/* Elemento en movimiento */
.is-dragging {
  opacity: 0.65;
  outline: 2px dashed var(--brand);
  outline-offset: 2px;
}

/* El servidor rechazó el nuevo orden */
.reorder-error {
  outline: 2px solid var(--ui-danger);
  outline-offset: 4px;
  border-radius: var(--ui-radius-control);
}

/* Sin puntero fino (táctil puro) el arrastre es incómodo: se deja el asa
   visible pero los botones son la vía principal. */
@media (hover: none) {
  .drag-handle {
    opacity: 0.5;
  }
}



/* ── editor-inline.css ── */

/* ═══════════════════════════════════════════════
   EDICIÓN EN LÍNEA DE BLOQUES
   El formulario se despliega bajo la fila del bloque. Sin JavaScript nada de
   esto se ve: el lápiz sigue llevando a la página de edición completa.
═══════════════════════════════════════════════ */

.block-item {
  margin-bottom: 0.5rem;
}
.block-item > .block-row {
  margin-bottom: 0;
}

.block-item.is-editing > .block-row {
  border-color: color-mix(in srgb, var(--brand) 35%, transparent);
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}

.block-inline-slot[hidden] {
  display: none;
}

.block-inline-form {
  padding: 1rem;
  border: 1px solid color-mix(in srgb, var(--brand) 35%, transparent);
  border-top: 0;
  border-radius: 0 0 var(--ui-radius-control) var(--ui-radius-control);
  background: var(--ui-velo-1);
}

.block-inline-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1rem;
  flex-wrap: wrap;
}

.block-inline-errors {
  margin-bottom: 0.75rem;
  padding: 0.6rem 0.8rem;
  border-radius: var(--ui-radius-control);
  border: 1px solid var(--ui-danger);
  background: rgba(239, 68, 68, 0.08);
  font-size: var(--ui-text-sm);
}
.block-inline-errors ul {
  padding-left: 1.1rem;
}

/* El guardado no llegó al servidor: se avisa sin cerrar el formulario, para
   que el trabajo escrito no se pierda. */
.inline-edit-error {
  outline: 2px solid var(--ui-danger);
  outline-offset: 4px;
  border-radius: var(--ui-radius-control);
}



/* ── editor-draft.css ── */

/* ═══════════════════════════════════════════════
   BORRADOR DE SEGURIDAD — aviso de recuperación
   Aparece solo cuando quedó trabajo sin guardar en este navegador.
═══════════════════════════════════════════════ */

.draft-recovery {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-bottom: 1.25rem;
  padding: 0.8rem 1rem;
  border: 1px solid var(--ui-warning);
  border-radius: var(--ui-radius-control);
  background: rgba(251, 191, 36, 0.1);
}

.draft-recovery-text {
  flex: 1;
  min-width: 15rem;
  font-size: var(--ui-text-md);
  line-height: 1.4;
}



/* ── tables.css ── */

/* ═══════════════════════════════════════════════
   TABLAS
   Bootstrap las pinta claras por defecto: dentro de un panel de Codelab eso
   salía como un bloque blanco con enlaces azules, sin relación con el resto.
   Solo se tocan las que viven dentro de un panel, que son las de
   administración y la vista previa del esquema de curso.
═══════════════════════════════════════════════ */

.panel-shell .table {
  --bs-table-bg: transparent;
  --bs-table-color: var(--ui-text, #e2e8f0);
  --bs-table-border-color: var(--ui-velo-3);
  --bs-table-striped-bg: var(--ui-velo-1);
  --bs-table-striped-color: var(--ui-text, #e2e8f0);
  --bs-table-hover-bg: var(--ui-velo-2);
  --bs-table-hover-color: #fff;
  color: var(--ui-text);
  margin-bottom: 0;
}

.panel-shell .table > thead th {
  font-size: var(--ui-text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ui-text-faint);
  background: var(--ui-velo-1);
  border-bottom: 1px solid var(--ui-velo-3);
  padding: 0.7rem 0.9rem;
  white-space: nowrap;
}

.panel-shell .table > tbody td {
  padding: 0.65rem 0.9rem;
  vertical-align: middle;
  border-color: var(--ui-velo-2);
}

.panel-shell .table a {
  color: var(--ui-text);
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--brand) 30%, transparent);
}
.panel-shell .table a:hover {
  color: var(--brand);
  border-bottom-color: var(--brand);
}

/* Los controles embebidos en una celda no deben romper la altura de la fila */
.panel-shell .table .form-control,
.panel-shell .table .form-select {
  min-width: 0;
}

/* Una tabla ancha se desplaza dentro de su panel, no arrastra la página */
.panel-shell .table-wrap {
  overflow-x: auto;
}

/* Distintivos de estado (origen, activo/inactivo…) */
.tag-chip {
  display: inline-block;
  font-size: var(--ui-text-xs);
  font-weight: 700;
  letter-spacing: 0.03em;
  padding: 0.1rem 0.5rem;
  border-radius: var(--ui-radius-surface);
  border: 1px solid var(--ui-velo-4);
  color: var(--ui-text-faint);
  background: var(--ui-velo-2);
  white-space: nowrap;
}
/* Los cuatro estados salen de los tokens semánticos y no de un hex propio: así
   cambian con el tema —en claro son las versiones oscuras, porque los pasteles
   del tema oscuro no llegan a 4,5:1 sobre blanco— y no hay que acordarse de
   tocarlos en dos sitios.

   `color-mix` sobre el propio color en vez de un rgba fijo, por lo mismo: un
   rgba lleva el tono escrito dentro y se queda anclado al tema oscuro. */
.tag-chip-ok {
  color: var(--ui-success);
  border-color: color-mix(in srgb, var(--ui-success) 32%, transparent);
  background: color-mix(in srgb, var(--ui-success) 12%, transparent);
}
.tag-chip-info {
  color: var(--ui-info);
  border-color: color-mix(in srgb, var(--ui-info) 32%, transparent);
  background: color-mix(in srgb, var(--ui-info) 12%, transparent);
}
.tag-chip-warn {
  color: var(--ui-warning);
  border-color: color-mix(in srgb, var(--ui-warning) 32%, transparent);
  background: color-mix(in srgb, var(--ui-warning) 12%, transparent);
}
.tag-chip-bad {
  color: var(--ui-danger);
  border-color: color-mix(in srgb, var(--ui-danger) 32%, transparent);
  background: color-mix(in srgb, var(--ui-danger) 12%, transparent);
}

/* ── Rejilla de calificaciones ──────────────────────────────────────
   Alumnado en filas, prácticas evaluables en columnas. Con 20 evaluables la
   tabla se va a lo ancho, así que la columna del nombre queda fija: si al
   desplazarte pierdes de vista de quién es la fila, la rejilla no sirve. */
.rejilla-notas {
  --rejilla-alumno-ancho: 190px;
}
.rejilla-notas .rejilla-alumno {
  position: sticky;
  left: 0;
  z-index: 2;
  min-width: var(--rejilla-alumno-ancho);
  text-align: left;
  /* Opaco a propósito: es lo que pasa por debajo al desplazar. `--ui-surface`
     no se definía en ninguna hoja, así que lo que se pintaba era el respaldo
     #0f172a —un azul pizarra de otra paleta—, y la columna del nombre salía de
     un color distinto al del resto de la rejilla. */
  background: var(--ui-surface-solid);
}
.rejilla-notas thead .rejilla-alumno {
  z-index: 3;
}
/* Los encabezados de práctica llevan títulos largos de verdad —«EVALUACIÓN
   DEL TEMA 1: INTRODUCCIÓN AL ORDENADOR…»—, así que hay dos cosas que domar.

   1. `.panel-shell .table > thead th` pone `white-space: nowrap` y gana por
      especificidad (0,2,1 contra 0,2,0): los títulos iban en una sola línea y
      se montaban unos sobre otros. Por eso este selector nombra la tabla.
   2. En una tabla de ancho automático, `max-width` sobre la celda **no** lo
      respeta el navegador. El recorte tiene que ir en un elemento de dentro,
      que es lo que hace `.rejilla-practica-titulo`. */
.rejilla-notas thead th.rejilla-practica {
  min-width: 128px;
  white-space: normal;
  vertical-align: bottom;
  font-size: var(--ui-text-xs);
  line-height: 1.25;
  /* En mayúsculas un título largo se lee peor y ocupa más. */
  text-transform: none;
  letter-spacing: 0;
}
/* Dos líneas y puntos suspensivos. El título entero sigue estando en el
   atributo `title` y a un clic, en la ficha de la práctica: recortar no puede
   ser perderlo. */
.rejilla-practica-titulo {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  max-width: 170px;
  font-weight: 700;
}
.rejilla-notas .rejilla-plazo {
  display: block;
  margin-top: 0.15rem;
  font-weight: 500;
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
}
.rejilla-notas .rejilla-celda,
.rejilla-notas td.rejilla-media {
  text-align: center;
  white-space: nowrap;
}
.rejilla-notas .rejilla-nota {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: var(--ui-text-base);
}
.rejilla-notas .rejilla-media {
  border-left: 1px solid var(--ui-velo-4);
}
.rejilla-nota-pie {
  margin: 0.85rem 0 0;
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
}

/* ── Prueba tipo test ───────────────────────────────────────────────
   Se pinta desde la base de datos, no del Markdown: el documento lleva su
   solucionario dentro y al alumnado se le sirve recortado. */
.prueba-test {
  margin: 1.5rem 0;
  padding: 1.25rem;
  border: 1px solid var(--ui-velo-3);
  border-radius: var(--ui-radius-surface);
  background: var(--ui-velo-1);
}
.prueba-test-cabecera {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  flex-wrap: wrap;
  margin-bottom: 0.75rem;
}
.prueba-test-cabecera h2 {
  margin: 0;
  font-size: var(--ui-text-base);
}
.prueba-test-meta,
.prueba-test-intentos {
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
}
.prueba-test-intentos {
  margin: 0.35rem 0 0;
}
.prueba-test-aviso {
  display: flex;
  align-items: flex-start;
  gap: 0.4rem;
  margin-bottom: 1rem;
  font-size: var(--ui-text-md);
  color: var(--ui-text-faint);
}
.prueba-test-lista {
  margin: 0;
  padding-left: 1.4rem;
}
.prueba-test-pregunta {
  margin-bottom: 1.35rem;
}
.prueba-test-pregunta fieldset {
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}
.prueba-test-enunciado {
  margin: 0 0 0.5rem;
  font-weight: 600;
  line-height: 1.4;
}
.prueba-test-opciones {
  margin: 0;
  padding-left: 1.1rem;
  list-style: none;
}
.prueba-test-opciones li {
  padding: 0.2rem 0;
  line-height: 1.45;
}
/* Verde el acierto, rojo lo que se marcó mal. El color no va solo: cada caso
   lleva además su etiqueta en texto, para quien no distingue los tonos. */
.prueba-test-opciones .es-correcta {
  color: var(--ui-success);
}
.prueba-test-opciones .es-marcada-mal {
  color: var(--ui-danger);
}
.prueba-test-opcion-radio {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  padding: 0.35rem 0.5rem;
  border-radius: var(--ui-radius-control);
  cursor: pointer;
  line-height: 1.45;
}
.prueba-test-opcion-radio:hover {
  background: var(--ui-velo-2);
}
.prueba-test-opcion-radio input {
  margin-top: 0.28rem;
  flex-shrink: 0;
}
.prueba-test-explicacion {
  margin: 0.45rem 0 0;
  padding-left: 0.7rem;
  border-left: 2px solid rgba(125, 211, 252, 0.35);
  font-size: var(--ui-text-md);
  color: var(--ui-text-faint);
}
.prueba-test-resultado {
  margin-bottom: 1.1rem;
  padding: 0.85rem 1rem;
  border-radius: var(--ui-radius-control);
  background: var(--ui-velo-2);
}
.prueba-test-marcador {
  margin: 0;
  font-size: var(--ui-text-base);
}
.prueba-test-repetir {
  margin-top: 1.25rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--ui-velo-3);
}
.prueba-test-repetir summary {
  cursor: pointer;
  font-weight: 600;
  font-size: var(--ui-text-md);
}
.prueba-test-pregunta.es-acertada .prueba-test-enunciado::before {
  content: "✓ ";
  color: var(--ui-success);
}
.prueba-test-pregunta.es-fallada .prueba-test-enunciado::before {
  content: "✗ ";
  color: var(--ui-danger);
}

/* ── Guía del formato del test ──────────────────────────────────── */
.guia-reglas > li {
  margin-bottom: 0.85rem;
  line-height: 1.55;
}
.guia-reglas code,
.guia-ejemplo {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.guia-reglas code {
  padding: 0.1rem 0.35rem;
  border-radius: var(--ui-radius-control);
  font-size: 0.85em;
  background: var(--ui-velo-3);
}
.guia-ejemplo {
  margin: 0;
  padding: 1rem;
  border: 1px solid var(--ui-velo-3);
  border-radius: var(--ui-radius-control);
  background: var(--ui-sombra-1);
  font-size: var(--ui-text-sm);
  line-height: 1.5;
  /* El ejemplo se lee tal cual: sin cortar líneas, con barra si hace falta. */
  overflow-x: auto;
  white-space: pre;
}

/* ── Evaluación de UF / MF completa ───────────────────────────────── */
.eval-ambito {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  padding: .7rem .9rem;
  margin-bottom: .5rem;
  border: 1px solid var(--ui-velo-3);
  border-radius: var(--ui-radius-control);
  background: var(--ui-velo-1);
}
.eval-ambito-unidad {
  margin-left: 1.4rem;
  border-left: 2px solid rgba(125, 211, 252, .25);
}
.eval-ambito-info { display: flex; flex-direction: column; gap: .15rem; flex: 1 1 14rem; }
.eval-ambito-info strong { color: var(--ui-text); font-size: var(--ui-text-md); }
.eval-ambito-info .text-secondary { font-size: var(--ui-text-xs); }
.eval-ambito-acciones { display: flex; gap: .4rem; flex: 0 0 auto; }

.lista-temas-eval { list-style: none; padding: 0; margin: 0; }
.lista-temas-eval li {
  display: flex;
  align-items: center;
  gap: .4rem;
  padding: .35rem 0;
  border-bottom: 1px solid var(--ui-velo-2);
  font-size: var(--ui-text-md);
  color: var(--ui-text-soft);
}
.lista-temas-eval li:last-child { border-bottom: 0; }
.lista-temas-eval .material-symbols-rounded { font-size: 16px; color: var(--ui-success); }

.lista-avisos-prueba { list-style: none; padding: 0; margin: 0 0 1rem; }
.lista-avisos-prueba li { padding: .3rem 0; font-size: var(--ui-text-md); color: var(--ui-text-soft); }

.prueba-test-resumen { padding-left: 1.4rem; margin: 0; }
.prueba-test-resumen > li { margin-bottom: 1rem; }
.prueba-test-enunciado { font-weight: 600; color: var(--ui-text); margin-bottom: .3rem; }
.prueba-test-resumen ul { list-style: none; padding: 0; margin: 0; }
.prueba-test-resumen ul li {
  padding: .2rem .5rem;
  border-radius: var(--ui-radius-control);
  font-size: var(--ui-text-md);
  color: var(--ui-text-faint);
}
.prueba-test-resumen ul li.es-correcta {
  background: rgba(74, 222, 128, .08);
  color: var(--ui-text-soft);
}

.documento-generado {
  max-height: 26rem;
  overflow: auto;
  padding: 1rem 1.1rem;
  border-radius: var(--ui-radius-control);
  background: #090f1a;
  border: 1px solid var(--ui-velo-3);
  color: var(--ui-text-soft);
  font-family: 'Fira Code', 'Consolas', monospace;
  font-size: var(--ui-text-sm);
  line-height: 1.6;
  white-space: pre-wrap;
  word-break: break-word;
}

/* El botón de evaluar, dentro de las cabeceras del mapa del curso */
.map-eval-btn { margin-left: auto; flex: 0 0 auto; }

/* ── Retirar un contenido de la clase: la confirmación ────────────── */
.retirar-lista { list-style: none; padding: 0; margin: .6rem 0 0; }
.retirar-lista li {
  display: flex;
  align-items: flex-start;
  gap: .6rem;
  padding: .6rem 0;
  border-bottom: 1px solid var(--ui-velo-2);
  font-size: var(--ui-text-md);
  color: var(--ui-text-soft);
}
.retirar-lista li:last-child { border-bottom: 0; }
.retirar-lista .material-symbols-rounded { font-size: 18px; color: var(--ui-success); flex: 0 0 auto; }
.retirar-lista li.es-grave .material-symbols-rounded { color: var(--ui-danger); }
.retirar-lista li.es-grave strong { color: var(--ui-danger); }
.retirar-nota {
  display: block;
  margin-top: .15rem;
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
}
.retirar-aviso {
  padding: .85rem 1.1rem;
  border: 1px solid rgba(248, 113, 113, .4);
  border-left: 3px solid var(--ui-danger);
  border-radius: 0 var(--ui-radius-control) var(--ui-radius-control) 0;
  background: rgba(248, 113, 113, .08);
  font-size: var(--ui-text-md);
  color: var(--ui-text);
}
.retirar-aviso label { display: flex; align-items: flex-start; gap: .55rem; cursor: pointer; margin: 0; }
.retirar-aviso input[type="checkbox"] { margin-top: .2rem; accent-color: var(--ui-danger); flex: 0 0 auto; }

/* ── Acciones por impartición en la ficha del tema ────────────────── */
.imp-acciones {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem;
  margin-top: .5rem;
  padding-top: .5rem;
  border-top: 1px solid var(--ui-velo-2);
}
.imp-acciones form { margin: 0; }
.btn-mini {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  padding: .2rem .5rem;
  border-radius: var(--ui-radius-control);
  border: 1px solid var(--ui-velo-4);
  background: var(--ui-velo-2);
  color: var(--ui-text-faint);
  font: inherit;
  font-size: var(--ui-text-xs);
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: color .15s, border-color .15s, background .15s;
}
.btn-mini:hover {
  color: var(--ui-text);
  border-color: var(--ui-velo-5);
  background: var(--ui-velo-3);
}
.btn-mini .material-symbols-rounded { font-size: 14px; }
.btn-mini.es-peligro { color: var(--ui-danger); border-color: rgba(248, 113, 113, .3); }
.btn-mini.es-peligro:hover {
  color: var(--ui-danger);
  border-color: rgba(248, 113, 113, .6);
  background: rgba(248, 113, 113, .1);
}

/* ── Mensaje que se está contestando ──
   Sin verlo, responder desde una bandeja larga obliga a volver atrás para
   recordar de qué iba. */
.mensaje-citado {
  margin: 0 0 1.25rem;
  padding: 0.75rem 1rem;
  border-left: 3px solid var(--ui-line-strong);
  background: var(--ui-velo-1);
  border-radius: 0 var(--ui-radius-control) var(--ui-radius-control) 0;
}
.mensaje-citado-quien {
  display: block;
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
  margin-bottom: 0.25rem;
}
.mensaje-citado p {
  margin: 0.35rem 0 0;
  font-size: var(--ui-text-md);
  color: var(--ui-text-soft);
  white-space: pre-line;
}

/* ── Avance de un tema en el aula (13/08/2026) ──────────────────────────
   Se usa en las dos vistas: para el alumnado es lo que lleva hecho, y para
   quien da la clase, cuántos la han terminado. La barra acompaña al texto,
   no lo sustituye: en los temas sin pasos solo hay dos estados y el número
   es lo que de verdad informa. */
.aula-avance { display: flex; align-items: center; gap: .5rem; margin-top: .35rem; }
.aula-avance-barra {
  flex: 0 0 84px;
  height: 5px;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-velo-3);
  overflow: hidden;
}
.aula-avance-barra span {
  display: block;
  height: 100%;
  border-radius: var(--ui-radius-pill);
  background: var(--brand, var(--brand));
  transition: width .2s ease;
}
.aula-avance-texto { font-size: var(--ui-text-xs); color: var(--ui-text-faint); }

/* El título del tema, en la fila del aula del docente: es un enlace, pero no
   debe parecer un enlace suelto dentro de la fila. */
.aula-tema-enlace { text-decoration: none; display: inline-block; }
.aula-tema-enlace:hover { text-decoration: underline; }

/* Camino de vuelta al aula desde un tema o desde la ficha de clase. */
.reader-volver { margin: 0 0 .75rem; font-size: var(--ui-text-md); }
.reader-volver a { display: inline-flex; align-items: center; gap: .3rem; color: var(--ui-text-faint); text-decoration: none; }
.reader-volver a:hover { color: var(--brand, var(--brand)); }
.reader-volver .material-symbols-rounded { font-size: 16px; }
.volver-al-aula { color: inherit; text-decoration: none; }
.volver-al-aula:hover { text-decoration: underline; }



/* ── dudas.css ── */

/* ═══════════════════════════════════════════════
   DUDAS DEL ALUMNADO
   Panel del docente en la ficha de impartición.
═══════════════════════════════════════════════ */

.duda-item {
  border-left: 2px solid var(--ui-block-hint);
  padding: 0.6rem 0 0.6rem 0.9rem;
  margin-bottom: 1rem;
}
.duda-item.is-answered {
  border-left-color: var(--ui-success);
  opacity: 0.85;
}
.duda-item:last-child {
  margin-bottom: 0;
}

.duda-cabecera {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
  margin-bottom: 0.3rem;
  font-size: var(--ui-text-sm);
}
.duda-cabecera strong {
  color: var(--ui-text);
}
.duda-paso {
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
  border: 1px solid var(--ui-line);
  border-radius: var(--ui-radius-pill);
  padding: 1px 8px;
}
.duda-fecha {
  margin-left: auto;
  font-size: var(--ui-text-xs);
  color: var(--ui-text-faint);
  font-variant-numeric: tabular-nums;
}

.duda-texto {
  margin: 0 0 0.5rem;
  font-size: var(--ui-text-md);
  color: var(--ui-text-soft);
  white-space: pre-line;
}

.duda-respuesta {
  display: flex;
  gap: 0.4rem;
  margin: 0;
  font-size: var(--ui-text-md);
  color: var(--ui-text);
}
.duda-respuesta .material-symbols-rounded {
  font-size: 15px;
  color: var(--ui-success);
  flex-shrink: 0;
  margin-top: 2px;
}

.duda-responder textarea {
  max-width: 46rem;
}

@media (max-width: 575.98px) {
  .duda-fecha {
    margin-left: 0;
    flex-basis: 100%;
  }
}

/* ═══════════════════════════════════════════════
   PESTAÑAS DE LA CLASE
═══════════════════════════════════════════════ */

.clase-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  margin-top: 1.25rem;
  border-bottom: 1px solid var(--ui-line);
}

.clase-tab {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.55rem 1rem;
  border-radius: var(--ui-radius-control) var(--ui-radius-control) 0 0;
  font-size: var(--ui-text-sm);
  font-weight: 600;
  color: var(--ui-text-faint);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color var(--ui-duration-fast), background var(--ui-duration-fast);
}
.clase-tab:hover {
  color: var(--ui-text);
  background: var(--ui-velo-1);
}
.clase-tab.is-active {
  color: var(--brand);
  border-bottom-color: var(--brand);
}
.clase-tab .material-symbols-rounded {
  font-size: 17px;
}

@media (max-width: 575.98px) {
  .clase-tab {
    flex: 1 1 auto;
    justify-content: center;
    padding: 0.55rem 0.6rem;
  }
}

