/* ============================================================
   SCHOOLARYX — Pages CSS
   Estilos específicos por página
   ============================================================ */

.lms-task-item { background-color: #ffffff !important; }

/* ======================================================
   DASHBOARD
   ====================================================== */
.sx-mini-calendar {
  font-size: 0.8rem;
}
.sx-mini-calendar table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 2px;
}
.sx-mini-calendar th {
  text-align: center;
  font-weight: 800;
  font-size: 0.68rem;
  color: var(--sx-text-muted);
  text-transform: uppercase;
  padding: 0.25rem;
}
.sx-mini-calendar td {
  text-align: center;
  padding: 0.3rem 0.2rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--sx-text-body);
  font-weight: 600;
  transition: var(--transition-fast);
  border: none !important;
}
.sx-mini-calendar td:hover { background: var(--sx-primary-light); color: var(--sx-primary-text); }
.sx-mini-calendar td.today { background: var(--sx-primary-solid); color: #fff; border-radius: var(--radius-sm); }
.sx-mini-calendar td.other-month { color: var(--sx-text-muted); opacity: 0.4; }
.sx-cal-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.75rem;
}
.sx-cal-nav button {
  background: none;
  border: none;
  color: var(--sx-text-muted);
  cursor: pointer;
  padding: 0.25rem;
  border-radius: var(--radius-sm);
  transition: var(--transition-fast);
}
.sx-cal-nav button:hover { background: var(--sx-primary-light); color: var(--sx-primary-text); }
.sx-cal-nav-title { font-weight: 800; font-size: 0.875rem; color: var(--sx-text-heading); }

/* Semester progress */
.sx-semester-progress { }
.sx-semester-item { margin-bottom: 1rem; }
.sx-semester-item:last-child { margin-bottom: 0; }
.sx-semester-label {
  display: flex;
  justify-content: space-between;
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--sx-text-body);
  margin-bottom: 0.35rem;
}
.sx-semester-label span:last-child { color: var(--sx-text-muted); }

/* ======================================================
   FORMS — WIZARD
   ====================================================== */
.sx-wizard-steps {
  display: flex;
  align-items: center;
  margin-bottom: 2rem;
  position: relative;
}
.sx-wizard-steps::before {
  content: '';
  position: absolute;
  top: 18px;
  left: 10%;
  right: 10%;
  height: 2px;
  background: var(--sx-border-color);
  z-index: 0;
}
.sx-wizard-step {
  flex: 1;
  text-align: center;
  position: relative;
  z-index: 1;
}
.sx-wizard-step-dot {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--sx-border-color);
  color: var(--sx-text-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 0.875rem;
  margin: 0 auto 0.5rem;
  transition: var(--transition);
  border: 2px solid var(--sx-border-color);
}
.sx-wizard-step.active .sx-wizard-step-dot {
  background: var(--sx-primary-solid);
  color: #fff;
  border-color: var(--sx-primary-solid);
  box-shadow: 0 0 0 4px var(--sx-primary-light);
}
.sx-wizard-step.done .sx-wizard-step-dot {
  background: var(--sx-success);
  color: #fff;
  border-color: var(--sx-success);
}
.sx-wizard-step-label {
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--sx-text-muted);
}
.sx-wizard-step.active .sx-wizard-step-label { color: var(--sx-primary-text); }
.sx-wizard-step.done .sx-wizard-step-label  { color: var(--sx-success-dark); }

.sx-wizard-panel { display: none; }
.sx-wizard-panel.active { display: block; }

/* ======================================================
   FORMS — FILE UPLOAD
   ====================================================== */
.sx-file-preview-list { list-style: none; padding: 0; margin-top: 1rem; }
.sx-file-preview-item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 0.875rem;
  background: var(--sx-body-bg);
  border: 1px solid var(--sx-border-color);
  border-radius: var(--radius);
  margin-bottom: 0.5rem;
}
.sx-file-preview-icon { font-size: 1.25rem; color: var(--sx-primary-text); flex-shrink: 0; }
.sx-file-preview-name { font-size: 0.8rem; font-weight: 700; color: var(--sx-text-body); flex: 1; }
.sx-file-preview-size { font-size: 0.72rem; color: var(--sx-text-muted); }
.sx-file-preview-remove {
  background: none;
  border: none;
  color: var(--sx-danger);
  cursor: pointer;
  padding: 0.2rem;
  border-radius: var(--radius-sm);
  opacity: 0.7;
  transition: var(--transition-fast);
}
.sx-file-preview-remove:hover { opacity: 1; background: var(--sx-danger-light); }

/* ======================================================
   FORMS — INPUT MASKS
   ====================================================== */
.sx-mask-group { margin-bottom: 1.25rem; }
.sx-mask-complete { border-color: var(--sx-success) !important; }
.sx-mask-complete:focus { box-shadow: 0 0 0 3px rgba(var(--sx-success-rgb), 0.15) !important; }

/* Card detector de tarjeta */
.sx-card-type-icon {
  font-size: 1.25rem;
  color: var(--sx-text-muted);
  transition: var(--transition-fast);
}
.sx-card-type-visa    { color: #1434cb; }
.sx-card-type-mc      { color: #eb001b; }
.sx-card-type-amex    { color: #007bc1; }

/* ======================================================
   FORMS — SELECT2 CUSTOM THEME
   ====================================================== */
.select2-container--default .select2-selection--single,
.select2-container--default .select2-selection--multiple {
  border: 1.5px solid var(--sx-border-color) !important;
  border-radius: var(--radius) !important;
  min-height: 40px !important;
  background: var(--sx-card-bg) !important;
  font-family: var(--font-body) !important;
  font-size: 0.875rem !important;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
  color: var(--sx-text-body) !important;
  line-height: 38px !important;
  padding-left: 0.875rem !important;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
  height: 38px !important;
}
/* En Select2 4.1.0 el <ul> de chips y el campo de búsqueda son hermanos
   APILADOS dentro de un contenedor block → el cuadro vacío queda ~58px de alto.
   Lo convertimos en una fila flex y disolvemos el <ul> (display:contents) para
   que chips + buscador fluyan en la MISMA línea, igual que un select2 single. */
.select2-container--default .select2-selection--multiple {
  display: flex !important;
  flex-wrap: wrap !important;
  align-items: center !important;
  padding: 0.15rem 0.5rem !important;
  gap: 0.25rem !important;
}
.select2-container--default .select2-selection--multiple .select2-selection__rendered {
  display: contents !important;
  padding: 0 !important;
  margin: 0 !important;
}
/* Campo de búsqueda interno: ya es un item flex del contenedor; lo alineamos
   a la altura del single (40px de caja). */
.select2-container--default .select2-selection--multiple .select2-search--inline {
  display: flex !important;
  align-items: center !important;
  margin: 0 !important;
}
.select2-container--default .select2-selection--multiple .select2-search--inline .select2-search__field {
  margin: 0 !important;
  padding-left: 0.3rem !important;
  height: 28px !important;
  line-height: 28px !important;
  /* El texto que se escribe debe usar la MISMA fuente/color que el resto del
     select2 (Nunito), no el sans-serif negro por defecto del navegador. */
  font-family: var(--font-body) !important;
  font-size: 0.875rem !important;
  font-weight: 400 !important;
  color: var(--sx-text-body) !important;
}
.select2-container--default .select2-selection--multiple .select2-search--inline .select2-search__field::placeholder {
  color: var(--sx-text-muted) !important;
  font-family: var(--font-body) !important;
}
.select2-container--default .select2-selection--multiple .select2-selection__choice {
  background: var(--sx-primary-light) !important;
  border: 1px solid var(--sx-primary) !important;
  border-radius: var(--radius-pill) !important;
  color: var(--sx-primary-text) !important;
  font-size: 0.78rem !important;
  font-weight: 700 !important;
  /* inline-flex + gap: la "x" (botón) y el nombre se alinean sin encimarse.
     En Select2 4.1.0 el chip es <button.remove> + <span.display>; al pasar
     ambos a flex con position:static, el layout absoluto por defecto se anula. */
  display: inline-flex !important;
  align-items: center !important;
  gap: 0.4rem !important;
  padding: 0.1rem 0.65rem 0.1rem 0.35rem !important;
  margin: 0.1rem !important;
  line-height: 1.4 !important;
  position: relative !important;
}
/* El texto del chip: anula el padding-left por defecto (28px) que dejaba
   hueco para la "x" absoluta — ahora la "x" es un item flex normal. */
.select2-container--default .select2-selection--multiple .select2-selection__choice__display {
  padding: 0 !important;
  line-height: 1.4 !important;
}
/* "x" como botón circular claro y clickeable (más legible para marcar) */
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
  color: var(--sx-primary-text) !important;
  /* Quita el posicionamiento absoluto y el separador por defecto de Select2 */
  position: static !important;
  border: 0 !important;
  border-right: 0 !important;
  background: transparent !important;
  padding: 0 !important;
  margin: 0 !important;
  top: auto !important;
  left: auto !important;
  font-weight: 700 !important;
  font-size: 0.85rem !important;
  line-height: 1 !important;
  order: -1 !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  width: 1.1rem !important;
  height: 1.1rem !important;
  border-radius: 50% !important;
  cursor: pointer !important;
  flex-shrink: 0 !important;
  transition: background-color .15s ease, color .15s ease !important;
}
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
  color: #fff !important;
  background: var(--sx-danger) !important;
}
.select2-container--default.select2-container--focus .select2-selection--single,
.select2-container--default.select2-container--focus .select2-selection--multiple,
.select2-container--default.select2-container--open .select2-selection--single {
  border-color: #bdbdbd !important;
  box-shadow: none !important;
}
.select2-dropdown {
  border: 1px solid var(--sx-border-color) !important;
  border-radius: var(--radius-lg) !important;
  box-shadow: var(--shadow-lg) !important;
  background: var(--sx-card-bg) !important;
  font-family: var(--font-body) !important;
  font-size: 0.875rem !important;
  overflow: hidden;
}
.select2-search--dropdown .select2-search__field {
  border: 1.5px solid var(--sx-border-color) !important;
  border-radius: var(--radius-sm) !important;
  padding: 0.4rem 0.75rem !important;
  font-family: var(--font-body) !important;
  font-size: 0.875rem !important;
  color: var(--sx-text-body) !important;
  background: var(--sx-body-bg) !important;
  box-shadow: none !important;
  outline: none !important;
}
.select2-search--dropdown .select2-search__field:focus {
  box-shadow: none !important;
  outline: none !important;
  border-color: #bdbdbd !important;
}
.select2-results__option {
  padding: 0.5rem 0.875rem !important;
  border-radius: var(--radius-sm) !important;
  font-family: var(--font-body) !important;
  font-size: 0.875rem !important;
  color: var(--sx-text-body) !important;
  transition: var(--transition-fast) !important;
}
.select2-results__option--highlighted {
  background: var(--sx-primary-light) !important;
  color: var(--sx-primary-text) !important;
}
/* -solid, no el base: es un relleno macizo con texto blanco encima, y el naranja
   de marca no llega al contraste AA ahí. */
.select2-results__option--selected {
  background: var(--sx-primary-solid) !important;
  color: #fff !important;
}

/* "Mostrar N" de las tablas: la lista son cifras (25/50/100/∞), no etiquetas, y
   alineadas a la izquierda se leen desiguales por el ancho distinto de cada una.
   La clase la pone sx-datatables.js vía dropdownCssClass — el dropdown de
   Select2 cuelga de <body>, así que no hay forma de alcanzarlo por herencia. */
.sx-dt-length-dropdown .select2-results__option { text-align: center !important; }

/* Y el valor cerrado, a juego con la lista. El arrow se saca del flujo (absoluto,
   pegado al borde derecho) para que la cifra se centre respecto a TODA la caja:
   mientras ocupaba ancho propio, el texto se centraba solo en el hueco sobrante
   y quedaba descuadrado. */
.dataTables_length .select2-container--default .select2-selection--single {
  position: relative;
}
/* La caja se ajusta al contenido (con suelo para que quepan "100" y el arrow):
   con el ancho del <select> nativo y el padding del tema, la cifra no cabía en
   su caja de contenido y salía recortada en vez de centrada. */
.dataTables_length .select2-container {
  width: auto !important;
  min-width: 5rem !important;
}
.dataTables_length .select2-container--default .select2-selection--single .select2-selection__rendered {
  flex: 1 1 auto !important;
  text-align: center !important;
  padding-left: 0.75rem !important;
  padding-right: 0.75rem !important;
  overflow: visible !important;
}
.dataTables_length .select2-container--default .select2-selection--single .select2-selection__arrow {
  position: absolute !important;
  top: 0 !important;
  bottom: 0 !important;
  right: 0.35rem !important;
  height: auto !important;
  width: 1rem !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
}
.select2-results__group {
  font-size: 0.7rem !important;
  font-weight: 800 !important;
  text-transform: uppercase !important;
  letter-spacing: 0.06em !important;
  color: var(--sx-text-muted) !important;
  padding: 0.6rem 0.875rem 0.25rem !important;
}

/* Select2: alinear altura/padding con .form-control y dar más aire interno */
.select2-container--default .select2-selection--single {
  height: calc(1.5em + 1rem + 3px) !important;
  padding: 0 0.25rem !important;
  display: flex !important;
  align-items: center !important;
  position: relative !important;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
  line-height: 1.5 !important;
  padding-left: 0.6rem !important;
  padding-right: 3.6rem !important;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
  height: 100% !important;
  width: 2.2rem !important;
  right: 2px !important;
}
.select2-container--default .select2-selection__placeholder {
  color: var(--sx-text-muted) !important;
}
/* allowClear: mover la "x" a la derecha, justo al lado del arrow (no a la izquierda). */
.select2-container--default .select2-selection--single .select2-selection__clear {
  position: absolute !important;
  right: 2.5rem !important;
  top: 50% !important;
  transform: translateY(-50%) !important;
  margin: 0 !important;
  padding: 0 !important;
  line-height: 1 !important;
  z-index: 2 !important;
  color: var(--sx-text-muted) !important;
}
.select2-container--default .select2-selection--single .select2-selection__clear:hover {
  color: var(--sx-danger) !important;
}
.select2-results__options { padding: 0.3rem !important; }
.select2-results__option { margin-bottom: 0.1rem !important; }
.select2-dropdown { padding: 0 !important; }

/* Select2 SOBRE UN .form-select-sm (celdas de tabla, topbar, barras de filtro).
   El alto normal de Select2 está calcado de .form-control; en una rejilla de
   estudiantes × criterios, o en un tri-estado por permiso, eso suma un tercio
   más de alto por fila y descuadra la barra donde vive. Aquí se iguala al alto
   de .form-select-sm, que es lo que llevaba el <select> nativo, y se estrechan
   flecha y "x" para que quepan en una celda angosta.

   Se engancha al hermano: Select2 oculta el <select> original (que conserva sus
   clases) y pinta su contenedor justo después, así que .form-select-sm elige
   exactamente los que antes eran pequeños — sin ir listando ids uno por uno
   (#rgGrid, #sxTopbar, .po-state, .sx-enradmin-docstate, .sx-pg-len…). */
.form-select-sm + .select2-container--default .select2-selection--single {
  height: calc(1.5em + 0.5rem + 2px) !important;
}
.form-select-sm + .select2-container--default .select2-selection--single .select2-selection__rendered {
  font-size: 0.8125rem !important;
  padding-left: 0.4rem !important;
  padding-right: 2.9rem !important;
}
.form-select-sm + .select2-container--default .select2-selection--single .select2-selection__arrow {
  width: 1.5rem !important;
}
.form-select-sm + .select2-container--default .select2-selection--single .select2-selection__clear {
  right: 1.7rem !important;
}

/* ======================================================
   COLUMNA ESTATUS EDITABLE (catálogo de estudiantes)
   El badge sigue siendo lo que se lee de un vistazo; el Select2 vive en la
   misma celda con .d-none y solo sale al pulsarlo. El botón que envuelve al
   badge es un botón de verdad (foco y teclado), pero no debe parecerlo: sin
   fondo, sin borde y sin padding, para que la celda se vea igual que antes.
   ====================================================== */
.sx-status-cell { display: inline-flex; align-items: center; }
.sx-status-badge {
  background: none;
  border: 0;
  padding: 0;
  line-height: 1;
  cursor: pointer;
}
.sx-status-badge:focus-visible {
  outline: 2px solid var(--sx-primary);
  outline-offset: 2px;
  border-radius: var(--radius-pill);
}

/* ======================================================
   MODAL FORMS — FIELDSET + INPUT CON ÍCONO (patrón super-admin)
   Convención de markup:
     <fieldset class="app-form-fieldset">
       <legend class="app-form-legend">Grupo</legend>
       <div class="form-icon">
         <input class="form-control form-control-icon"> <i class="bi bi-..."></i>
       </div>
     </fieldset>
   Textarea: usar .form-icon.form-icon-textarea (ícono arriba).
   ====================================================== */
.app-form-fieldset {
  border: 1.5px solid var(--sx-border-color);
  border-radius: var(--radius);
  padding: 1rem 1rem 0.85rem;
  margin: 0 0 1rem;
  background: var(--sx-card-bg);
}
.app-form-fieldset:last-child { margin-bottom: 0; }
.app-form-legend {
  float: none;
  width: auto;
  margin: 0 0 0.25rem;
  padding: 0 0.5rem;
  font-size: 0.72rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--sx-primary-text);
}
/* Fieldset de traducción (es/en) con leve tinte para distinguir idioma */
.app-form-fieldset-lang { background: var(--sx-body-bg); }
.app-form-label-flag {
  margin-left: 0.35rem;
  vertical-align: baseline;
  line-height: 1;
  font-size: 0.95rem;
}

/* Input con ícono interno (izquierda) */
.form-icon { position: relative; }
.form-icon > i {
  position: absolute;
  top: 50%;
  left: 0.9rem;
  transform: translateY(-50%);
  color: var(--sx-text-muted);
  font-size: 1rem;
  line-height: 1;
  z-index: 5;
  pointer-events: none;
}
.form-control-icon { padding-left: 2.5rem !important; }
.form-icon .form-control:focus ~ i,
.form-icon:focus-within > i { color: var(--sx-primary-text); }
/* Ícono de YouTube (enlaces de video): siempre en color de marca de error/rojo,
   incluso con foco (no cambia a primary). */
.form-icon > i.bi-youtube,
.form-icon:focus-within > i.bi-youtube { color: var(--sx-danger); }

/* Select2 dentro de .form-icon: empujar el texto para el ícono */
.form-icon .select2-container--default .select2-selection--single .select2-selection__rendered {
  padding-left: 1.9rem !important;
}
/* Select2 MÚLTIPLE dentro de .form-icon: empujar los tags/placeholder para el ícono */
.form-icon .select2-container--default .select2-selection--multiple {
  padding-left: 1.9rem !important;
}
.form-icon .select2-container { z-index: 1; }

/* Filtros de estudiantes: el mensaje de validacion aumenta la altura del
   wrapper y con top:50% el icono se desplaza. Aqui lo fijamos al alto del
   control para que Select2 conserve la alineacion. */
/* Textarea con ícono: ícono anclado arriba, no centrado */
.form-icon-textarea > i { top: 0.85rem; transform: none; }
textarea.form-control-icon { padding-left: 2.5rem !important; }

[data-theme="dark"] .app-form-fieldset { background: var(--sx-dark-2); }
[data-theme="dark"] .app-form-fieldset-lang { background: var(--sx-dark-3); }

/* DataTables: ver components.css (sección "DATATABLES — toolbar, tabla y paginación") */

/* ======================================================
   CHARTS PAGES
   ====================================================== */
.sx-chart-card .card-body { padding: 1.25rem; }
.sx-chart-title {
  font-family: var(--font-display);
  font-size: 1rem;
  color: var(--sx-text-heading);
  margin-bottom: 0.25rem;
}
.sx-chart-subtitle { font-size: 0.78rem; color: var(--sx-text-muted); margin-bottom: 1rem; }

/* ======================================================
   WIDGETS PAGE
   ====================================================== */
/* Leaderboard */
.sx-leaderboard { list-style: none; padding: 0; }
.sx-leaderboard-item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--sx-border-color);
}
.sx-leaderboard-item:last-child { border-bottom: none; }
.sx-leaderboard-rank {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--sx-body-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.72rem;
  font-weight: 800;
  color: var(--sx-text-muted);
  flex-shrink: 0;
}
.sx-leaderboard-item:nth-child(1) .sx-leaderboard-rank { background: var(--sx-yellow-light); color: var(--sx-yellow-dark); }
.sx-leaderboard-item:nth-child(2) .sx-leaderboard-rank { background: var(--sx-sky-light); color: var(--sx-sky-dark); }
.sx-leaderboard-item:nth-child(3) .sx-leaderboard-rank { background: var(--sx-primary-light); color: var(--sx-primary-text); }

/* Timeline horario */
.sx-schedule-timeline { position: relative; padding-left: 1.5rem; }
.sx-schedule-timeline::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--sx-border-color);
}
.sx-schedule-item {
  position: relative;
  padding-bottom: 1.25rem;
}
.sx-schedule-item::before {
  content: '';
  position: absolute;
  left: -1.5rem;
  top: 0.25rem;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--sx-primary);
  border: 2px solid var(--sx-card-bg);
  box-shadow: 0 0 0 2px var(--sx-primary);
  transform: translateX(-4px);
}
.sx-schedule-time { font-size: 0.72rem; font-weight: 700; color: var(--sx-text-muted); margin-bottom: 0.2rem; }
.sx-schedule-class { font-size: 0.875rem; font-weight: 700; color: var(--sx-text-heading); }
.sx-schedule-room { font-size: 0.78rem; color: var(--sx-text-muted); }

/* Achievements grid */
.sx-achievements-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.75rem;
}
.sx-achievement-item {
  text-align: center;
  padding: 0.75rem 0.5rem;
  border-radius: var(--radius);
  background: var(--sx-body-bg);
}
.sx-achievement-icon {
  font-size: 1.75rem;
  margin-bottom: 0.35rem;
  display: block;
}
.sx-achievement-label { font-size: 0.68rem; font-weight: 700; color: var(--sx-text-muted); }
.sx-achievement-item.earned { background: var(--sx-primary-light); }
.sx-achievement-item.earned .sx-achievement-icon { color: var(--sx-primary-text); }
.sx-achievement-item.earned .sx-achievement-label { color: var(--sx-primary-text); }
.sx-achievement-item.locked { opacity: 0.4; filter: grayscale(1); }

/* ======================================================
   APPS - CALENDAR
   ====================================================== */
#fcWrap {
  background: var(--sx-card-bg);
  border: 1px solid var(--sx-border-color);
  border-radius: var(--radius-lg);
  overflow: visible;
}

/* Aquí vivía un `.fc .fc-scrollgrid { border: none !important }` que le quitaba
   el marco exterior a TODO calendario de la app. Tenía sentido cuando el
   calendario iba dentro de #fcWrap (arriba), que pone su propio borde y así se
   evitaba el doble marco — pero #fcWrap ya no existe en ningún markup (ver el
   comentario de courses.css:376, que documenta lo mismo). O sea que solo dejaba
   la rejilla abierta por fuera. Se quita para que cada calendario dibuje su
   marco completo; el de "Mis Cursos" mantiene el suyo sin borde con su propia
   regla (#crsCalMount, courses.css:389), que no depende de esta. */

.fc .fc-scrollgrid td,
.fc .fc-scrollgrid th {
  border-color: var(--sx-border-color) !important;
}

.fc .fc-scrollgrid td {
  height: 140px;
}

.fc .fc-scroller {
  overflow: visible !important;
}

#modalEvent .modal-dialog,
#modalEventDetail .modal-dialog {
  max-width: 560px;
}

#modalEventHeader,
#detailModalHeader {
  border-bottom: 0;
}

#modalEventHeader .modal-title,
#detailModalHeader .modal-title,
#detailModalHeader #detailEvTime {
  color: inherit;
}

/* ===========================================================================
   APARIENCIA (super-admin) — color pickers, file input y preview de logos.
   =========================================================================== */

/* Barra superior con el boton Guardar (sticky para que siempre se vea). */
.appearance-toolbar {
  position: sticky;
  top: 0;
  z-index: 5;
  padding: 0.5rem 0;
  background: var(--sx-body-bg, transparent);
}

/* Regla global de inputs de color (misma que Apariencia): swatch compacto
   dentro del input-group y SIN box-shadow. Aplica a TODOS los selectores de
   color del sistema, no solo a los de Apariencia (.js-color-picker). */
.input-group .form-control-color {
  width: 2.4rem;
  flex: 0 0 2.4rem;
  padding: 0.2rem;
  border-radius: 0; /* swatch en medio del grupo (icono · swatch · hex) */
}
.form-control-color,
.form-control-color:focus,
.form-control-color:focus-visible {
  box-shadow: none !important;
  outline: none !important;
}
/* Al hacer clic se veía un salto: .form-control anima `all 0.15s`, y en un
   input de color eso también anima el propio swatch (fondo y caja) mientras el
   navegador abre su selector. Aquí solo debe animar el borde. */
.form-control-color { transition: border-color 0.15s ease; }
.form-control-color::-webkit-color-swatch-wrapper,
.form-control-color::-webkit-color-swatch { transition: none; }

/* En focus se resalta TODO el grupo (icono + swatch + texto) con UN solo color,
   SIN glow/box-shadow. El addon ya usa --sx-primary-text con !important
   (components.css), así que el swatch y el texto siguen el mismo borde: con el
   gris de antes el swatch quedaba con un tramo distinto al del resto. */
.input-group:focus-within {
  border-radius: var(--radius-sm);
}
.input-group:focus-within .form-control,
.input-group:focus-within .form-control-color,
.input-group:focus-within .input-group-text {
  border-color: var(--sx-primary-text);
}
.input-group .form-control:focus,
.input-group .form-control-color:focus,
.input-group .js-color-hex:focus,
.input-group .input-group-text:focus {
  box-shadow: none; /* el resaltado lo da el borde del grupo completo */
}

/* Input de archivo (choose file) redondeado, incluido su boton interno.
   Clase reutilizable .sx-file-input (la antigua .appearance-file se mantiene
   por compatibilidad y comparte el mismo estilo). */
.appearance-file.form-control,
.sx-file-input.form-control {
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.appearance-file.form-control::file-selector-button,
.sx-file-input.form-control::file-selector-button {
  border-radius: var(--radius-xs);
  border: 0;
  margin-inline-end: 0.65rem;
  background: var(--sx-primary-light);
  color: var(--sx-primary-text);
  font-weight: 600;
  cursor: pointer;
}

/* Caja de preview de logos. */
.appearance-logo-box {
  min-height: 96px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.75rem;
  border: 1px solid var(--sx-border-color);
  border-radius: var(--radius-sm);
}
.appearance-logo-box img {
  max-height: 64px;
  max-width: 100%;
}
/* Logo blanco -> fondo oscuro para contraste. */
.appearance-logo-box--dark {
  background: var(--sx-dark, #302f3b);
  border-color: transparent;
}
/* Logo "a color" que en realidad es blanco -> fondo tipo damero para que se vea. */
.appearance-logo-box--check {
  background-color: #e9ecf2;
  background-image:
    linear-gradient(45deg, #c9cedb 25%, transparent 25%),
    linear-gradient(-45deg, #c9cedb 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, #c9cedb 75%),
    linear-gradient(-45deg, transparent 75%, #c9cedb 75%);
  background-size: 16px 16px;
  background-position: 0 0, 0 8px, 8px -8px, -8px 0;
}
[data-theme="dark"] .appearance-logo-box--check {
  background-color: #3a3947;
  background-image:
    linear-gradient(45deg, #2d2c38 25%, transparent 25%),
    linear-gradient(-45deg, #2d2c38 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, #2d2c38 75%),
    linear-gradient(-45deg, transparent 75%, #2d2c38 75%);
}

/* ============================================================
   Detalle de log (admin/log-details.php) — patrón "ticket details"
   ============================================================ */
.ld-info-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; padding: .55rem 0; border-bottom: 1px solid var(--sx-border-color); font-size: .83rem; }
.ld-info-row:last-child { border-bottom: 0; }
.ld-info-label { color: var(--sx-text-muted); white-space: nowrap; }
.ld-info-value { font-weight: 600; color: var(--sx-text-heading); text-align: right; word-break: break-word; }
.ld-json { background: var(--sx-body-bg); border: 1px solid var(--sx-border-color); border-radius: var(--radius-sm, .5rem); padding: .75rem 1rem; font-size: .8rem; white-space: pre-wrap; word-break: break-word; margin: 0; }
.ld-diff td, .ld-diff th { vertical-align: top; }
.ld-diff .ld-old { color: var(--sx-danger, #c0392b); }
.ld-diff .ld-new { color: var(--sx-success, #1e7e34); }

/* ===========================================================================
   Wizard de creación de escuela (admin/school-wizard.php)
   Stepper horizontal: badge numerado + etiqueta. Estados: activo / completado.
   =========================================================================== */
.sx-wizard-steps { margin: 0; padding: 0; }
.sx-wizard-step {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.85rem;
  border: 1px solid var(--sx-border-color);
  border-radius: var(--radius-pill, 999px);
  background: var(--sx-body-bg);
  color: var(--sx-text-muted);
  font-size: 0.85rem;
  cursor: default;
  transition: var(--transition-fast, all .15s ease);
}
.sx-wizard-step__badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.6em;
  height: 1.6em;
  border-radius: 50%;
  background: var(--sx-text-muted);
  color: #fff;
  font-size: 0.8rem;
  flex: 0 0 auto;
}
/* Texto opcional: etiqueta + pequeña descripción apiladas. */
.sx-wizard-step__text { display: inline-flex; flex-direction: column; align-items: flex-start; text-align: left; line-height: 1.15; }
.sx-wizard-step__desc { font-size: 0.7rem; font-weight: 400; opacity: 0.72; }
.sx-wizard-step.is-active {
  border-color: var(--sx-primary-text);
  background: var(--sx-primary-light);
  color: var(--sx-primary-text);
  font-weight: 600;
}
/* Relleno macizo con el icono blanco encima: va en -solid, no en el tono base. */
.sx-wizard-step.is-active .sx-wizard-step__badge { background: var(--sx-primary-solid); }
.sx-wizard-step.is-done {
  border-color: var(--sx-success);
  color: var(--sx-success-dark);
  cursor: pointer;
}
.sx-wizard-step.is-done .sx-wizard-step__badge { background: var(--sx-success-solid); }

/* ===========================================================================
   Selector de iconos: grilla dentro del modal compartido.

   OJO: estas reglas las usaba sx-icon-picker.js, que ya no existe (lo sustituyó
   sx-icon-autocomplete.js y ninguna página lo cargaba). Hoy ningún HTML ni JS pone
   .sx-icon-grid / .sx-icon-grid-cell, así que el bloque está sin usar. No se borra
   con el JS porque .sx-icon-grid está declarada TAMBIÉN en components.css con otros
   valores, y desenredar cuál gana en qué pantalla es una limpieza de CSS aparte.
   =========================================================================== */
.sx-icon-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(3rem, 1fr));
  gap: 0.4rem;
}
.sx-icon-grid-cell {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1 / 1;
  border: 1px solid var(--sx-border-color);
  border-radius: var(--radius-sm, 8px);
  background: var(--sx-card-bg);
  color: var(--sx-text-body);
  font-size: 1.15rem;
  cursor: pointer;
  transition: var(--transition-fast, all .12s ease);
}
.sx-icon-grid-cell:hover {
  border-color: var(--sx-primary-text);
  background: var(--sx-primary-light);
  color: var(--sx-primary-text);
}
.sx-icon-grid-cell.is-selected {
  border-color: var(--sx-primary-solid);
  background: var(--sx-primary-solid);
  color: #fff;
}
/* Botón "examinar" del campo de icono. */
.sx-icon-pick-btn { display: inline-flex; align-items: center; }

/* ===========================================================================
   Autocompletado de iconos (sx-icon-autocomplete.js): desplegable typeahead.
   =========================================================================== */
.sx-icon-field { position: relative; }
.sx-icon-ac-menu {
  position: fixed;       /* montado en <body>; coordenadas vía JS */
  z-index: 1085;         /* sobre el modal (1055) y su backdrop */
  max-height: 16rem;
  overflow-y: auto;
  padding: 0.25rem;
  background: var(--sx-card-bg);
  border: 1px solid var(--sx-border-color);
  border-radius: var(--radius-sm, 8px);
  box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.12);
}
.sx-icon-ac-item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  padding: 0.4rem 0.6rem;
  border: 0;
  border-radius: var(--radius-sm, 8px);
  background: transparent;
  color: var(--sx-text-body);
  font-size: 0.9rem;
  text-align: left;
  cursor: pointer;
}
.sx-icon-ac-item > i { font-size: 1.15rem; line-height: 1; width: 1.4rem; text-align: center; }
.sx-icon-ac-item:hover,
.sx-icon-ac-item.is-active {
  background: var(--sx-primary-light);
  color: var(--sx-primary-text);
}
.sx-icon-ac-empty {
  padding: 0.5rem 0.6rem;
  color: var(--sx-text-muted);
  font-size: 0.85rem;
}
/* Botón "x" para limpiar el campo de icono (lo crea sx-icon-autocomplete.js). */
.sx-icon-ac-has-clear { padding-right: 2.2rem !important; }
.sx-icon-ac-clear {
  position: absolute;
  top: 50%;
  right: 0.55rem;
  transform: translateY(-50%);
  display: none; /* el JS lo pone en 'flex' cuando hay valor */
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--sx-text-muted);
  font-size: 0.75rem;
  line-height: 1;
  cursor: pointer;
  z-index: 6;
  transition: var(--transition-fast, all .12s ease);
}
.sx-icon-ac-clear:hover {
  background: var(--sx-primary-light);
  color: var(--sx-primary-text);
}

/* ===========================================================================
   Estilos movidos desde public/app/students-create.php (regla: nada de <style> inline)
   =========================================================================== */
/* El stepper horizontal es el componente OFICIAL del sistema (.sx-wizard-step
   en pages.css, igual que admin/school-wizard). Aquí solo van estilos propios. */
.sx-guardian-card { border:1px solid var(--sx-border-color); border-radius:var(--radius, .6rem); padding:1rem; margin-bottom:1rem; }
.sx-guardian-card .sx-guardian-head { display:flex; align-items:center; justify-content:space-between; margin-bottom:.75rem; }
.sx-review-grid dt { font-weight:600; color:var(--sx-text-heading, #302f3b); }
.sx-review-grid dd { margin-bottom:.4rem; }
/* Radios sin marcar: círculo gris neutro (claro que no hay selección). */
#wBapYes:not(:checked), #wBapNo:not(:checked) { background-color:#fff; border-color:var(--sx-text-muted); }

/* ===========================================================================
   Estilos movidos desde public/app/chat.php (regla: nada de <style> inline)
   =========================================================================== */
.sx-chat { overflow: hidden; }
.sx-chat__row { min-height: 70vh; }
.sx-chat__aside { display: flex; flex-direction: column; }
.sx-chat__conv-list { overflow-y: auto; flex: 1 1 auto; }
.sx-chat__conv-item { display: flex; align-items: center; width: 100%; border-bottom: 1px solid var(--sx-border-color); }
.sx-chat__conv-item:hover { background: var(--sx-row-hover); }
.sx-chat__conv-item.active { background: rgba(var(--sx-primary-rgb), .12); }
.sx-chat__conv-open { display: flex; gap: .65rem; align-items: center; flex: 1 1 auto; min-width: 0; padding: .65rem .85rem; border: 0; background: transparent; text-align: start; cursor: pointer; }
.sx-chat__conv-del { flex: 0 0 auto; border: 0; background: transparent; color: var(--sx-text-muted); padding: .35rem .55rem; margin-right: .25rem; border-radius: var(--radius-sm, .4rem); opacity: 0; cursor: pointer; transition: var(--transition); }
.sx-chat__conv-item:hover .sx-chat__conv-del { opacity: 1; }
.sx-chat__conv-del:hover { color: var(--sx-danger); background: rgba(var(--sx-danger-rgb), .12); }
.sx-chat__peer-avatar { width: 40px; height: 40px; border-radius: 50%; flex: 0 0 40px; display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: .85rem; color: #fff; background: var(--sx-primary-solid); text-transform: uppercase; }
.sx-chat__conv-body { min-width: 0; flex: 1 1 auto; }
.sx-chat__conv-name { font-weight: 600; }
.sx-chat__conv-last { font-size: .8rem; }
.sx-chat__unread-badge { min-width: 20px; height: 20px; padding: 0 6px; border-radius: 10px; background: var(--sx-primary, #4361ee); color: #fff; font-size: .72rem; font-weight: 600; display: inline-flex; align-items: center; justify-content: center; }
.sx-chat__main { min-height: 70vh; }
.sx-chat__messages { overflow-y: auto; padding: 1rem; display: flex; flex-direction: column; gap: .4rem; background: var(--sx-card-bg); }
.sx-chat__bubble-row { display: flex; flex-direction: column; align-items: flex-start; }
.sx-chat__bubble-row.mine { align-items: flex-end; }
.sx-chat__bubble { max-width: 75%; padding: .5rem .75rem; border-radius: 14px; background: var(--sx-body-bg); }
.sx-chat__bubble-row.mine .sx-chat__bubble { background: var(--sx-primary-light); color: var(--sx-text-heading); border-bottom-right-radius: 4px; }
.sx-chat__bubble-row:not(.mine) .sx-chat__bubble { border-bottom-left-radius: 4px; }
.sx-chat__bubble-sender { font-size: .72rem; font-weight: 600; opacity: .8; margin-bottom: 2px; }
.sx-chat__bubble-text { white-space: pre-wrap; word-wrap: break-word; overflow-wrap: anywhere; }
.sx-chat__bubble-meta { display: flex; align-items: center; gap: .35rem; margin: 2px 4px 0; }
.sx-chat__bubble-row.mine .sx-chat__bubble-meta { flex-direction: row-reverse; }
.sx-chat__bubble-time { font-size: .66rem; color: var(--sx-text-muted); }
.sx-chat__bubble-actions { display: flex; gap: .1rem; opacity: 0; transition: var(--transition); }
.sx-chat__bubble-row.mine:hover .sx-chat__bubble-actions { opacity: 1; }
.sx-chat__bubble-action { border: 0; background: transparent; color: var(--sx-text-muted); padding: .15rem .3rem; border-radius: var(--radius-sm, .4rem); cursor: pointer; font-size: .72rem; line-height: 1; }
.sx-chat__bubble-action:hover { background: var(--sx-row-hover); color: var(--sx-text-heading); }
.sx-chat__bubble-action--danger:hover { color: var(--sx-danger); background: rgba(var(--sx-danger-rgb), .12); }
.sx-chat__bubble-edit-form { display: flex; flex-direction: column; gap: .3rem; min-width: 180px; }
.sx-chat__bubble-edit-form textarea { resize: none; border: 1px solid var(--sx-border-color); border-radius: var(--radius-sm, .4rem); padding: .35rem .5rem; font: inherit; background: var(--sx-card-bg); color: var(--sx-text-body); }
.sx-chat__bubble-edit-actions { display: flex; gap: .25rem; justify-content: flex-end; }
.sx-chat__contact-item { display: flex; gap: .65rem; align-items: center; width: 100%; padding: .55rem .65rem; border: 0; background: transparent; text-align: start; border-radius: .5rem; cursor: pointer; }
.sx-chat__contact-item:hover { background: var(--sx-body-bg); }
.sx-chat__contact-list { max-height: 45vh; overflow-y: auto; }
#chatInput { resize: none; min-height: 0; max-height: 140px; overflow-y: hidden; }
/* Adjuntos del chat (imágenes inline + chip descargable). */
.sx-chat__att-img { display: block; margin-top: .35rem; max-width: 220px; }
.sx-chat__att-img img { max-width: 100%; border-radius: 10px; display: block; }
.sx-chat__att-file { display: flex; align-items: center; gap: .5rem; margin-top: .35rem; padding: .5rem .65rem; border-radius: 10px; background: var(--sx-card-bg); border: 1px solid var(--sx-border-color); color: var(--sx-text-body); text-decoration: none; max-width: 260px; }
.sx-chat__att-file:hover { background: var(--sx-row-hover); }
.sx-chat__att-file > i { font-size: 1.2rem; color: var(--sx-primary-text); }
.sx-chat__att-meta { display: flex; flex-direction: column; min-width: 0; }
.sx-chat__att-name { font-size: .8rem; font-weight: 600; }
.sx-chat__att-size { font-size: .7rem; color: var(--sx-text-muted); }
.sx-chat__typing { font-style: italic; }
/* Progreso de subida DENTRO de la burbuja que se envía (solo quien envía). */
.sx-chat__att-up { margin-top: .35rem; min-width: 160px; }
.sx-chat__att-up-name { font-size: .75rem; color: var(--sx-text-muted); margin-bottom: .3rem; }
.sx-chat__upload-bar { height: 6px; border-radius: 3px; background: var(--sx-border-color); overflow: hidden; }
.sx-chat__upload-fill { height: 100%; width: 0; background: var(--sx-primary); border-radius: 3px; transition: width .15s ease; }
/* Imagen adjunta clicable (abre modal). */
.sx-chat__att-img { cursor: zoom-in; }
.sx-chat__img-modal-img { max-width: 100%; max-height: 80vh; border-radius: var(--radius); display: block; margin: 0 auto; }
/* Panel de emojis. */
.sx-chat__emoji-panel { position: absolute; bottom: calc(100% + .4rem); left: 0; z-index: 20; width: 264px; max-height: 200px; overflow-y: auto; display: grid; grid-template-columns: repeat(8, 1fr); gap: 2px; padding: .5rem; background: var(--sx-card-bg); border: 1px solid var(--sx-border-color); border-radius: var(--radius); box-shadow: var(--shadow-lg); }
.sx-chat__emoji { border: 0; background: transparent; font-size: 1.25rem; line-height: 1; padding: .25rem; border-radius: var(--radius-sm, .4rem); cursor: pointer; }
.sx-chat__emoji:hover { background: var(--sx-row-hover); }
@media (max-width: 767.98px) {
  .sx-chat__aside.is-hidden { display: none; }
  .sx-chat__main.is-hidden { display: none !important; }
}

/* Transcripción: vista HTML — DISEÑO WEB EDUCATIVO (distinto al PDF). */
.sx-transcript-scroll { max-height: 78vh; overflow-y: auto; background: var(--sx-body-bg); border-radius: var(--radius); padding: 1.25rem; }
.sx-tr-doc { display: flex; flex-direction: column; gap: 1.5rem; }
.sx-tr {
  background: var(--sx-card-bg);
  border: 1px solid var(--sx-border-color);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  max-width: 1000px;
  margin: 0 auto;
  width: 100%;
  padding: 1.5rem 1.75rem;
  color: var(--sx-text-body);
}
/* Banda del estudiante (encabezado del preview) */
.sx-tr__student { display: flex; align-items: center; gap: 1rem; }
.sx-tr__avatar { width: 52px; height: 52px; font-size: 1.1rem; }
.sx-tr__name { font-size: 1.15rem; font-weight: 700; color: var(--sx-text-heading); }
.sx-tr__chips { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .35rem; }
.sx-tr__chip { background: var(--sx-body-bg); border: 1px solid var(--sx-border-color); color: var(--sx-text-body); font-size: .74rem; font-weight: 600; padding: .15rem .55rem; border-radius: var(--radius-pill); }
.sx-tr__pill { margin-left: auto; align-self: flex-start; background: var(--sx-primary-solid); color: #fff; font-size: .72rem; font-weight: 700; letter-spacing: .3px; padding: .35rem .75rem; border-radius: var(--radius-pill); white-space: nowrap; }
/* Stat tiles */
.sx-tr__stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: .75rem; margin: 1.2rem 0; }
.sx-tr__stat { background: var(--sx-body-bg); border: 1px solid var(--sx-border-color); border-radius: var(--radius); padding: .8rem 1rem; text-align: center;
  /* Las tres tarjetas miden lo mismo (grid), pero "Generado" lleva una línea más:
     centrar en vertical para que GPA y Años no queden pegados arriba. */
  display: flex; flex-direction: column; justify-content: center; }
.sx-tr__stat:first-child { background: rgba(var(--sx-primary-rgb), .10); border-color: rgba(var(--sx-primary-rgb), .35); }
.sx-tr__stat-val { font-family: var(--font-display); font-size: 1.5rem; font-weight: 700; color: var(--sx-text-heading); line-height: 1.15; }
.sx-tr__stat:first-child .sx-tr__stat-val { color: var(--sx-primary-text); }
/* Segunda línea del stat (la fecha bajo el nombre de quien generó). */
.sx-tr__stat-sub { font-size: .78rem; color: var(--sx-text-body); margin-top: .3rem; line-height: 1.3; }
.sx-tr__stat-label { font-size: .68rem; text-transform: uppercase; letter-spacing: .4px; color: var(--sx-text-muted); margin-top: .3rem; }
/* Año */
/* La tabla del año scrollea DENTRO de la tarjeta, no empuja la página.
   Un grado por semana imprime una columna por semana: con 40 semanas la tabla
   mide bastante más que la tarjeta, y sin esto el desbordamiento se lo comía el
   ancho del documento. La cabecera de la tarjeta y el pie se quedan quietos. */
/* Cabecera de DOCUMENTO en pantalla: nombre de la escuela, dirección, regla
   oscura y la banda con el título a la izquierda y el AÑO ACADÉMICO a la
   derecha. Es la misma que imprime TenantPdf (.head + table.title); vive aquí
   para que la vista previa y el papel se lean como el mismo documento y no como
   dos productos. Solo tokens: el naranja lo sobreescribe cada escuela. */
.sx-doc-head { text-align: center; border-bottom: 2px solid var(--sx-dark); padding-bottom: .6rem; margin-bottom: .9rem; }
.sx-doc-head__school { font-size: 1.35rem; font-weight: 800; color: var(--sx-text-heading); font-family: var(--font-display); }
.sx-doc-head__sub { font-size: .8rem; color: var(--sx-text-body); margin-top: .15rem; }
.sx-doc-title {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  border-bottom: 2px solid var(--sx-primary);
  padding-bottom: .25rem; margin: 0 0 1rem;
  font-size: .95rem; font-weight: 800; color: var(--sx-primary-text);
  text-transform: uppercase; letter-spacing: .5px;
}
/* En móvil el año se cae debajo en vez de comprimir el título. */
@media (max-width: 575.98px) { .sx-doc-title { flex-wrap: wrap; } }

.sx-tr__year { margin-top: 1.1rem; overflow-x: auto; }
/* Tarjeta de incidente del expediente de conducta. En el boletín, .sx-tr__year
   envuelve una TABLA, que ya se delimita sola con sus filas; aquí envuelve
   párrafos sueltos y sin borde los incidentes se leen como un solo texto
   corrido. Mismo trazo que la maqueta impresa (.inc en ConductRecordPdf): solo
   la caja fina, sin filo de color a la izquierda (pedido del dueño, 22 oct
   2026), para que la pantalla y el papel no parezcan dos documentos distintos. */
.sx-tr__year--card {
  border: 1px solid var(--sx-border-color);
  border-radius: var(--radius);
  padding: .75rem .9rem;
  background: var(--sx-card-bg);
}
.sx-tr__year--card + .sx-tr__year--card { margin-top: .75rem; }
/* Las celdas de periodo no se parten en dos líneas: "Semana 10" en dos
   renglones hace la cabecera el doble de alta por nada. */
.sx-tr__table thead th:nth-child(n+2) { white-space: nowrap; }
.sx-tr__year-head { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-bottom: .5rem; }
.sx-tr__year-title { font-size: .95rem; font-weight: 700; color: var(--sx-text-heading); }
.sx-tr__year-grade { font-size: .76rem; color: var(--sx-text-muted); }
.sx-tr__year-gpa { margin-left: auto; background: rgba(var(--sx-primary-rgb), .12); color: var(--sx-primary-text); font-size: .74rem; font-weight: 700; padding: .15rem .6rem; border-radius: var(--radius-pill); }
.sx-tr__table { width: 100%; border-collapse: collapse; }
.sx-tr__table thead th { text-align: left; font-size: .66rem; text-transform: uppercase; letter-spacing: .4px; color: var(--sx-text-muted); font-weight: 700; padding: .35rem .6rem; border-bottom: 2px solid var(--sx-border-color); }
.sx-tr__table thead th:nth-child(n+2), .sx-tr__table tbody td:nth-child(n+2) { text-align: center; }
.sx-tr__table tbody td { font-size: .84rem; color: var(--sx-text-body); padding: .4rem .6rem; border-bottom: 1px solid var(--sx-border-color); }
.sx-tr__table tbody tr:nth-child(even) td { background: rgba(var(--sx-dark-rgb), .02); }
.sx-tr__cls { font-weight: 600; color: var(--sx-text-heading); }
.sx-tr__flag { font-size: .68rem; font-weight: 600; font-style: italic; color: var(--sx-text-muted); }
.sx-tr__dash { color: var(--sx-text-muted); }
.sx-tr__year-foot { display: flex; flex-wrap: wrap; gap: .35rem 1.25rem; margin-top: .5rem; font-size: .78rem; color: var(--sx-text-body); }
.sx-tr__year-foot b { color: var(--sx-text-heading); }
.sx-tr__none { color: var(--sx-text-muted); font-style: italic; padding: 1rem 0; }

/* Rejilla del informe de progreso: una fila por materia y una casilla por
   trabajo, agrupadas por tipo — la misma forma del informe en papel que la
   escuela reparte. Hereda TODO de .sx-tr__table; aquí solo lo que la rejilla
   necesita y esa no puede darle:
   - la cabecera es de DOS filas (grupo + número), así que el centrado no puede
     depender de nth-child como en las tablas normales;
   - nada se parte en dos renglones: un "8 / 10" en dos líneas hace la fila el
     doble de alta y la rejilla deja de leerse de un vistazo. La tabla scrollea
     dentro de su .sx-tr__year, que ya es overflow-x:auto. */
/* Documento ancho: el boletín cabe en los 1000px de .sx-tr, la rejilla no —
   lleva una columna por trabajo. Se usa donde la página ya es col-12. */
.sx-tr--wide { max-width: none; padding: 1.5rem 1.25rem; }
.sx-transcript-scroll:has(.sx-tr--wide) { padding: .75rem; }

.sx-pp-grid thead th { text-align: center; white-space: nowrap; }
.sx-pp-grid thead tr:first-child th:first-child { text-align: left; }
.sx-pp-grid tbody td { text-align: center; white-space: nowrap; }
/* Materia y maestro son texto, no casillas: van a la izquierda. */
.sx-pp-grid tbody td:first-child { text-align: left; min-width: 9rem; }
.sx-pp-grid tbody td:last-child,
.sx-pp-grid thead tr:first-child th:last-child { text-align: left; }
/* El asterisco de "no cuenta para el promedio" acompaña al dato, no compite. */
.sx-pp-grid .sx-tr__flag { display: inline; margin-left: .15rem; }
/* Nombre del trabajo bajo la nota: en teléfono no hay hover, así que el título
   no puede vivir solo en el tooltip. Recortado en el JS y a media tinta, para
   que la nota siga siendo lo primero que se lee. */
.sx-pp-grid__name {
  display: block;
  font-size: .66rem;
  font-weight: 600;
  color: var(--sx-text-muted);
  margin-top: .15rem;
  max-width: 8rem;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Un informe por HOJA cuando se imprime el grupo entero: en pantalla van
   separados por aire, y en papel cada uno empieza en su propia página (el
   primero no, o saldría una hoja en blanco delante). */
.sx-pp-sheet + .sx-pp-sheet { margin-top: 2rem; }
@media print {
  .sx-pp-sheet + .sx-pp-sheet { break-before: page; page-break-before: always; margin-top: 0; }
}

/* Tarjeta Acumulativa: rejilla de datos biográficos (reusa .sx-tr* para todo
   lo demás — bandas, stat tiles y tablas por año ya son genéricas). */
.sx-cr-section-title { font-size: .95rem; font-weight: 700; color: var(--sx-text-heading); margin: 1.3rem 0 .5rem; padding-bottom: .35rem; border-bottom: 2px solid var(--sx-border-color); }
.sx-cr-info { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: .75rem 1.25rem; margin: .75rem 0; }
.sx-cr-info__k { font-size: .68rem; text-transform: uppercase; letter-spacing: .4px; color: var(--sx-text-muted); }
.sx-cr-info__v { font-size: .88rem; font-weight: 600; color: var(--sx-text-heading); margin-top: .15rem; }
.sx-cr-conduct__cell, .sx-cr-comment__cell, .sx-cr-tests__cell { cursor: pointer; }
.sx-cr-conduct__cell:hover, .sx-cr-comment__cell:hover, .sx-cr-tests__cell:hover { background: rgba(var(--sx-primary-rgb), .06); }

/* Estado vacío de la transcripción (llamativo, de marca). */
.sx-transcript-empty { text-align: center; padding: 3.5rem 1.5rem; }
.sx-transcript-empty__icon { width: 84px; height: 84px; margin: 0 auto 1.25rem; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: rgba(var(--sx-primary-rgb), .12); color: var(--sx-primary-text); font-size: 2.4rem; }
.sx-transcript-empty__title { font-size: 1.05rem; font-weight: 700; color: var(--sx-text-heading); margin-bottom: .35rem; }
.sx-transcript-empty__hint { color: var(--sx-text-muted); max-width: 360px; margin: 0 auto; font-size: .9rem; }

/* ===========================================================================
   Collapsible Table — BASE COMPARTIDA
   Movido desde: public/admin/{grading,modules,standards,geo,evaluations,
   lookups,planning}.php (todas tenían este mismo bloque <style> inline).
   Se consolida UNA sola vez; abajo van solo los deltas por página.
   =========================================================================== */
.sx-lvl { width: 100%; margin-bottom: 0; vertical-align: middle; }
.sx-lvl > thead > tr > th { font-size: .8rem; text-transform: uppercase; letter-spacing: .02em; white-space: nowrap; }
.sx-lvl > tbody > tr > td { vertical-align: middle; }

/* ===========================================================================
   TABLA A RAS DEL CARD — para las tablas que NO son DataTables.
   ===========================================================================
   Regla del sistema (design-system-css #11): una tabla de datos va a ras de su
   card. Las DataTables ya lo consiguen con .sx-att-card. Las demás —las
   colapsables de nivel y las que se pintan a mano (gradebook, rúbricas,
   resultados…)— se quedaban metidas 1.25rem por el padding del card-body.

   POR QUÉ :has() Y NO UNA CLASE: el selector describe la condición real —"un
   card-body cuyo HIJO DIRECTO es el envoltorio de una tabla"— así que no hay que
   acordarse de poner una clase en la próxima página. Ya se usaba en courses.css.

   EL `> >` ES EL FILTRO, y no es casual:
     - DataTables NO matchea: su bootstrap5 crea su propio wrapper anidado
       (.dataTables_wrapper > .row > .col > .table-responsive), así que su
       .table-responsive no es hijo directo del card-body. Su tratamiento sigue
       siendo .sx-att-card, y este selector no lo pisa.
     - Las tablas ANIDADAS de los árboles tampoco: viven dentro de
       .sx-detail-inner y conservan su indentación.
     - Los widgets de dashboard con tablita dentro de una columna tampoco: ahí el
       padding del card es el correcto.
   =========================================================================== */
.card-body:has(> .table-responsive:not(.sx-table-flush) > .table) { padding: 0; }
/* ESQUINAS DE ABAJO. La tabla a ras termina exactamente en el canto inferior del
   card, y su envoltorio es un rectángulo de esquinas rectas. Con .card normal no
   se nota (overflow:hidden recorta), pero las tarjetas que dejan escapar sus
   dropdowns —.sx-card-overflow, que es lo que usan las colapsables— tienen
   overflow:visible: al pasar el ratón por la ÚLTIMA fila, su fondo de hover se
   pintaba cuadrado por encima del redondeo y tapaba el trazo curvo del borde del
   card en las dos esquinas.
   El radio se le da al .table-responsive, que ya recorta por su cuenta
   (overflow-x:auto hace que el eje vertical también recorte), así que el fondo de
   la fila sigue la curva sin tocar el overflow del card ni el de la tabla.
   Solo cuando la tabla es el ÚLTIMO hijo de un card-body que a su vez cierra el
   card: si debajo hay paginador, pie de tarjeta o cualquier otra cosa, la tabla no
   llega al canto y no hay nada que redondear.
   El radio es el del card MENOS su borde de 1px: el card-body queda por dentro de
   ese borde, y con los 12px pelados la curva del fondo asomaba un pelo por fuera
   de la del card. */
.card > .card-body:last-child:has(> .table-responsive:not(.sx-table-flush) > .table) > .table-responsive:last-child {
  border-bottom-left-radius: calc(var(--radius) - 1px);
  border-bottom-right-radius: calc(var(--radius) - 1px);
}
/* Lo que convive con la tabla dentro de ese card-body necesita su propio aire,
   ahora que el card ya no lo pone. Mismo .85rem/1rem que usa .sx-att-card para las
   filas de controles de DataTables: es lo que las alinea con las celdas. */
.card-body:has(> .table-responsive:not(.sx-table-flush) > .table) > .sx-lvl-top { padding: .85rem 1rem; }
.card-body:has(> .table-responsive:not(.sx-table-flush) > .table) > .sx-pager { padding: 0 1rem .85rem; margin-top: .75rem; }
/* El estado vacío y los estados de carga/error que comparten card-body con la
   tabla: sin el padding del card se pegarían a los bordes. */
.card-body:has(> .table-responsive:not(.sx-table-flush) > .table) > .sx-transcript-empty { padding-inline: 1.5rem; }
.card-body:has(> .table-responsive:not(.sx-table-flush) > .table) > .sx-state { padding: .75rem 1rem; }
/* Lo mismo para los avisos y los bloques que acompañan a la tabla (la leyenda
   de materias y el segmentado de grupo del constructor de horarios): sin esto
   quedan pegados al borde del card, y el último además al borde inferior. */
.card-body:has(> .table-responsive:not(.sx-table-flush) > .table) > .sx-note,
.card-body:has(> .table-responsive:not(.sx-table-flush) > .table) > .sx-card-inset { padding-inline: 1rem; }
.card-body:has(> .table-responsive:not(.sx-table-flush) > .table) > .sx-note:first-child,
.card-body:has(> .table-responsive:not(.sx-table-flush) > .table) > .sx-card-inset:first-child { padding-top: .85rem; }
/* Si el primero está oculto (un aviso que no aplica), el aire de arriba pasa al
   siguiente: `:first-child` mira el DOM, no lo que se ve. */
.card-body:has(> .table-responsive:not(.sx-table-flush) > .table) > .sx-note.d-none + .sx-note,
.card-body:has(> .table-responsive:not(.sx-table-flush) > .table) > .sx-note.d-none + .sx-card-inset { padding-top: .85rem; }
.card-body:has(> .table-responsive:not(.sx-table-flush) > .table) > .sx-note:last-child,
.card-body:has(> .table-responsive:not(.sx-table-flush) > .table) > .sx-card-inset:last-child { padding-bottom: .85rem; }

/* ---------------------------------------------------------------------------
   .sx-table-flush — tabla a ras cuando el card-body SÍ conserva su padding.
   ---------------------------------------------------------------------------
   El caso de admin/promotion-rules: el card-body tiene contenido mixto (un texto
   introductorio, un formulario Y la tabla). Quitarle el padding pegaría el texto y
   los campos a los bordes, así que la regla de arriba —que anula el padding
   entero— no sirve, y por eso su `> >` no la alcanzaba.

   Aquí solo la TABLA se estira hasta los bordes, cancelando el padding con un
   margen negativo del tamaño exacto. Ese tamaño sale de --sx-card-pad, que declara
   el propio .card-body (components.css): repetir aquí un 1.25rem literal sería
   dejar dos números que divergen en cuanto alguien toque uno.

   Va en el .table-responsive, no en la <table>: así la tabla conserva su scroll
   horizontal propio y no desborda el card cuando es ancha.

   EXCLUYENTE CON LA REGLA DE ARRIBA, y no es teórico: si un .sx-table-flush cayera
   como hijo directo del card-body, dispararían LAS DOS —el :has() dejaría el
   padding en 0 y encima el margen negativo restaría otros 20px— y la tabla se
   saldría del card. Medido: -19px por lado. De ahí el :not(.sx-table-flush) del
   selector de arriba: donde una manda, la otra se calla.
   --------------------------------------------------------------------------- */
.sx-table-flush {
  margin-inline: calc(var(--sx-card-pad, 1.25rem) * -1);
  /* El ancho lo resuelve el margen negativo sobre un bloque; width:auto evita que
     un w-100 heredado lo fije al ancho viejo. */
  width: auto;
}
/* Las celdas recuperan el aire lateral que daba el card: mismo 1rem que el resto
   de tablas a ras del sistema (ver .sx-att-card). */
.sx-table-flush > .table > thead > tr > th:first-child,
.sx-table-flush > .table > tbody > tr > td:first-child { padding-inline-start: 1rem; }
.sx-table-flush > .table > thead > tr > th:last-child,
.sx-table-flush > .table > tbody > tr > td:last-child { padding-inline-end: 1rem; }

/* Celda-toggle (chevron) y celda-acciones, compactas. */
.sx-col-toggle { width: 2.25rem; text-align: center; }
.sx-col-actions { width: 1%; white-space: nowrap; text-align: start; }
.sx-col-status  { width: 1%; white-space: nowrap; text-align: start; }
.sx-toggle { background: none; border: 0; padding: 0; width: 1.25rem; line-height: 1; color: var(--sx-text-muted); }
.sx-toggle.is-leaf { visibility: hidden; }
/* Celda de código en tabla de nivel. El árbol de estándares ya no la usa (el
   código bajó bajo el texto), pero sí grading, grading-settings y modules. */
.sx-row-code { font-weight: 600; white-space: nowrap; }

/* Fila-detalle: contiene la tabla anidada del nivel hijo. */
.sx-detail > td { padding: 0; border-top: 0; }
.sx-detail-inner { padding: .5rem .5rem .75rem 1.75rem; }

.sx-state { padding: .75rem 1rem; color: var(--sx-text-muted); }

/* Barra de herramientas de cada tabla anidada (título + botón "Añadir"). */
.sx-lvl-toolbar { display: flex; align-items: center; justify-content: space-between; gap: .5rem; padding: .25rem .25rem .5rem; }
.sx-lvl-toolbar .sx-lvl-title { font-size: .8rem; font-weight: 600; text-transform: uppercase; letter-spacing: .02em; margin: 0; }

/* Cabecera colapsable por estudiante (Materias por estudiante, modo grupo). */
.sc-stu-toggle { cursor: pointer; }
.sc-stu-toggle .sc-chevron { transition: transform .2s ease; }
.sc-stu-toggle[aria-expanded="true"] .sc-chevron { transform: rotate(90deg); }

/* Controles del nivel raíz, con la MISMA maqueta que DataTables:
 *
 *   .sx-lvl-top   [Mostrar N ▾]                    [Buscar…]
 *                 ┌──────────── tabla ────────────┐
 *   .sx-pager     [Mostrando 1 a 3 de 3]      [‹ 1 2 3 ›]
 *
 * Los dos son flex con space-between, así que el primer hijo cae a la izquierda y
 * el último a la derecha — igual que .dataTables_length/.dataTables_filter y
 * .dataTables_info/.dataTables_paginate. El padding lateral es 1rem: el mismo que
 * el de las celdas de la tabla (ver .sx-att-card), para que el selector, el
 * buscador, la info y la primera columna caigan en la misma línea vertical. */
.sx-lvl-top { display: flex; align-items: center; justify-content: space-between; gap: .75rem; flex-wrap: wrap; }
.sx-lvl-top__search { width: 100%; max-width: 20rem; }
.sx-pager { display: flex; align-items: center; justify-content: space-between; gap: .75rem; flex-wrap: wrap; margin-top: .75rem; }
.sx-pager .pagination { flex-wrap: wrap; }
/* Si el selector de largo se oculta (tabla vacía), el buscador no debe saltar a la
   izquierda: el hueco se mantiene. */
.sx-lvl-top > .d-none + .sx-lvl-top__search { margin-inline-start: auto; }

/* Tinte del nivel "item" (solo evaluations.php: sus niveles Item y Niveles).
   Va en success porque las dos tablas que acompaña —sx-lvl-item y sx-lvl-level—
   son success: el título salía azul sobre una tabla verde. Antes lo compartía con
   planning.php, que sí quería info, y por eso estaba mal para uno de los dos;
   planning ya tiene el suyo (sx-tint-plan-item). */
.sx-lvl-toolbar.sx-tint-item .sx-lvl-title { color: var(--sx-success-dark); }

/* ===========================================================================
   Estilos movidos desde public/admin/grading.php (regla: nada de <style> inline)
   Solo delta: niveles Escala -> primary, Banda -> info. (Base compartida arriba.)
   =========================================================================== */
.sx-lvl-scale > thead > tr > th { background: var(--sx-body-bg); color: var(--sx-text-muted); }
.sx-lvl-band > thead > tr > th { background: var(--sx-info-light); color: var(--sx-info-dark); }
.sx-lvl-toolbar.sx-tint-band .sx-lvl-title { color: var(--sx-info-dark); }

/* ===========================================================================
   Estilos movidos desde public/admin/modules.php (regla: nada de <style> inline)
   Solo delta: Módulo -> primary, Funcionalidad -> info. (Base compartida arriba.)
   =========================================================================== */
.sx-col-default { width: 1%; white-space: nowrap; text-align: start; }
.sx-lvl-module   > thead > tr > th { background: var(--sx-body-bg); color: var(--sx-text-muted); }
.sx-lvl-feature  > thead > tr > th { background: var(--sx-info-light); color: var(--sx-info-dark); }
.sx-lvl-toolbar.sx-tint-feature .sx-lvl-title { color: var(--sx-info-dark); }

/* ===========================================================================
   Estilos movidos desde public/admin/standards.php (regla: nada de <style> inline)
   Solo delta: Estándar -> primary, Expectativa -> info, Indicador -> success.
   =========================================================================== */
.sx-lvl-standard   > thead > tr > th { background: var(--sx-body-bg); color: var(--sx-text-muted); }
.sx-lvl-expectation > thead > tr > th { background: var(--sx-info-light); color: var(--sx-info-dark); }
.sx-lvl-indicator  > thead > tr > th { background: var(--sx-success-light); color: var(--sx-success-dark); }
.sx-lvl-toolbar.sx-tint-expectation .sx-lvl-title { color: var(--sx-info-dark); }
.sx-lvl-toolbar.sx-tint-indicator  .sx-lvl-title { color: var(--sx-success-dark); }

/* ===========================================================================
   Estilos movidos desde public/admin/geo.php (regla: nada de <style> inline)
   Solo delta: País -> primary, Ciudades -> info. (Base compartida arriba.)
   =========================================================================== */
.sx-col-count   { width: 1%; white-space: nowrap; text-align: start; }
.sx-row-name { font-weight: 600; }
.sx-lvl-country > thead > tr > th { background: var(--sx-body-bg); color: var(--sx-text-muted); }
.sx-lvl-city > thead > tr > th { background: var(--sx-info-light); color: var(--sx-info-dark); }
.sx-lvl-toolbar.sx-tint-city .sx-lvl-title { color: var(--sx-info-dark); }

/* ===========================================================================
   Estilos movidos desde public/admin/evaluations.php (regla: nada de <style> inline)
   Delta: Instrumento/Sección/Item + pestaña Escalas (Escala/Opciones/Niveles).
   =========================================================================== */
.sx-lvl-instrument > thead > tr > th { background: var(--sx-body-bg); color: var(--sx-text-muted); }
.sx-lvl-section > thead > tr > th { background: var(--sx-info-light); color: var(--sx-info-dark); }
.sx-lvl-item > thead > tr > th { background: var(--sx-success-light); color: var(--sx-success-dark); }
/* Pestaña Escalas: Escala -> primary; Opciones -> info; Niveles -> success.
   Reutiliza los tintes -section (info) y -item (success) porque aquí valen por su
   COLOR, no por la entidad: "Opciones" toma el tinte info y "Niveles" el success.
   sx-lvl-scale lo define el bloque de grading.php: misma clase, misma página raíz
   y mismos valores. Estaba duplicada aquí, palabra por palabra. */
.sx-lvl-option > thead > tr > th { background: var(--sx-info-light); color: var(--sx-info-dark); }
.sx-lvl-level  > thead > tr > th { background: var(--sx-success-light); color: var(--sx-success-dark); }
/* Apila las dos tablas hijas (Opciones / Niveles) con separación. */
.sx-scale-child + .sx-scale-child { margin-top: 1rem; }
.sx-lvl-toolbar.sx-tint-section .sx-lvl-title { color: var(--sx-info-dark); }

/* ===========================================================================
   Estilos movidos desde public/admin/lookups.php (regla: nada de <style> inline)
   Solo delta: Tipo -> primary, Valor -> info, + chip de color del valor.
   =========================================================================== */
.sx-lvl-type  > thead > tr > th { background: var(--sx-body-bg); color: var(--sx-text-muted); }
.sx-lvl-value > thead > tr > th { background: var(--sx-info-light); color: var(--sx-info-dark); }
.sx-lvl-toolbar.sx-tint-value .sx-lvl-title { color: var(--sx-info-dark); }
/* Chip de color del valor. */
.sx-color-chip { display: inline-flex; align-items: center; gap: .35rem; }
.sx-color-dot { display: inline-block; width: 14px; height: 14px; border-radius: 50%; border: 1px solid var(--sx-border-color); }

/* ===========================================================================
   Estilos movidos desde public/admin/planning.php (regla: nada de <style> inline)
   Delta: Sección -> primary (raíz), Ítem -> info.

   NOMBRES PROPIOS (sx-lvl-plan-*), y no es cosmético: esta página llamaba a sus
   niveles sx-lvl-section y sx-lvl-item, los MISMOS nombres que usa
   evaluations.php — pero con otro significado. Aquí "section" es la RAÍZ (gris +
   borde primary); allí es un nivel HIJO (info). Como este bloque va después,
   ganaba, y evaluations renderizaba su "Sección" en gris con un borde de más y su
   "Item" en azul en vez de verde. Misma especificidad, decide el orden del
   archivo: una colisión silenciosa que solo se ve mirando la pantalla.
   =========================================================================== */
.sx-col-icon    { width: 1%; white-space: nowrap; text-align: start; }
.sx-col-sort    { width: 1%; white-space: nowrap; text-align: center; }
.sx-lvl-plan-section > thead > tr > th { background: var(--sx-body-bg); color: var(--sx-text-muted); }
.sx-lvl-plan-item > thead > tr > th { background: var(--sx-info-light); color: var(--sx-info-dark); }
.sx-lvl-toolbar.sx-tint-plan-item .sx-lvl-title { color: var(--sx-info-dark); }

/* ===========================================================================
   Estilos movidos desde public/admin/billing-invoice.php (regla: nada de <style> inline)
   =========================================================================== */
/* Toggle minimalista $ / % del descuento (sin azul de Bootstrap). */
.sx-disc-toggle { display: inline-flex; }
.sx-disc-toggle .btn-check + .sx-disc-btn {
  border: 1px solid var(--sx-primary);
  color: var(--sx-primary-text);
  background: transparent;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  padding: 0;
  line-height: 1.6;
  --bs-btn-focus-shadow-rgb: var(--sx-primary-rgb);
}
.sx-disc-toggle .sx-disc-btn:first-of-type { border-top-left-radius: .375rem; border-bottom-left-radius: .375rem; }
.sx-disc-toggle .sx-disc-btn:last-of-type  { border-top-right-radius: .375rem; border-bottom-right-radius: .375rem; border-left: 0; }
.sx-disc-toggle .btn-check:checked + .sx-disc-btn {
  background: var(--sx-primary-solid);
  border-color: var(--sx-primary-solid);
  color: #fff;
}
.sx-disc-toggle .btn-check:focus-visible + .sx-disc-btn {
  box-shadow: 0 0 0 .2rem rgba(var(--sx-primary-rgb), .35);
}
/* Total en color primario del theme. */
#totTotal { color: var(--sx-primary-text) !important; font-family: var(--font-body); }
/* Boton agregar producto: icono solo, paleta (nunca azul). */
#btnAddItem { white-space: nowrap; }
/* Checkboxes de la tabla de items: todos del mismo tamaño. */
#itemsBody .form-check-input,
#itemsSelectAll {
  width: 1rem;
  height: 1rem;
  margin: 0;
  vertical-align: middle;
}
/* Alertas de la seccion de ítems (vacío + confirmación de borrado): layout flex
   SIN !important. Bootstrap `.d-flex` es `display:flex !important` y ganaría sobre
   el `display:none` inline que pone jQuery .hide(), dejando las alertas SIEMPRE
   visibles. Con esta clase propia, .show()/.hide() funcionan correctamente. */
.sx-items-alert { display: flex; align-items: center; flex-wrap: wrap; }
.sx-items-alert.sx-items-between { justify-content: space-between; }
/* Cantidad editable en linea: el input se ve como texto plano hasta que
   recibe foco/hover; ahi aparece el borde y el fondo para "activarlo". */
.sx-qty-input {
  width: 4.5rem;
  text-align: right;
  font: inherit;
  color: inherit;
  border: 1px solid transparent;
  background: transparent;
  border-radius: .375rem;
  padding: .15rem .4rem;
  cursor: pointer;
  -moz-appearance: textfield;
}
.sx-qty-input::-webkit-outer-spin-button,
.sx-qty-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.sx-qty-input:hover { border-color: var(--sx-border-color); }
.sx-qty-input:focus {
  cursor: text;
  background: var(--sx-card-bg);
  outline: none;
}
/* Precio unitario editable: un poco mas ancho y con prefijo $ pegado al numero. */
.sx-price-input { width: 6rem; }
.sx-price-prefix { color: inherit; }

/* ============================================================
   Autosave indicator (sx-autosave.js) — borrador/publicado.
   Indicador discreto en el footer del modal; el icono de "saving"
   gira con .sx-spin. Clases scopeadas (prefijo sx-), sin elementos
   desnudos, segun UI_CONVENTIONS §15.
   ============================================================ */
.sx-autosave-indicator {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  min-height: 1.25rem;
  line-height: 1.25;
}
.sx-autosave-indicator:empty { display: none; }
@keyframes sxAutosaveSpin { to { transform: rotate(360deg); } }
.sx-autosave-indicator .sx-spin {
  display: inline-block;
  animation: sxAutosaveSpin 1s linear infinite;
}

/* ============================================================
   AI Assistant (public/app/ai-assistant.php · ai-assistant.js)
   Layout de chat: sidebar de conversaciones + hilo + input.
   Clases scopeadas con prefijo .sx-ai- (UI_CONVENTIONS §15).
   ============================================================ */

/* Lista de conversaciones (sidebar) */
.sx-ai-conv-list {
  max-height: 60vh;
  overflow-y: auto;
}
.sx-ai-conv-item {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  border-radius: var(--radius-sm);
  padding: 0.25rem;
  margin-bottom: 0.25rem;
  transition: var(--transition-fast);
}
.sx-ai-conv-item:hover { background: var(--sx-row-hover); }
.sx-ai-conv-item.active { background: var(--sx-primary-light); }
.sx-ai-conv-open {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.1rem;
  border: 0;
  background: transparent;
  text-align: left;
  padding: 0.4rem 0.5rem;
  color: var(--sx-text-body);
  cursor: pointer;
}
.sx-ai-conv-title {
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.sx-ai-conv-meta {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.sx-ai-conv-edit,
.sx-ai-conv-del { flex: 0 0 auto; padding: 0.2rem 0.3rem; line-height: 1; }
/* Iconos de acción pegados entre sí (sin separación del gap del item). */
.sx-ai-conv-edit { margin-left: 0.1rem; }
.sx-ai-conv-edit + .sx-ai-conv-del { margin-left: -0.2rem; }

/* Hilo de mensajes */
.sx-ai-thread {
  overflow-y: auto;
  max-height: 60vh;
  min-height: 280px;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.sx-ai-thread-empty { margin: auto; max-width: 28rem; }

.sx-ai-msg { display: flex; }
.sx-ai-msg--user { justify-content: flex-end; }
.sx-ai-msg--assistant { justify-content: flex-start; }

/* Misma burbuja que la mensajería persona-a-persona (.sx-chat__bubble, arriba en
   este archivo): sin borde, el fondo gris para lo recibido y el tinte de marca
   para lo propio, y la esquina inferior del lado del emisor recortada a 4px —
   ese "pico" es lo que hace que se lea como conversación y no como tarjetas.
   Lo único que NO se copia es el ancho: la mensajería usa 75% y aquí se queda en
   85% porque la respuesta del asistente trae tablas y bloques de código, que a
   75% empiezan a scrollear en horizontal. */
.sx-ai-bubble {
  max-width: 85%;
  padding: 0.5rem 0.75rem;
  border-radius: 14px;
  border: 0;
  background: var(--sx-body-bg);
}
.sx-ai-msg--assistant .sx-ai-bubble { border-bottom-left-radius: 4px; }
.sx-ai-msg--user .sx-ai-bubble {
  background: var(--sx-primary-light);
  color: var(--sx-text-heading);
  border-bottom-right-radius: 4px;
}
/* Tarjeta de acción propuesta por la IA (aún no se ha guardado nada): borde de
   marca para que no se confunda con una respuesta de texto más. */
.sx-ai-action-card {
  max-width: 85%;
  border-color: var(--sx-primary-text);
}
.sx-ai-action-card .card-header { background: var(--sx-primary-light); }
.sx-ai-action-card .card-header i { color: var(--sx-primary-text); }

/* Igual que .sx-chat__bubble-sender: dentro de la burbuja, pequeño y atenuado. */
.sx-ai-msg-role { font-size: .72rem; font-weight: 600; opacity: .8; color: inherit; margin-bottom: 2px; }
.sx-ai-msg-body {
  white-space: pre-wrap;   /* conserva saltos de línea del texto del LLM */
  word-break: break-word;
  color: var(--sx-text-body);
}
/* Respuestas del asistente renderizadas como HTML: sin pre-wrap y con espaciado. */
.sx-ai-msg-body--html { white-space: normal; }
.sx-ai-msg-body--html > :first-child { margin-top: 0; }
.sx-ai-msg-body--html > :last-child { margin-bottom: 0; }
.sx-ai-msg-body--html p { margin: 0 0 0.5rem; }
.sx-ai-msg-body--html ul,
.sx-ai-msg-body--html ol { margin: 0 0 0.5rem; padding-left: 1.25rem; }
.sx-ai-msg-body--html li { margin-bottom: 0.15rem; }
.sx-ai-msg-body--html h1,
.sx-ai-msg-body--html h2,
.sx-ai-msg-body--html h3,
.sx-ai-msg-body--html h4,
.sx-ai-msg-body--html h5,
.sx-ai-msg-body--html h6 { margin: 0.5rem 0 0.35rem; font-weight: 700; }
.sx-ai-msg-body--html h4 { font-size: 1rem; }
.sx-ai-msg-body--html code {
  background: var(--sx-body-bg);
  padding: 0.05rem 0.3rem;
  border-radius: var(--radius-sm);
  font-size: 0.875em;
}
.sx-ai-msg-body--html pre {
  background: var(--sx-body-bg);
  padding: 0.6rem 0.75rem;
  border-radius: var(--radius-sm);
  overflow-x: auto;
  margin: 0 0 0.5rem;
}
.sx-ai-msg-body--html pre code { background: none; padding: 0; }
.sx-ai-msg-body--html table {
  width: 100%;
  border-collapse: collapse;
  margin: 0 0 0.5rem;
  font-size: 0.9em;
}
.sx-ai-msg-body--html th,
.sx-ai-msg-body--html td {
  border: 1px solid var(--sx-border-color);
  padding: 0.3rem 0.5rem;
  text-align: left;
}
.sx-ai-msg-body--html a { color: var(--sx-primary-text); text-decoration: underline; }
.sx-ai-msg-body--html blockquote {
  border-left: 3px solid var(--sx-border-color);
  margin: 0 0 0.5rem;
  padding-left: 0.75rem;
  color: var(--sx-text-muted);
}

/* Valoración de la respuesta (👍/👎): íconos sutiles bajo cada mensaje del asistente. */
.sx-ai-feedback {
  display: flex;
  gap: 0.25rem;
  margin-top: 0.4rem;
}
.sx-ai-feedback-btn {
  border: 0;
  background: none;
  padding: 0.1rem 0.3rem;
  line-height: 1;
  border-radius: var(--radius-sm);
  color: var(--sx-text-muted);
  cursor: pointer;
  transition: var(--transition);
}
.sx-ai-feedback-btn:hover { color: var(--sx-text-body); background: var(--sx-body-bg); }
.sx-ai-feedback-btn.is-active { color: var(--sx-primary-text); }

/* Columna del mensaje: burbuja + pie (hora · acciones). Limita el ancho al 85%
   (antes lo hacía la burbuja) para que el pie se alinee al borde del mensaje. */
.sx-ai-msg-col { display: flex; flex-direction: column; max-width: 85%; min-width: 0; }
.sx-ai-msg--user .sx-ai-msg-col { align-items: flex-end; }
.sx-ai-msg--assistant .sx-ai-msg-col { align-items: flex-start; }
.sx-ai-msg-col .sx-ai-bubble { max-width: 100%; }

/* Pie: hora siempre visible; acciones (copiar/editar) fuera de la burbuja, solo
   al hacer hover sobre el mensaje. */
.sx-ai-msg-foot {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 2px 4px 0;
  font-size: 0.66rem;
  color: var(--sx-text-muted);
}
.sx-ai-msg--user .sx-ai-msg-foot { flex-direction: row-reverse; }
.sx-ai-msg-time { line-height: 1; white-space: nowrap; }
.sx-ai-msg-actions {
  display: flex;
  gap: 0.1rem;
  opacity: 0;
  transition: var(--transition);
}
.sx-ai-msg:hover .sx-ai-msg-actions { opacity: 1; }
.sx-ai-act-btn { font-size: 0.8rem; }

/* Textarea de edición: crece con el contenido, sin barra de scroll. */
.sx-ai-edit-ta { resize: none; overflow-y: hidden; }

/* Medidores de uso: barras tipo "context window" (pill + relleno suave). */
.sx-ai-usage-card .progress {
  height: 7px;
  border-radius: var(--radius-pill);
  background: var(--sx-border-color);
  overflow: hidden;
}
.sx-ai-usage-card .progress-bar {
  border-radius: var(--radius-pill);
  transition: width 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}
.sx-ai-usage-card #uCtxLbl,
.sx-ai-usage-card #u5hLbl,
.sx-ai-usage-card #uGenLbl {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

/* Indicador "pensando…" */
/* Indicador "pensando": burbuja con ícono en pulso + puntos que rebotan. */
.sx-ai-thinking-bubble {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}
.sx-ai-thinking-icon {
  color: var(--sx-primary-text);
  font-size: 1.05rem;
  animation: sxAiPulse 1.4s ease-in-out infinite;
}
.sx-ai-thinking-label {
  color: var(--sx-text-muted);
  font-style: italic;
  background: linear-gradient(90deg,
    var(--sx-text-muted) 0%, var(--sx-primary) 50%, var(--sx-text-muted) 100%);
  background-size: 200% auto;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: sxAiShimmer 2s linear infinite;
}
.sx-ai-typing {
  display: inline-flex;
  align-items: center;
  gap: 3px;
}
.sx-ai-typing span {
  width: 6px;
  height: 6px;
  border-radius: var(--radius-circle);
  background: var(--sx-primary);
  animation: sxAiBounce 1.2s ease-in-out infinite;
}
.sx-ai-typing span:nth-child(2) { animation-delay: 0.18s; }
.sx-ai-typing span:nth-child(3) { animation-delay: 0.36s; }
@keyframes sxAiBounce {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.45; }
  30% { transform: translateY(-5px); opacity: 1; }
}
@keyframes sxAiPulse {
  0%, 100% { transform: scale(1); opacity: 0.7; }
  50% { transform: scale(1.18); opacity: 1; }
}
@keyframes sxAiShimmer {
  0% { background-position: 200% center; }
  100% { background-position: 0% center; }
}
@media (prefers-reduced-motion: reduce) {
  .sx-ai-thinking-icon,
  .sx-ai-thinking-label,
  .sx-ai-typing span { animation: none; }
}

/* Fila de input */
.sx-ai-input-row .form-icon { margin-bottom: 0; }
/* Sin min-height global (components.css lo pone en 100px): este textarea arranca
   en 1 renglón y crece solo (autoGrow). */
.sx-ai-input-row textarea.form-control { resize: vertical; min-height: 0; }
/* Selector "enfocar clase" en el header del chat. */
.sx-ai-focus { min-width: 220px; max-width: 340px; margin-bottom: 0; }
.sx-ai-focus .select2-container { min-width: 200px; }
/* Micrófono grabando: color de marca "peligro" + pulso suave. */
.sx-ai-mic-on { color: var(--sx-red); border-color: var(--sx-red); animation: sxMicPulse 1.2s ease-in-out infinite; }
@keyframes sxMicPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }

/* =========================================================================
 * Inscripciones (admin) — enrollment-admin
 * Prefijo: .sx-enradmin-
 * ========================================================================= */

/* Modal de detalle: lista de documentos (checklist). */
.sx-enradmin-doclist .sx-enradmin-docrow:last-child,
.sx-enradmin-conlist .sx-enradmin-conrow:last-child {
  border-bottom: 0 !important;
}
.sx-enradmin-docstate {
  width: auto;
  min-width: 9rem;
}

/* Configurador: grupos de campos. */
.sx-enradmin-cfg-group {
  padding-bottom: 0.5rem;
  border-bottom: 1px dashed var(--sx-border-color);
}
.sx-enradmin-cfg-group:last-child {
  border-bottom: 0;
}

/* Configurador: bloques de consentimiento. */
.sx-enradmin-cfg-con {
  background: var(--sx-body-bg);
}
.sx-enradmin-cfg-con textarea {
  resize: vertical;
}

/* Espacio interno coherente entre fieldsets del configurador. */
.sx-enradmin-fieldset {
  margin-bottom: 1.25rem;
}

/* Avatar grande para el badge de identidad del estudiante. */
.sx-avatar--lg {
  width: 62px;
  height: 62px;
  min-width: 62px;
  font-size: 1.45rem;
}

/* Tamaño de fuente extra pequeño (Bootstrap solo llega a fs-6). */
.fs-7 { font-size: 0.8rem; }

/* Avatar mediano (cabeceras de colapsables por grupo). */
.sx-avatar--md {
  width: 46px;
  height: 46px;
  min-width: 46px;
  font-size: 1.1rem;
}

/* Variantes de color para el avatar de iniciales (paleta schoolaryx). */
.sx-avatar--primary { background: var(--sx-primary); }
.sx-avatar--purple  { background: var(--sx-purple); }
.sx-avatar--success { background: var(--sx-green); }
.sx-avatar--sky     { background: var(--sx-sky); }
.sx-avatar--red     { background: var(--sx-red); }

/* ===========================================================================
   Guía de orden de importación (app/import.php).

   Cada paso es un <button> y no un <a>: no navega a ninguna parte, solo
   selecciona la entidad en el formulario de al lado. Un enlace con href="#"
   ensuciaría el historial y le mentiría al lector de pantalla sobre lo que hace.
   =========================================================================== */
.sx-import-steps { list-style: none; counter-reset: none; margin: 0; padding: 0; }
/* Solo en la variante APILADA: en la de fila los <li> son columnas de un .row y
   el aire se lo da la gutter de Bootstrap, igual para los cuatro. */
.sx-import-steps:not(.sx-import-steps--row) .sx-import-step + .sx-import-step { margin-top: .35rem; }

/* Variante en FILA (admin/data-io, app/import): los pasos van lado a lado, como
   una secuencia de izquierda a derecha, en vez de apilados. El borde se hace
   visible: sin él, tres cajas sin marco en horizontal parecen un solo párrafo
   partido en tres, y con marco se leen como tres pasos.

   El margen vertical de la variante apilada YA no llega aquí (la regla de
   arriba lo excluye). Antes se anulaba con `.sx-import-step + .sx-import-step
   { margin-top: 0 }`, y eso también borraba la gutter que Bootstrap pone en
   TODAS las columnas del .row — pero solo de la segunda en adelante: el primer
   paso se quedaba con 8px de margen que los otros tres no tenían, así que
   arrancaba más abajo y salía más bajito que sus hermanos. */
.sx-import-steps--row .sx-import-step__btn {
  height: 100%;
  border-color: var(--sx-border-color);
}
.sx-import-step__btn {
  display: flex;
  align-items: flex-start;
  gap: .6rem;
  width: 100%;
  text-align: left;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius);
  padding: .5rem .6rem;
  transition: var(--transition-fast, all .15s ease);
  text-decoration: none;
  color: inherit;
}
/* El puntero y el hover SOLO en los pasos que de verdad hacen algo: en
   admin/data-io hay pasos informativos (<div>) que no se pulsan, y darles mano
   de clic prometería una interacción que no existe. */
button.sx-import-step__btn,
a.sx-import-step__btn { cursor: pointer; }
button.sx-import-step__btn:hover,
a.sx-import-step__btn:hover {
  background: var(--sx-body-bg);
  border-color: var(--sx-border-color);
  color: inherit;
}
.sx-import-step__btn.is-active {
  background: var(--sx-body-bg);
  border-color: var(--sx-primary-text);
}
.sx-import-step__num {
  flex: 0 0 auto;
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 50%;
  background: var(--sx-primary-solid);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: .72rem;
  line-height: 1.4rem;
  text-align: center;
}
.sx-import-step__body { display: flex; flex-direction: column; min-width: 0; }
.sx-import-step__label {
  font-weight: 700;
  font-size: .82rem;
  color: var(--sx-text-heading);
  line-height: 1.25;
}
.sx-import-step__desc {
  font-size: .76rem;
  color: var(--sx-text-muted);
  line-height: 1.35;
  margin-top: .1rem;
}

/* ---------------------------------------------------------------------------
   app/student-courses — la tabla arranca pegada al borde superior del card.
   .sx-table-flush solo cancela el padding LATERAL del card-body; el de arriba
   seguía ahí y dejaba una franja en blanco sobre la primera fila. Se cancela
   solo cuando la tabla es lo PRIMERO del bloque: en el modo estudiante va
   detrás de la ficha del alumno, y ahí esa franja sí hace falta.
   --------------------------------------------------------------------------- */
#scStudentView > .sx-table-flush:first-child,
#scGroupBody > .sx-table-flush:first-child {
  margin-top: calc(var(--sx-card-pad, 1.25rem) * -1);
}

/* ---------------------------------------------------------------------------
   app/lesson-plan-view — cuerpo del plan escrito por el docente (.sx-plan-html)
   El HTML lo teclea (o lo PEGA desde Word/Docs) el maestro: viene con
   font-family y font-size en línea — 14pt, 36pt, "Calibri" —, tablas con
   anchos en px e imágenes a tamaño original. Nada de eso cabía en el card y el
   texto se salía del margen. Se normaliza SOLO lo que trae estilo en línea
   (los <h*>, listas y negritas del editor conservan el tamaño del tema) y todo
   lo ancho se obliga a caber. Va con !important porque compite contra el
   atributo style del propio contenido, que de otro modo gana siempre.
   --------------------------------------------------------------------------- */
.sx-plan-html {
  max-width: 100%;
  overflow-wrap: anywhere;   /* una URL o palabra larguísima ya no empuja el card */
  word-break: break-word;
}
.sx-plan-html > :last-child { margin-bottom: 0; }
.sx-plan-html [style*="font-family"] { font-family: inherit !important; }
.sx-plan-html [style*="font-size"]   { font-size: inherit !important; }
.sx-plan-html [style*="line-height"] { line-height: inherit !important; }
.sx-plan-html font { font-family: inherit !important; font-size: inherit !important; }
.sx-plan-html [style*="width"] { max-width: 100% !important; }
.sx-plan-html img,
.sx-plan-html video,
.sx-plan-html iframe { max-width: 100% !important; height: auto; }
.sx-plan-html table {
  width: 100% !important;
  max-width: 100% !important;
  table-layout: fixed;
}
.sx-plan-html th,
.sx-plan-html td {
  width: auto !important;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.sx-plan-html pre { white-space: pre-wrap; word-break: break-word; }

/* Estándares e indicadores: el indicador CUELGA de su estándar, indentado y
   con guía a la izquierda, para que se lea a qué estándar responde. Antes
   iban en dos listas seguidas y no había forma de saberlo. */
.sx-plan-std { list-style: none; margin: 0; padding: 0; }
.sx-plan-std__item + .sx-plan-std__item { margin-top: .6rem; }
.sx-plan-std__name { line-height: 1.4; }
.sx-plan-std__inds {
  list-style: disc;
  margin: .25rem 0 0;
  padding-left: 1.25rem;
  margin-left: .35rem;
  border-left: 2px solid var(--sx-border-color);
  color: var(--sx-text-muted);
  font-size: .9rem;
}
.sx-plan-std__inds li { margin-top: .15rem; padding-left: .25rem; }
.sx-plan-std__code { color: var(--sx-text-muted); font-weight: 600; }

/* app/lesson-plan-view — tarjeta "Datos del plan": fecha en píldora y cada
   dato con su ícono. Neutra a propósito (sin el color de la escuela). */
.sx-lpv-info { display: grid; gap: .85rem; }
.sx-lpv-info__date {
  display: flex; align-items: center; gap: .5rem;
  padding: .55rem .8rem; border-radius: .6rem;
  border: 1px solid var(--sx-border-color); background: var(--sx-body-bg);
  color: var(--sx-text-heading); font-weight: 600; line-height: 1.3;
}
.sx-lpv-info__date i { color: var(--sx-text-muted); flex: none; }
.sx-lpv-info__row { display: flex; align-items: flex-start; gap: .65rem; }
.sx-lpv-info__row > i {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 1.9rem; height: 1.9rem; border-radius: 50%;
  background: var(--sx-body-bg); border: 1px solid var(--sx-border-color);
  color: var(--sx-text-muted); font-size: .9rem;
}
.sx-lpv-info__text { min-width: 0; }
.sx-lpv-info__label { font-size: .72rem; font-weight: 600; letter-spacing: .05em; text-transform: uppercase; color: var(--sx-text-muted); }
.sx-lpv-info__value { font-size: .9rem; color: var(--sx-text-heading); overflow-wrap: anywhere; }

/* app/lesson-plan-view — cada sección del plan en su bloque, con ícono. Las
   vacías van punteadas y con una línea gris en vez del aviso amarillo. */
.sx-lpv__body { display: grid; gap: 1rem; }
.sx-lpv-sec {
  border: 1px solid var(--sx-border-color); border-radius: .75rem;
  padding: 1rem 1.1rem; background: var(--sx-card-bg);
}
.sx-lpv-sec.is-empty { background: transparent; border-style: dashed; padding-top: .75rem; padding-bottom: .75rem; }
.sx-lpv-sec__head { display: flex; align-items: center; gap: .6rem; margin: 0 0 .75rem; font-size: .95rem; font-weight: 700; color: var(--sx-text-heading); }
.sx-lpv-sec.is-empty .sx-lpv-sec__head { margin-bottom: .25rem; }
.sx-lpv-sec__icon {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem; border-radius: 50%;
  background: rgba(var(--sx-primary-rgb), .12); color: var(--sx-primary-text); font-size: 1rem;
}
.sx-lpv-sec.is-empty .sx-lpv-sec__icon { background: rgba(var(--sx-primary-rgb), .06); color: var(--sx-text-muted); }
.sx-lpv-sec__name { min-width: 0; }
.sx-lpv-sec__min { margin-left: auto; font-size: .78rem; font-weight: 600; color: var(--sx-text-muted); white-space: nowrap; }
.sx-lpv-sec__body { color: var(--sx-text-body); }
.sx-lpv-sec__body > :last-child { margin-bottom: 0; }
.sx-lpv-sec__empty { margin: 0 0 0 2.6rem; font-size: .875rem; font-style: italic; color: var(--sx-text-muted); }
@media (max-width: 575.98px) {
  .sx-lpv__body { gap: .75rem; }
  .sx-lpv-sec { padding: .85rem; }
  .sx-lpv-sec__empty { margin-left: 0; }
}
@media print {
  .sx-lpv-sec { break-inside: avoid; }
}

