/* ASTRA – plataforma :: sistema visual (tokens del "claude design" de marketing) */
:root {
  --terracotta:   #A84C31;
  --terracotta-h: #7F3721;
  --terracotta-t: #D98B6B;
  --tint:         #FADFD1;
  --ink:          #2A2622;
  --muted:        #6E655C;
  /* Gris de la barra lateral (nav-group, userbar): 5.76:1 sobre --ink. */
  --sidebar-muted: #A89F94;
  --sidebar-bg:   var(--ink);
  --bg:           #faf9f5;
  --surface:      #ffffff;
  --surface-2:    #F6F1E8;
  --border:       #E3DACB;
  --border-2:     #D8CDBC;
  --line:         var(--border);
  /* Borde de campos de formulario: --border-2 sólo da ~1.6:1 sobre blanco
     (falla el 3:1 de contraste no textual, WCAG 1.4.11). Token propio en vez
     de oscurecer --border-2 en todas partes (botones, tarjetas, tablas). */
  --field-border: #948878;
  --ok:           #2e7d32;
  /* #b26a00 original: ~3.8:1 sobre el fondo crema del badge, por debajo del
     4.5:1 de texto pequeño. #8a5200 da 5.79:1 sobre #fbf3e2. */
  --warn:         #8a5200;
  --danger:       #b3261e;
  --info:         #1c5d99;
  /* Pares de estado (fondo + borde) de badge, flash, banners y confirmación. */
  --ok-bg:        #eef6ee;
  --ok-border:    #bcdcbd;
  --warn-bg:      #fbf3e2;
  --warn-border:  #e6cfa0;
  --info-bg:      #e9f1f8;
  --info-border:  #b9d3e8;
  --danger-bg:    #fbebea;
  --danger-border:#e6b6b2;
  --radius:       10px;
  --radius-sm:    7px;
  --shadow:       0 1px 3px rgba(42,38,34,.08), 0 6px 20px rgba(42,38,34,.05);
  --serif:        Georgia, 'Times New Roman', serif;
  --sans:         -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

  /* Tokens que existen para el modo oscuro (ver el bloque de abajo): todo color
     que no sea de estos pares se toma de aquí y no como literal. */
  color-scheme: light;
  /* Texto sobre relleno terracota/estado (botón primario, pestaña activa, …). */
  --on-accent:    #fff;
  /* Texto sobre --terracotta-t, que no cambia de tono en oscuro. */
  --on-tint:      #2A2622;
  /* Fondo de las burbujas oscuras («Guardado», barra de selección). */
  --inverse-bg:   var(--ink);
  --focus-ring:   rgba(168,76,49,.14);
  --slot-hover:   #F1E9DC;
  --overlay:      rgba(20,17,14,.4);
  --overlay-nav:  rgba(20,17,14,.5);
  /* Anotaciones del lector: nota privada, feedback público, importadas. */
  --mark-note:          #FCE9A8;
  --mark-note-h:        #FADD7A;
  --mark-note-border:   #E3B341;
  --mark-public:        #D8ECE3;
  --mark-public-h:      #C3E3D6;
  --mark-import:        #E3D4F0;
  --mark-import-h:      #D6C0E8;
  --mark-import-border: #9B6FBF;
  /* Diagramas del libro (<img> SVG con tinta oscura): en oscuro llevan superficie clara. */
  --figure-bg:    transparent;
  --figure-pad:   0;
  /* Iconos de orden de Grid.js (SVG negros incrustados). */
  --icon-filter:  none;
}

/* Modo oscuro: sólo sigue el ajuste del sistema, sin conmutador manual. Redefine
   únicamente tokens; los pares de estado y las anotaciones se aclaran/oscurecen
   por igual para conservar contraste (texto ≥ 4.5:1, bordes de campo ≥ 3:1). */
@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;
    --terracotta:   #E08A68;
    --terracotta-h: #F0A585;
    --tint:         #3d2a20;
    --ink:          #ece5db;
    --muted:        #a89f94;
    --sidebar-bg:   #120f0d;
    --bg:           #1a1714;
    --surface:      #24201c;
    --surface-2:    #2e2924;
    --border:       #3d362f;
    --border-2:     #52493f;
    --field-border: #857a6c;
    --ok:           #7cc681;
    --warn:         #e2ac52;
    --danger:       #f2867d;
    --info:         #7db8ee;
    --ok-bg:        #1c2e1e;
    --ok-border:    #34573a;
    --warn-bg:      #32270f;
    --warn-border:  #5c4620;
    --info-bg:      #16283a;
    --info-border:  #2f4f70;
    --danger-bg:    #3a1c1a;
    --danger-border:#6b3531;
    --shadow:       0 1px 3px rgba(0,0,0,.4), 0 6px 20px rgba(0,0,0,.3);

    --on-accent:    #1a1714;
    --inverse-bg:   #ece5db;
    --focus-ring:   rgba(224,138,104,.28);
    --slot-hover:   #38322b;
    --overlay:      rgba(0,0,0,.6);
    --overlay-nav:  rgba(0,0,0,.65);
    --mark-note:          #4a3d14;
    --mark-note-h:        #5a4a1a;
    --mark-note-border:   #b08a2a;
    --mark-public:        #1f3a2e;
    --mark-public-h:      #29493a;
    --mark-import:        #3b2c4a;
    --mark-import-h:      #4a3a5c;
    --figure-bg:    #faf9f5;
    --figure-pad:   .6rem;
    --icon-filter:  invert(1);
  }
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
/* Sólo para lectores de pantalla: etiqueta un control cuya intención ya es
   evidente visualmente (p.ej. un textarea con placeholder). */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
body {
  font-family: var(--sans);
  color: var(--ink);
  background: var(--bg);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4 { font-family: var(--serif); font-weight: 600; color: var(--ink); line-height: 1.2; margin: 0 0 .5rem; }
a { color: var(--terracotta); text-decoration: none; }
a:hover { color: var(--terracotta-h); text-decoration: underline; }

/* Anillo de foco visible por teclado (Tab), en toda la app: enlaces, botones
   y navegación. :focus-visible y no :focus — un clic de mouse no debe dejar
   el anillo puesto, sólo la navegación por teclado. :where() = especificidad 0,
   así cualquier regla propia de un componente puede afinarlo. */
:where(a, button, .btn, summary, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--terracotta);
  outline-offset: 2px;
}
/* Sobre fondo oscuro (barra lateral y barra superior móvil) el terracota
   oscuro no contrasta: variante clara. */
.sidebar :focus-visible, .mobile-topbar :focus-visible {
  outline: 2px solid var(--terracotta-t);
  outline-offset: -2px;
}

/* ─── Layout app: barra lateral + contenido ─── */
.app { display: flex; min-height: 100vh; }
.sidebar {
  width: 250px; flex-shrink: 0; background: var(--sidebar-bg); color: #E7E1D8;
  display: flex; flex-direction: column; padding: 1.1rem 0;
  /* `bottom: 0` y no `height: 100vh`: en móvil `100vh` cuenta también la franja que
     ocupa la barra de direcciones del navegador, así que el final de la barra lateral
     —donde está «Cerrar sesión»— quedaba por debajo del borde visible. El bloque
     contenedor de un elemento `fixed` sí sigue la altura realmente visible. */
  position: fixed; top: 0; left: 0; bottom: 0; overflow-y: auto; z-index: 30;
}
.main { margin-left: 250px; flex: 0 1 auto; min-width: 0; display: flex; flex-direction: column; }
.sidebar .brand { font-family: var(--serif); font-size: 1.35rem; letter-spacing: .08em; color: #FCEFE7; padding: .2rem 1.3rem 1rem; }
.sidebar .brand small { display: block; font-family: var(--sans); font-size: .62rem; letter-spacing: .14em; text-transform: uppercase; color: var(--terracotta-t); margin-top: .25rem; }
.sidebar nav { display: flex; flex-direction: column; gap: 2px; padding: .4rem .6rem; }
.sidebar nav a { color: #C9C1B6; padding: .5rem .7rem; border-radius: var(--radius-sm); font-size: .9rem; }
.sidebar nav a:hover { background: rgba(255,255,255,.06); text-decoration: none; color: #fff; }
.sidebar nav a.active { background: var(--terracotta); color: var(--on-accent); }
.sidebar .navgroup { font-size: .62rem; text-transform: uppercase; letter-spacing: .12em; color: var(--sidebar-muted); padding: .9rem .9rem .25rem; }
.sidebar .userbar { margin-top: auto; padding: .9rem 1.3rem; font-size: .78rem; color: var(--sidebar-muted); border-top: 1px solid rgba(255,255,255,.08); }
.sidebar .userbar a { color: var(--terracotta-t); }

.topbar { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 1rem 1.6rem; border-bottom: 1px solid var(--border); background: var(--surface); }
/* `overflow-x: clip` y no `hidden`: `hidden` convierte a .content en contenedor
   de scroll y anula todo `position: sticky` de sus descendientes (la columna de
   notas del lector). `clip` recorta igual en horizontal sin crear scroll. */
.content { padding: 1.6rem; max-width: 1100px; width: 100%; overflow-x: clip; }
.page-title { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 1.2rem; }
footer.site { padding: 1.2rem 1.6rem; color: var(--muted); font-size: .78rem; border-top: 1px solid var(--border); }
/* Aviso de derechos: segunda línea, un punto más chica y tenue que el crédito. */
.copyright { display: block; margin-top: .3rem; font-size: .7rem; opacity: .75; letter-spacing: .01em; }

/* ─── Búsqueda de personas (asignar gestores/mentores) ─── */
[data-user-search] { position: relative; }
.user-search-results {
  position: absolute; z-index: 20; left: 0; right: 0; top: 100%; margin-top: 2px;
  background: var(--surface); border: 1px solid var(--border-2); border-radius: var(--radius-sm);
  box-shadow: var(--shadow); max-height: 220px; overflow-y: auto;
}
.user-search-result {
  display: block; width: 100%; text-align: left; padding: .5rem .7rem; border: 0; background: none;
  cursor: pointer; font: inherit; color: var(--ink); border-bottom: 1px solid var(--border);
}
.user-search-result:last-child { border-bottom: 0; }
.user-search-result:hover { background: var(--surface-2); }

/* ─── Buscador del libro (type-ahead) ─── */
.book-search { position: relative; }
/* Ocupa todo el ancho disponible: en el índice, el de la página; en el lector,
   el que dejan libre «Índice» y «Editar» en la barra fija. */
.book-search-input {
  width: 100%; padding: .5rem .8rem; color: var(--ink);
  /* 16px y no `font: inherit` (15px): por debajo de 16px iOS hace zoom al
     enfocar el campo. Mismo motivo que los textarea de los modales. */
  font-family: inherit; font-size: 16px;
  background: var(--surface); border: 1px solid var(--border-2); border-radius: var(--radius-sm);
}
.book-search-input:focus { outline: 2px solid var(--terracotta-t); outline-offset: 1px; border-color: var(--terracotta); }
.book-search-results {
  position: absolute; z-index: 40; left: 0; right: 0; top: 100%; margin-top: 4px;
  background: var(--surface); border: 1px solid var(--border-2); border-radius: var(--radius-sm);
  box-shadow: var(--shadow); max-height: min(60vh, 420px); overflow-y: auto; overscroll-behavior: contain;
}
.book-search-result {
  display: block; width: 100%; text-align: left; padding: .55rem .75rem; border: 0; background: none;
  cursor: pointer; font: inherit; color: var(--ink); border-bottom: 1px solid var(--border);
}
.book-search-result:last-child { border-bottom: 0; }
.book-search-result:hover, .book-search-result.active { background: var(--surface-2); }
.book-search-title { font-weight: 600; font-size: .9rem; }
.book-search-snippet { color: var(--muted); margin-top: .15rem; line-height: 1.4; }
.book-search-snippet mark { background: var(--terracotta-t); color: var(--on-tint); padding: 0 .1em; border-radius: 2px; }
.book-search-empty { padding: .6rem .75rem; }
/* Índice de capítulos (buscador enfocado y vacío) */
.book-search-group {
  position: sticky; top: 0; z-index: 1; background: var(--surface-2);
  padding: .35rem .75rem; text-transform: uppercase; letter-spacing: .1em; font-size: .62rem;
  border-bottom: 1px solid var(--border);
}
.book-search-result.is-current { background: var(--surface-2); }
.book-search-result.is-current .book-search-title { color: var(--terracotta); }

/* Destello al llegar a un resultado de búsqueda; se quita solo tras unos ms. */
mark.search-flash { background: var(--terracotta); color: var(--on-accent); border-radius: 2px; padding: 0 .1em; animation: search-flash-fade 2.4s ease-out; }
@keyframes search-flash-fade { 0%, 55% { background: var(--terracotta); } 100% { background: var(--terracotta-t); } }

/* Item de feedback al que se llega desde el enlace de una respuesta por correo (?fb=ID). */
.feedback-item.is-highlight { animation: item-highlight-fade 2.4s ease-out; border-radius: var(--radius-sm); }
@keyframes item-highlight-fade { 0%, 45% { background: var(--tint); } 100% { background: transparent; } }

/* ─── Tarjetas ─── */
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); padding: 1.2rem 1.3rem; margin-bottom: 1.2rem; }
.card h2, .card h3 { margin-top: 0; }
.grid { display: grid; gap: 1rem; }
.grid.cols-3 { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
.stat { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 1rem 1.1rem; }
.stat .n { font-family: var(--serif); font-size: 1.9rem; color: var(--terracotta); }
.stat .l { font-size: .78rem; color: var(--muted); text-transform: uppercase; letter-spacing: .08em; }

/* ─── Botones ─── */
.btn { display: inline-flex; align-items: center; gap: .45rem; font-family: var(--sans); font-size: .88rem; font-weight: 600; border: 1px solid var(--border-2); background: var(--surface); color: var(--ink); padding: .5rem .95rem; border-radius: var(--radius-sm); cursor: pointer; text-decoration: none; transition: background .12s, border-color .12s; }
.btn:hover { background: var(--surface-2); text-decoration: none; }
.btn-primary { background: var(--terracotta); border-color: var(--terracotta); color: var(--on-accent); }
.btn-primary:hover { background: var(--terracotta-h); border-color: var(--terracotta-h); color: var(--on-accent); }
.btn-danger { background: var(--surface); border-color: var(--danger); color: var(--danger); }
.btn-danger:hover { background: var(--danger); color: var(--on-accent); }
/* Variante discreta para acciones destructivas poco frecuentes: no compite con
   la navegación, pero se declara en rojo al apuntarla. */
.btn-quiet-danger { border-color: transparent; background: transparent; color: var(--muted); font-weight: 500; }
.btn-quiet-danger:hover { background: transparent; border-color: var(--danger); color: var(--danger); }
.btn-sm { padding: .32rem .6rem; font-size: .78rem; }
.btn-row { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; }

/* Pestañas (grupos/show.php; app.js: bindTabs). Sin JS son anclas. */
.tabs { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; border-bottom: 1px solid var(--border); margin-bottom: 1.2rem; }
.tabs a { padding: .5rem .8rem; margin-bottom: -1px; border-bottom: 2px solid transparent; color: var(--muted); font-weight: 600; text-decoration: none; }
.tabs a:hover { color: var(--ink); text-decoration: none; }
.tabs a[aria-selected="true"] { color: var(--terracotta); border-bottom-color: var(--terracotta); }

/* Acciones por fila: «Editar» + menú «⋯» (<details>). Grid.js recorta con
   overflow; al abrir, app.js (bindRowMenus) pasa el panel a position:fixed. */
.row-actions { display: flex; gap: .4rem; align-items: center; }
.row-menu { position: relative; }
.row-menu > summary { list-style: none; }
.row-menu > summary::-webkit-details-marker { display: none; }
.row-menu-list { position: absolute; right: 0; top: calc(100% + .25rem); z-index: 40; min-width: 11rem; display: flex; flex-direction: column; gap: .25rem; padding: .4rem; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow); }
.row-menu-form { display: block; margin: 0; }
.row-menu-form .btn { width: 100%; justify-content: flex-start; }
.row-menu-sep { border: 0; border-top: 1px solid var(--border); margin: .15rem 0; }

/* ─── Formularios ─── */
.field { margin-bottom: 1rem; }
.field label { display: block; font-size: .8rem; font-weight: 600; color: var(--muted); margin-bottom: .3rem; }
.field input, .field select, .field textarea {
  width: 100%; font-family: var(--sans); font-size: .92rem; color: var(--ink);
  padding: .55rem .7rem; border: 1px solid var(--field-border); border-radius: var(--radius-sm); background: var(--surface);
}
.field input:focus, .field select:focus, .field textarea:focus { outline: 1px solid var(--terracotta); outline-offset: 0; border-color: var(--terracotta); box-shadow: none; }
.field .hint { font-size: .74rem; color: var(--muted); margin-top: .25rem; }
.field .err { font-size: .76rem; color: var(--danger); margin-top: .25rem; }
/* Altura mínima = 4 renglones exactos (ver --rule-h más abajo), para que la
   última raya no quede pegada al borde inferior. */
textarea { min-height: calc(var(--rule-h) * 4 + var(--rule-pad) * 2); resize: vertical; }

/* ─── Badges / estados ─── */
.badge { display: inline-block; font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; padding: .18rem .5rem; border-radius: 999px; border: 1px solid var(--border-2); color: var(--muted); background: var(--surface-2); }
.badge.ok { color: var(--ok); border-color: var(--ok-border); background: var(--ok-bg); }
.badge.warn { color: var(--warn); border-color: var(--warn-border); background: var(--warn-bg); }
.badge.info { color: var(--info); border-color: var(--info-border); background: var(--info-bg); }
.badge.danger { color: var(--danger); border-color: var(--danger-border); background: var(--danger-bg); }

/* ─── Flash ─── */
.flash {
  display: flex; align-items: flex-start; justify-content: space-between; gap: .8rem;
  padding: .7rem 1rem; border-radius: var(--radius-sm); margin-bottom: 1rem; font-size: .88rem; border: 1px solid;
  transition: opacity .3s ease, transform .3s ease;
}
.flash.success { background: var(--ok-bg); border-color: var(--ok-border); color: var(--ok); }
.flash.error   { background: var(--danger-bg); border-color: var(--danger-border); color: var(--danger); }
.flash.info    { background: var(--info-bg); border-color: var(--info-border); color: var(--info); }
.flash.is-hiding { opacity: 0; transform: translateY(-4px); }
.flash-close {
  flex: 0 0 auto; border: 0; background: none; padding: 0 0 0 .4rem; margin: -.1rem 0 0;
  font-size: .95rem; line-height: 1; color: inherit; opacity: .6; cursor: pointer;
}
.flash-close:hover { opacity: 1; }

/* ─── Login ─── */
.auth-wrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 1.5rem; background: linear-gradient(180deg, var(--surface-2), var(--bg)); }
.auth-box { width: 100%; max-width: 380px; margin-inline: auto; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); padding: 2rem 1.8rem; }
.auth-box .brand { font-family: var(--serif); font-size: 1.8rem; letter-spacing: .08em; color: var(--terracotta); text-align: center; }
.auth-box .sub { text-align: center; color: var(--muted); font-size: .85rem; margin-bottom: 1.5rem; }

/* ─── Tablas base + tema Grid.js ─── */
table.data { width: 100%; border-collapse: collapse; font-size: .9rem; }
table.data th, table.data td { text-align: left; padding: .55rem .7rem; border-bottom: 1px solid var(--border); }
table.data th { font-size: .72rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
table.data tr:hover td { background: var(--surface-2); }

.gridjs-wrapper { border-color: var(--border) !important; box-shadow: var(--shadow) !important; border-radius: var(--radius) !important; }

/* Fila de filtros por columna: reinsertada por app.js (ver enhanceTables) como
   segunda fila de `.gridjs-thead`, alineada automáticamente con las columnas.
   Sin JS queda dentro de la tabla normal (inputs visibles pero sin efecto) —
   degradación aceptable. */
.filter-row th { padding: .3rem .7rem .55rem; background: var(--surface-2) !important; border: 1px solid var(--border); border-top: none; text-transform: none; font-weight: normal; vertical-align: top; }
.filter-row .filter-input { width: 100%; font-size: .82rem; padding: .3rem .5rem; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); color: var(--ink); }
/* Cabecera de Grid.js: buscador (float:left de Grid.js) a la izquierda,
   controles propios (Restablecer filtros + Mostrar N, ver app.js) agrupados
   y centrados verticalmente a la derecha — flex en vez del float suelto de
   antes, que dejaba el buscador (más alto, por el padding del input) y los
   controles (texto/select, más bajos) desalineados entre sí. */
.gridjs-head { display: flex; align-items: center; flex-wrap: wrap; gap: .5rem .75rem; }
.gridjs-head:after { content: none; }
.gridjs-search { float: none; }
.gridjs-head-controls { display: flex; align-items: center; flex-wrap: wrap; gap: .6rem; margin-left: auto; }
.gridjs-head-controls .filter-reset { float: none; }
.page-size-wrap { display: inline-flex; align-items: center; gap: .35rem; }
.page-size-select { padding: .25rem .4rem; width: auto; }
/* Selector «Columnas» (app.js enhanceTables, tablas con $tableId). */
.col-chooser { position: relative; }
.col-chooser > summary { list-style: none; cursor: pointer; }
.col-chooser > summary::-webkit-details-marker { display: none; }
.col-chooser-panel { position: absolute; right: 0; top: calc(100% + .25rem); z-index: 40; min-width: 12rem; display: flex; flex-direction: column; gap: .15rem; padding: .4rem; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow); }
.col-chooser-item { display: flex; align-items: center; gap: .5rem; padding: .3rem .4rem; border-radius: var(--radius-sm); cursor: pointer; white-space: nowrap; font-size: .9rem; }
.col-chooser-item:hover { background: var(--surface-2); }
.col-chooser-item input { margin: 0; }

/* Barra de acciones en lote (/miembros, ver partials/table.php $select).
   Pegada arriba de la tarjeta de la tabla; en móvil los botones envuelven. */
.bulk-bar {
  display: flex; flex-wrap: wrap; align-items: center; gap: .6rem .9rem;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius);
  padding: .6rem .9rem; margin-bottom: .8rem;
}
.bulk-bar-count { font-size: .88rem; }
.bulk-bar-actions { display: flex; flex-wrap: wrap; gap: .4rem; }
.bulk-bar [data-bulk-clear] { margin-left: auto; }
@media (max-width: 620px) {
  .bulk-bar { flex-direction: column; align-items: stretch; }
  .bulk-bar-count { order: -1; }
  .bulk-bar [data-bulk-clear] { margin-left: 0; }
}
.gridjs-table { font-family: var(--sans) !important; }
.gridjs-th { background: var(--surface-2) !important; color: var(--muted) !important; border-color: var(--border) !important; font-size: .72rem !important; text-transform: uppercase; letter-spacing: .05em; }
.gridjs-td { border-color: var(--border) !important; color: var(--ink) !important; }
.gridjs-tr:hover .gridjs-td { background: var(--surface-2) !important; }
input.gridjs-input, .gridjs-search-input { border: 1px solid var(--border-2) !important; border-radius: var(--radius-sm) !important; }

/* Modo oscuro de Grid.js: gridjs.mermaid.css se carga después de este archivo y
   trae colores fijos (blanco, grises), así que todo va con !important y con los
   tokens; en claro los valores coinciden con los de siempre. */
.gridjs-container { color: var(--ink) !important; }
.gridjs-tbody, td.gridjs-td { background-color: var(--surface) !important; }
.gridjs-footer { background-color: var(--surface) !important; border-color: var(--border) !important; }
.gridjs-pagination { color: var(--muted) !important; }
.gridjs-pagination .gridjs-pages button { background-color: var(--surface) !important; border-color: var(--border-2) !important; color: var(--ink); }
.gridjs-pagination .gridjs-pages button:hover { background-color: var(--surface-2) !important; color: var(--ink) !important; }
.gridjs-pagination .gridjs-pages button:disabled,
.gridjs-pagination .gridjs-pages button:hover:disabled,
.gridjs-pagination .gridjs-pages button[disabled],
.gridjs-pagination .gridjs-pages button.gridjs-spread { background-color: var(--surface) !important; color: var(--muted) !important; }
input.gridjs-input { background-color: var(--surface) !important; color: var(--ink); }
input.gridjs-input:focus { border-color: var(--terracotta) !important; box-shadow: 0 0 0 3px var(--focus-ring) !important; }
th.gridjs-th-sort:hover, th.gridjs-th-sort:focus { background-color: var(--border) !important; }
button.gridjs-sort { filter: var(--icon-filter); }
.gridjs-tr.gridjs-tr-selected .gridjs-td { background-color: var(--info-bg) !important; }
.gridjs-loading-bar { background-color: var(--surface) !important; }
/* La página actual, la última de las reglas de los botones: gana los empates. */
.gridjs-pagination .gridjs-pages button.gridjs-currentPage { background-color: var(--terracotta) !important; color: var(--on-accent) !important; }

.muted { color: var(--muted); }
.small { font-size: .8rem; }
.right { text-align: right; }
.nowrap { white-space: nowrap; }

/* ─── Índice del libro ─── */
.chapter-list { list-style: none; margin: 0; padding: 0; }
.chapter-list li { border-bottom: 1px solid var(--border); }
.chapter-list li:last-child { border-bottom: 0; }
.chapter-list a { display: block; padding: .55rem .2rem; color: var(--ink); }
.chapter-list a:hover { color: var(--terracotta); text-decoration: none; }

/* ─── Lector ─── */
/* Barra fija del lector: progreso + índice/buscador + editar. El fondo y el
   margen negativo la hacen cubrir de lado a lado el ancho de .content mientras
   el capítulo pasa por debajo. */
.reader-sticky {
  position: sticky; top: 0; z-index: 20;
  margin: -1.6rem -1.6rem 1rem; padding: .7rem 1.6rem .6rem;
  background: var(--bg); border-bottom: 1px solid var(--border);
}
.reader-progress { height: 4px; background: var(--border); border-radius: 2px; margin-bottom: .6rem; overflow: hidden; }
.reader-progress-bar { height: 100%; background: var(--terracotta); width: 0; transition: width .15s ease-out; }
.reader-head { display: flex; align-items: center; gap: .6rem; }
/* El buscador ocupa todo el espacio libre: centrado y flotando entre los dos
   botones parecía suelto, y es lo que más se usa de la barra. */
.reader-head .book-search { flex: 1 1 auto; min-width: 0; }
.reader-head .btn { flex: 0 0 auto; }
@media (max-width: 620px) {
  /* La barra va justa en móvil: «Modo lectura» vuelve a icono solo. */
  .btn-focus-label { display: none; }
  [data-focus-toggle] { padding-inline: .45rem; justify-content: center; }
}
.reader-lang { margin-top: 1rem; text-align: right; }
.reader-cols { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 1.6rem; align-items: start; }
/* Columna de notas fija a la vista mientras se lee. Con `max-height` + scroll
   propio: si las notas crecen más que la pantalla, se desplazan dentro de la
   columna en vez de arrastrar el `sticky` fuera de la vista. */
.reader-notes {
  /* top ≈ alto de .reader-sticky (72px) + aire: si no, la primera tarjeta se
     mete debajo de la barra fija al bajar por el capítulo. */
  position: sticky; top: 5.5rem; align-self: start;
  display: flex; flex-direction: column;
  max-height: calc(100vh - 6.5rem); overflow-y: auto; overscroll-behavior: contain;
  padding-right: .25rem;
}
.reader-notes .card { margin-bottom: 1rem; }
.reader-notes .card:last-child { margin-bottom: 0; }
.reader-nav { display: flex; justify-content: space-between; gap: 1rem; margin-top: 1.6rem; padding-top: 1.2rem; border-top: 1px solid var(--border); }
.reader-danger { margin-top: 1.6rem; text-align: right; }
/* «Mi bitácora»: la acción constructiva, antes que la destructiva de arriba.
   Dentro del capítulo (directiva «::: bitacora») queda en el flujo del texto;
   al pie (fallback en read.php) se separa como .reader-danger/.reader-lang. */
.reader-bitacora { margin-top: 1.6rem; text-align: center; }
/* «¿Terminó este capítulo?» al pie del lector (read.php). */
.reader-complete { margin-top: 1.6rem; }
.reader-complete h3 { margin-top: 0; }
.reader-complete-nudge { color: var(--warn); }
.prose .reader-bitacora { margin: 2rem 0; }
/* El capítulo sólo recibe el foco por programa (repliegue al cerrar un modal),
   nunca tabulando: el recuadro del navegador alrededor de todo el texto sería
   ruido sin aportar orientación. */
.reader-article[tabindex="-1"]:focus { outline: none; }

/* ─── Lector: modo lectura ─── */
/* Sólo el texto: book.js pone html.reading-focus (y data-reader-size para el
   tamaño de letra). Todo va prefijado con html.reading-focus para ganar por
   especificidad a la media query de 1200px que viene más abajo. Se conservan
   el padding de .content y los márgenes negativos de .reader-sticky (se
   compensan entre sí) y el `overflow-x: clip` (con `hidden` dejaría de pegar). */
.reader-focusbar { display: none; }
html.reading-focus .sidebar,
html.reading-focus .mobile-topbar,
html.reading-focus .nav-backdrop,
html.reading-focus footer.site,
html.reading-focus .vineta,
html.reading-focus .reader-notes,
html.reading-focus .reader-lang,
html.reading-focus .reader-danger,
html.reading-focus .reader-head { display: none; }
/* .main es `flex: 0 1 auto` y sin la barra lateral se encogería al ancho del
   texto: la columna quedaría pegada a la izquierda en vez de centrada. */
html.reading-focus .main { margin-left: 0; flex: 1 1 auto; }
/* Sin el tope de 1100px la barra fija cubre todo el ancho y la columna de
   texto queda centrada en la pantalla, no desplazada a la izquierda. */
html.reading-focus .content { max-width: none; }
html.reading-focus .reader-cols { grid-template-columns: minmax(0, 1fr); }
html.reading-focus .reader-article,
html.reading-focus .reader-complete,
html.reading-focus .reader-nav,
html.reading-focus .reader-bitacora { max-width: var(--focus-measure, 49rem); margin-inline: auto; }
html.reading-focus .reader-sticky { top: 0; }
html.reading-focus .reader-focusbar { display: flex; align-items: center; gap: .5rem; }
.reader-focusbar-gap { flex: 1 1 auto; }
/* .btn declara su propio display y pisaría el [hidden] del navegador. */
.reader-focusbar [hidden] { display: none; }
.reader-focusbar .btn { flex: 0 0 auto; justify-content: center; }
.reader-focusbar .btn:disabled { opacity: .45; cursor: default; }
/* Botones de sólo icono (modo lectura, pantalla completa): cuadrados. */
.btn-icon { padding-inline: .45rem; justify-content: center; }
.btn-icon svg { display: block; }
.btn-icon .fs-exit, html.reading-fullscreen .btn-icon .fs-enter { display: none; }
html.reading-fullscreen .btn-icon .fs-exit { display: block; }
html.reading-focus .prose { line-height: 1.8; }
/* Ancho de línea ≈ 68ch del texto en cada tamaño, pero en rem: así el pie
   («¿Terminó…?», capítulo anterior/siguiente), con letra de interfaz, se
   alinea con la columna del texto en vez de quedar más estrecho. */
html.reading-focus[data-reader-size="0"] { --focus-measure: 44rem; }
html.reading-focus[data-reader-size="1"] { --focus-measure: 49rem; }
html.reading-focus[data-reader-size="2"] { --focus-measure: 55rem; }
html.reading-focus[data-reader-size="3"] { --focus-measure: 62rem; }
html.reading-focus[data-reader-size="0"] .prose { font-size: 1.06rem; }
html.reading-focus[data-reader-size="1"] .prose { font-size: 1.18rem; }
html.reading-focus[data-reader-size="2"] .prose { font-size: 1.32rem; }
html.reading-focus[data-reader-size="3"] .prose { font-size: 1.48rem; }
/* Algunos navegadores pintan de negro el fondo en pantalla completa. */
html.reading-fullscreen { background: var(--bg); }
@media (max-width: 620px) {
  .reader-focusbar .btn { min-width: 40px; min-height: 40px; }
}

/* Tipografía de lectura */
.prose { font-family: var(--serif); font-size: 1.06rem; line-height: 1.75; color: var(--ink); max-width: 68ch; }
.prose h1 { font-size: 1.9rem; margin: 0 0 1.2rem; }
.prose h2 { font-size: 1.4rem; margin: 2rem 0 .8rem; }
.prose h3 { font-size: 1.15rem; margin: 1.6rem 0 .6rem; }
.prose p { margin: 0 0 1.1rem; }
.prose img { max-width: 100%; height: auto; display: block; margin: 1rem auto; }
/* Diagramas y láminas del cuaderno: tinta oscura sobre fondo transparente; en
   modo oscuro se apoyan en una superficie clara (ver --figure-bg). */
.prose img[src*="/diagrams/"], .prose img[src*="/images/"] { background: var(--figure-bg); padding: var(--figure-pad); border-radius: var(--radius-sm); }
.prose ul, .prose ol { margin: 0 0 1.1rem; padding-left: 1.4rem; }
.prose li { margin-bottom: .35rem; }
.prose ul li::marker { color: var(--terracotta); }
.prose blockquote { margin: 1.2rem 0; padding: .4rem 0 .4rem 1.1rem; border-left: 3px solid var(--terracotta-t); color: var(--muted); font-style: italic; }
.prose em { font-style: italic; color: var(--terracotta); }
.prose hr { border: 0; border-top: 1px solid var(--border-2); margin: 1.8rem 0; }
.prose code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .9em; background: var(--surface-2); padding: .1em .35em; border-radius: 4px; }
.prose a { color: var(--terracotta); text-decoration: underline; }

/* Estrofa del cuaderno impreso («::: verso» en el Markdown): cursiva terracota
   conservando los saltos de línea. `verso-centrado` para las oraciones. */
.prose .verso { font-style: italic; color: var(--terracotta); line-height: 1.9; margin: 1.4rem 0; }
.prose .verso-centrado { text-align: center; }

/* Figuras del ejercicio de equilibrio (cap. 6): pequeñas y a la derecha del
   texto de los pasos, como en la página impresa. Bajo 640 px vuelven al flujo. */
.prose img[src*="figura-equilibrio"] {
  float: right; clear: right; width: 150px; margin: .2rem 0 1rem 1.6rem;
}
/* La figura en equilibrio (la del acto de equilibrio) va centrada y contenida:
   a todo el ancho de la columna el trazo se vuelve enorme y pierde la finura. */
.prose img[src*="figura-en-equilibrio"] { width: 230px; margin: 1.4rem auto 1.6rem; }

/* Diagramas del tercer cuaderno (cap. 9 y 10): a todo el ancho de la columna
   el trazo fino se agranda y se pierde; se contienen como en la página impresa. */
.prose img[src*="kap09-esquema-conflicto"] { max-width: 560px; margin: 1.6rem auto; }
.prose img[src*="kap09-relacion-con-otras"] { max-width: 460px; margin: 1.6rem auto; }
.prose img[src*="kap10-escuchar-tres-niveles"] { max-width: 480px; margin: 1.6rem auto; }
.prose img[src*="kap10-cuatro-ambitos"] { max-width: 440px; margin: 1.6rem auto; }
.prose img[src*="circulo-vacio"] { max-width: 330px; margin: 1.4rem auto; }
.prose img[src*="circulo-ejemplo"] { max-width: 300px; margin: 1.4rem auto; }

.md-table { overflow-x: auto; margin: 1.2rem 0; }
.md-table table { width: 100%; border-collapse: collapse; font-family: var(--sans); font-size: .92rem; }
.md-table th, .md-table td { border: 1px solid var(--border); padding: .5rem .65rem; text-align: left; vertical-align: top; }
.md-table th { background: var(--surface-2); }

/* Espacios rellenables del libro */
.fill-slot {
  font-family: var(--serif);
  font-size: 1rem;
  color: var(--ink);
  background: var(--surface-2);
  border: none;
  border-bottom: 2px solid var(--terracotta-t);
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  padding: .05em .3em;
  outline: none;
  transition: background .15s, border-color .15s, box-shadow .15s;
}
/* background-color (no el atajo «background») para no borrar los renglones
   de los campos de varias líneas al pasar el cursor o enfocar. */
.fill-slot:hover { background-color: var(--slot-hover); }
.fill-slot:focus { background-color: var(--surface); border-color: var(--terracotta); box-shadow: 0 0 0 3px var(--focus-ring); }

.fill-slot-word {
  display: inline-block;
  margin: 0 .15em;
  text-align: center;
  vertical-align: baseline;
}

.fill-slot-line,
.fill-slot-page {
  display: block;
  width: 100%;
  margin: .5rem 0;
  resize: none;
  overflow: hidden;
  border-radius: var(--radius-sm);
  border: 1px dashed var(--border-2);
  border-bottom: 1px dashed var(--border-2);
  /* Anula el `min-height: 4 renglones` genérico de más arriba: estos campos
     ya fijan su alto por el atributo `rows` (1 para fill-slot-line, 2-14
     para fill-slot-page) más el auto-resize en book.js. */
  min-height: 0;
}
.fill-slot-line:focus,
.fill-slot-page:focus { border: 1px solid var(--terracotta); border-style: solid; }

.fill-slot-page { background-color: var(--surface-2); }

/* El alto de un campo de varias líneas lo fija este `min-height`, no el
   atributo `rows`: autosize() en book.js iguala la altura al scrollHeight nada
   más cargar el capítulo, así que un textarea vacío colapsaría a un renglón.
   `min-height` gana sobre el `height` en línea, y el campo sigue creciendo al
   escribir porque autosize sólo puede superarlo. */
.fill-slot-page { min-height: calc(var(--rows, 3) * var(--rule-h) + 2 * var(--rule-pad)); }

/* Viñeta decorativa: figura de una línea sobre el horizonte, como las aperturas
   de capítulo del cuaderno. layout.php la pone al pie de todas las páginas, así
   que necesita aire por arriba para separarse del contenido. */
.vineta { display: block; width: 100%; max-width: 640px; height: auto; margin: 5rem auto 1.5rem; }

/* ─── Renglones de cuaderno en los campos de varias líneas ───
   Cada raya cae al final de una línea de texto: el paso del degradado es
   exactamente el line-height (--rule-h) y el desfase vertical coincide con el
   padding superior. «background-attachment: local» hace que las rayas
   acompañen el desplazamiento del texto dentro del campo. */
:root { --rule-h: 1.75rem; --rule-pad: .5rem; }

.field textarea,
#note-modal textarea,
#bit-modal textarea,
.fill-slot-line,
.fill-slot-page {
  line-height: var(--rule-h);
  padding: var(--rule-pad) .7rem;
  background-image: repeating-linear-gradient(to bottom,
    transparent 0,
    transparent calc(var(--rule-h) - 1px),
    var(--border-2) calc(var(--rule-h) - 1px),
    var(--border-2) var(--rule-h));
  background-position: 0 var(--rule-pad);
  background-attachment: local;
}

/* Los campos que editan markdown crudo quedan lisos: las rayas competirían con
   la sintaxis (editor de capítulo y modal de fragmento). */
textarea.editor-textarea,
#frag-modal textarea { background-image: none; }

/* Editor de capítulos (textarea sobre markdown crudo): tamaño y line-height
   explícitos, más cómodos de leer que el monospace por defecto del navegador. */
.editor-textarea {
  width: 100%;
  height: 65vh;
  font-family: 'SFMono-Regular', Consolas, Menlo, monospace;
  font-size: .92rem;
  line-height: 1.6;
  padding: .8rem;
}

/* Insignia flotante "Guardado" para el autoguardado de respuestas */
.fill-status {
  position: fixed;
  bottom: 1.2rem;
  right: 1.2rem;
  z-index: 40;
  background: var(--inverse-bg);
  color: var(--on-accent);
  font-family: var(--sans);
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .02em;
  padding: .45rem .9rem;
  border-radius: 999px;
  box-shadow: var(--shadow);
  opacity: 0;
  transform: translateY(6px);
  pointer-events: none;
  transition: opacity .25s, transform .25s;
}
.fill-status.show { opacity: 1; transform: translateY(0); }
.fill-status::before { content: "✓ "; }

/* Notas y feedback */
.field label.radio { display: block; font-weight: 400; text-transform: none; color: var(--ink); margin-bottom: .3rem; }
.field label.radio input { width: auto; margin-right: .4rem; }
.note-quote { margin: 0 0 .6rem; padding: .35rem .7rem; border-left: 3px solid var(--terracotta-t); background: var(--surface-2); color: var(--muted); font-style: italic; font-size: .85rem; border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
.note-quote-link { display: inline-block; margin-bottom: .5rem; font-size: .82rem; }
.note-item .note-quote { margin: 0 0 .35rem; }
.note-quote-stale { display: block; margin-bottom: .5rem; font-style: italic; }
.note-item { border-bottom: 1px solid var(--border); padding: .7rem 0; }
.note-item:last-child { border-bottom: 0; }
.note-body { font-size: .9rem; margin-bottom: .35rem; }
.note-meta { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.note-meta a { white-space: nowrap; }

/* «Mi bitácora»: editar en línea + botón de borrar bajo cada anotación. */
.bitacora-edit { margin: .45rem 0 .3rem; }
.bitacora-edit > summary { cursor: pointer; display: inline-block; color: var(--terracotta); }
.bitacora-edit textarea { width: 100%; min-height: 60px; }
.note-item form[data-confirm] { margin-top: .2rem; }

/* Citas resaltadas inline en el texto del libro (notas privadas / feedback público) */
.prose mark[data-note-id] { background: var(--mark-note); color: inherit; border-bottom: 2px solid var(--mark-note-border); border-radius: 2px; padding: 0 2px; cursor: pointer; transition: background .15s; }
.prose mark[data-note-id]:hover { background: var(--mark-note-h); }
.prose mark[data-note-id][data-visibility="public"] { background: var(--mark-public); border-bottom-color: var(--terracotta); }
.prose mark[data-note-id][data-visibility="public"]:hover { background: var(--mark-public-h); }
.prose mark.highlight-active { outline: 2px solid var(--terracotta); }

/* Anotaciones importadas de libro.somosastra.org (de sólo lectura, sin data-note-id) */
.prose mark[data-id] { background: var(--mark-import); color: inherit; border-bottom: 2px solid var(--mark-import-border); border-radius: 2px; padding: 0 2px; cursor: pointer; transition: background .15s; }
.prose mark[data-id]:hover { background: var(--mark-import-h); }

.mark-popup { position: fixed; z-index: 40; max-width: 300px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow); padding: .7rem .8rem; }
.mark-popup-meta { margin-bottom: .35rem; }
.mark-popup-body { font-size: .9rem; margin-bottom: .5rem; white-space: pre-wrap; }
.mark-popup-replies:empty { display: none; }
.mark-popup-replies .panel-soft.reply { margin: 0 0 .5rem; white-space: pre-wrap; }
.mark-popup-reply { margin-bottom: .5rem; }

/* Barra flotante ("✏️ Editar" / "💬 Comentar") junto a una selección de texto.
   display:flex sólo con :not([hidden]) — mismo motivo que los modales de abajo:
   si no, pisaría el display:none del atributo [hidden] y la barra ya no se
   podría ocultar una vez mostrada por primera vez. */
#sel-popup {
  position: fixed;
  z-index: 45;
  gap: 2px;
  background: var(--inverse-bg);
  border-radius: 999px;
  padding: 3px;
  box-shadow: var(--shadow);
  white-space: nowrap;
}
#sel-popup:not([hidden]) { display: flex; }
#sel-popup button {
  background: transparent;
  color: var(--on-accent);
  border: 0;
  border-radius: 999px;
  padding: .5rem 1rem;
  font-family: var(--sans);
  font-size: .82rem;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
#sel-popup button:hover { background: var(--terracotta); color: var(--on-accent); }

/* Modales pequeños (nota nueva / editar texto) sobre la selección del capítulo.
   display:flex sólo con :not([hidden]) — si no, pisaría el display:none que
   pone el atributo [hidden] por defecto y el modal quedaría visible siempre. */
#note-modal-overlay, #frag-modal-overlay, #bit-modal-overlay, #reply-modal-overlay {
  position: fixed; inset: 0; z-index: 50;
  background: var(--overlay);
  padding: 1rem;
}
#note-modal-overlay:not([hidden]), #frag-modal-overlay:not([hidden]), #bit-modal-overlay:not([hidden]), #reply-modal-overlay:not([hidden]) { display: flex; align-items: center; justify-content: center; }
#note-modal, #frag-modal, #bit-modal, #reply-modal {
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 1.4rem;
  width: 420px;
  max-width: 100%;
}
/* La bitácora muestra una lista de candidatos con casilla + texto: 420 px se
   queda estrecho. Y puede crecer más que la pantalla: scroll propio. */
#bit-modal { width: 560px; max-height: calc(100vh - 3rem); overflow-y: auto; }
#note-modal h3, #frag-modal h3, #bit-modal h3, #reply-modal h3 { margin: 0 0 .6rem; }
#note-modal textarea, #frag-modal textarea, #reply-modal textarea { min-height: 100px; }
#bit-modal-own { min-height: 60px; }

/* Un candidato: casilla + rótulo (encabezado más cercano) + texto editable. */
.bit-cand { border-top: 1px solid var(--border); padding: .7rem 0; }
.bit-cand:first-child { border-top: 0; }
.bit-cand-head { display: flex; align-items: baseline; gap: .5rem; }
.bit-cand-head input { flex: 0 0 auto; }
.bit-cand-ctx { display: block; margin: 0 0 .1rem; }
.bit-cand textarea { width: 100%; margin-top: .35rem; min-height: 40px; resize: vertical; }
.bit-cand .badge { margin-left: .4rem; }
#bit-modal-list:empty { display: none; }

@media (max-width: 620px) {
  /* Ya no cabe una columna de figuras junto al texto: vuelven al flujo. */
  .prose img[src*="figura-equilibrio"] { float: none; width: 130px; margin: 1rem auto; }
  #note-modal-overlay, #frag-modal-overlay, #bit-modal-overlay, #reply-modal-overlay { align-items: flex-end; padding: 0; }
  #note-modal, #frag-modal, #bit-modal, #reply-modal { width: 100%; border-radius: var(--radius) var(--radius) 0 0; }
  #bit-modal { max-height: 92vh; }
  #note-modal textarea, #frag-modal textarea, #reply-modal textarea,
  #bit-modal textarea { font-size: 16px; } /* evita el zoom automático de iOS al enfocar */
  #sel-popup button { padding: .65rem 1.15rem; font-size: .88rem; }
}

/* ─── Barra superior móvil + menú hamburguesa ─── */
.mobile-topbar { display: none; }
.nav-backdrop { display: none; }

/* ─── Responsive ─── */
/* Umbral 1200px (no 820): cubre todo el rango de iPad en las dos orientaciones
   (834 y 1024 en vertical, 1133–1180 en horizontal). Por encima de 820 las dos
   columnas laterales — la navegación (250px) y las notas (320px) — dejaban al
   capítulo menos de 400px de ancho, ilegible para leer un libro. A partir de
   1201px (portátiles, iPad Pro 13" en horizontal) no cambia nada. */
@media (max-width: 1200px) {
  .mobile-topbar {
    display: flex; align-items: center; gap: .8rem; position: sticky; top: 0; z-index: 40;
    background: var(--sidebar-bg); color: #fff; padding: .7rem 1rem;
  }
  /* Anclas (p. ej. /perfil#correos desde los correos): que no queden bajo la barra fija. */
  .card[id] { scroll-margin-top: 4.5rem; }
  .mobile-topbar-brand { font-family: var(--serif); font-size: 1.15rem; letter-spacing: .08em; color: #FCEFE7; }
  .hamburger-btn {
    display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 4px;
    width: 40px; height: 40px; padding: 0; border: 0; border-radius: var(--radius-sm);
    background: transparent; cursor: pointer; flex-shrink: 0;
  }
  .hamburger-btn:hover { background: rgba(255,255,255,.08); }
  .hamburger-btn span { display: block; width: 20px; height: 2px; background: #fff; border-radius: 2px; }

  .main { margin-left: 0; }
  .app { position: relative; }
  .sidebar {
    z-index: 50; width: 82%; max-width: 300px;
    flex-direction: column; overflow-x: hidden; overflow-y: auto; padding: 1.1rem 0;
    transform: translateX(-100%); transition: transform .22s ease; box-shadow: var(--shadow);
  }
  .sidebar.open { transform: translateX(0); }
  .sidebar .brand, .sidebar .navgroup, .sidebar .userbar { display: block; }
  .sidebar nav { flex-direction: column; }

  .nav-backdrop {
    position: fixed; inset: 0; background: var(--overlay-nav); z-index: 45;
  }
  .nav-backdrop.open { display: block; }
  body.nav-open { overflow: hidden; }

  .content { padding: 1rem; }
  /* La barra fija del lector cuelga bajo la barra superior móvil (~56px). */
  .reader-sticky { top: 56px; margin: -1rem -1rem 1rem; padding: .6rem 1rem .5rem; }
  /* En modo lectura la barra superior móvil se oculta: la del lector sube a 0. */
  html.reading-focus .reader-sticky { top: 0; }
  .reader-cols { grid-template-columns: minmax(0, 1fr); }
  .reader-notes { position: static; max-height: none; overflow: visible; padding-right: 0; }
}

/* ── Lista de contactos (Mi grupo) ───────────────────────────────────────── */
.contact-list { list-style: none; padding: 0; margin: .4rem 0 0; }
.contact-list .contact {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .1rem .6rem;
  padding: .5rem 0; border-bottom: 1px solid var(--border);
}
.contact-list .contact:last-child { border-bottom: 0; }
.contact-name { font-weight: 600; }
.contact-links { flex: 1 1 100%; }
@media (min-width: 640px) { .contact-links { flex: 1 1 auto; } }
.contact-avatar { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; }

/* ── Estado de la conexión ───────────────────────────────────────────────── */
/* Aviso fijo cuando la red se cae o va muy lenta (metro, túneles, datos al
   límite). Lo crea app.js: la CSP no permite <script> en línea en las vistas. */
.net-banner {
  position: fixed; left: 50%; bottom: 1rem; transform: translate(-50%, 8px);
  z-index: 60; max-width: min(92vw, 30rem);
  font-family: var(--sans); font-size: .82rem; font-weight: 600; text-align: center;
  padding: .55rem 1rem; border-radius: 999px; border: 1px solid;
  box-shadow: var(--shadow);
  opacity: 0; pointer-events: none; transition: opacity .2s, transform .2s;
}
.net-banner.show { opacity: 1; transform: translate(-50%, 0); }
.net-banner.is-warn { background: var(--warn-bg); border-color: var(--warn-border); color: var(--warn); }
.net-banner.is-off  { background: var(--danger-bg); border-color: var(--danger-border); color: var(--danger); }

/* Sesión cerrada (app.js, 419): fijo y con enlace, a diferencia del aviso de red. */
.session-banner {
  position: fixed; left: 50%; bottom: 4rem; transform: translateX(-50%);
  z-index: 61; width: max-content; max-width: min(92vw, 32rem);
  font-family: var(--sans); font-size: .85rem; line-height: 1.4; text-align: center;
  padding: .7rem 1rem; border-radius: 12px; border: 1px solid var(--warn-border);
  background: var(--warn-bg); color: var(--warn); box-shadow: var(--shadow);
  display: none;
}
.session-banner.show { display: block; }
.session-banner a { font-weight: 700; color: inherit; text-decoration: underline; white-space: nowrap; }

/* Autoguardado del libro: pendiente de llegar al servidor. */
.fill-status.is-pending { background: var(--warn); color: var(--on-accent); }
.fill-status.is-pending::before { content: "⟳ "; }

/* Botón enviando: evita el segundo toque cuando la respuesta tarda. */
.btn.is-busy, .btn:disabled, button:disabled { opacity: .6; cursor: progress; }

/* ── Página de confirmación de acciones destructivas ─────────────────────── */
.confirm-card { max-width: 34rem; border-top: 3px solid var(--danger); }
.confirm-title { font-size: 1.35rem; margin: 0 0 .6rem; }
.confirm-lead { margin: 0 0 1rem; }
.confirm-consequences {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: .7rem .9rem .7rem 1rem; margin-bottom: 1.2rem;
}
.confirm-consequences p { margin: 0 0 .3rem; }
.confirm-consequences ul { margin: 0; padding-left: 1.1rem; color: var(--muted); }
.confirm-consequences li { margin-bottom: .2rem; }
.confirm-consequences ul li::marker { color: var(--terracotta); }
.confirm-form label { display: block; font-size: .85rem; margin-bottom: .35rem; }
.confirm-form input[type="text"] {
  width: 100%; max-width: 16rem; font-family: var(--sans); font-size: .95rem;
  letter-spacing: .06em; padding: .55rem .7rem;
  border: 1px solid var(--border-2); border-radius: var(--radius-sm); background: var(--surface);
}
.confirm-form input[type="text"]:focus { outline: none; border-color: var(--danger); box-shadow: 0 0 0 3px var(--danger-bg); }
.confirm-check { display: flex; gap: .5rem; align-items: flex-start; margin-bottom: 1rem; }
.confirm-check input { margin-top: .2rem; }
.confirm-actions { display: flex; gap: .6rem; flex-wrap: wrap; align-items: center; margin-top: 1rem; }

/* ─── Utilidades (S2): sustituyen estilos en línea repetidos ─── */
.inline-form { display: inline; }
.card-narrow { max-width: 620px; }
.card-form { max-width: 640px; }
.card-medium { max-width: 680px; }
.card-wide { max-width: 720px; }
.card-auth { max-width: 520px; margin: 2rem auto; }
.auth-box.auth-wide { max-width: 560px; }
.auth-inner { width: 100%; max-width: 420px; }
.auth-inner:has(.auth-wide) { max-width: 560px; }

.row, .field label.row { display: flex; align-items: center; gap: .4rem; }
.row-between, .field label.row-between { display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap; }
.row-between.no-wrap { flex-wrap: nowrap; }
.gap-half { gap: .5rem; }
.gap-sm { gap: .6rem; }
.gap-1 { gap: 1rem; }
.summary-row { cursor: pointer; padding: .4rem 0; }
.self-center { align-self: center; }
.grow-search { flex: 1; min-width: 200px; }
.field-end { display: flex; align-items: flex-end; }
.btn-row.end { justify-content: flex-end; }
.btn-block { width: 100%; justify-content: center; }

label.check-row, .field label.check-row { display: flex; align-items: flex-start; gap: .6rem; padding: .35rem .2rem; cursor: pointer; font-weight: normal; }
label.check-row.is-centered, .field label.check-row.is-centered { align-items: center; padding: .45rem .2rem; }
input.check, .field input.check { width: auto; }
input.check.check-top, .field input.check.check-top { margin-top: .25rem; }

.avatar { border-radius: 50%; object-fit: cover; }
.avatar-28 { width: 28px; height: 28px; }
.avatar-32 { width: 32px; height: 32px; }
.avatar-36 { width: 36px; height: 36px; }
.avatar-64 { width: 64px; height: 64px; border: 1px solid var(--border); }
.avatar-48 { width: 48px; height: 48px; border: 1px solid var(--border); }

/* Tarjeta de contacto (partials/contact_*.php, app.js: bindContactCards).
   El anillo de foco lo pone la regla global de :focus-visible. */
.avatar-btn { display: inline-flex; padding: 0; margin: 0; border: 0; background: none; border-radius: 50%; cursor: pointer; line-height: 0; vertical-align: middle; }
.avatar-btn:hover .avatar, .avatar-btn[aria-expanded="true"] .avatar { box-shadow: 0 0 0 2px var(--border); }
.mentor-item .avatar-btn { margin-right: .35rem; }
.contact-popover { position: fixed; z-index: 60; max-width: min(320px, calc(100vw - 16px)); background: var(--surface); color: var(--ink); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); padding: .85rem 1rem; }
.contact-popover[hidden] { display: none; }
.contact-card-head { display: flex; align-items: center; gap: .75rem; margin-bottom: .6rem; }
.contact-card-name { display: block; margin-bottom: .2rem; overflow-wrap: anywhere; }
.contact-card-data { display: flex; flex-direction: column; gap: .15rem; margin: 0 0 .6rem; overflow-wrap: anywhere; }
.contact-card-actions { display: flex; flex-wrap: wrap; gap: .4rem; }
.contact-card-profile { margin: .6rem 0 0; }
@media (prefers-reduced-motion: no-preference) {
  .contact-popover:not([hidden]) { animation: contact-fade .12s ease-out; }
  @keyframes contact-fade { from { opacity: 0; transform: translateY(-2px); } to { opacity: 1; transform: none; } }
}
.avatar-inline { vertical-align: middle; margin-right: .5rem; }

.center { text-align: center; }
.bold, .row-between.is-current { font-weight: 600; }
.list-sm { font-size: .86rem; line-height: 1.6; }
.pad-row { padding: .55rem .2rem; }
.form-error, .muted.form-error { color: var(--danger); }

.panel-soft { background: var(--surface-2); border-radius: var(--radius-sm); padding: .6rem .8rem; }
.panel-soft.reply { margin: .6rem 0 0 1.2rem; padding: .5rem .7rem; }
.panel-outline { margin: .8rem 0; padding: .8rem; border: 1px solid var(--border); border-radius: 8px; }
.list-divided { border-bottom: 1px solid var(--border); padding: .7rem 0; }
.divider-top { margin-top: .8rem; padding-top: .6rem; border-top: 1px solid var(--border); }
.reader-progress.progress-mini { margin: .25rem 0 0; min-width: 6rem; }

/* márgenes: !important para ganar a reglas de contexto (.field label, .card h2, .hint) */
.m-0 { margin: 0 !important; }
.mt-0 { margin-top: 0 !important; }
.mt-xs { margin-top: .2rem !important; }
.mt-half { margin-top: .5rem !important; }
.mt-md { margin-top: .8rem !important; }
.mt-1 { margin-top: 1rem !important; }
.mt-pull { margin-top: -.4rem !important; }
.my-half { margin-top: .5rem !important; margin-bottom: .5rem !important; }
.mb-0 { margin-bottom: 0 !important; }
.mb-2xs { margin-bottom: .2rem !important; }
.mb-xs { margin-bottom: .3rem !important; }
.mb-sm { margin-bottom: .6rem !important; }
.mb-md { margin-bottom: .8rem !important; }
.mb-1 { margin-bottom: 1rem !important; }
.ml-indent { margin-left: 2.2rem !important; }

/* ── Tests de personalidad ──
   Tarjeta de ptest.js dentro del capítulo («::: test …»). Después de .prose a
   propósito: con igual especificidad, estas reglas ganan a .prose p/h3/ul.
   Color de cada grupo desde el JSON vía --c; posición de las marcas vía --at. */
.ptest { margin: 2rem 0; }
.ptest-card { max-width: 44rem; font-family: var(--sans); font-size: 1rem; line-height: 1.6; color: var(--ink); background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); padding: 1.25rem 1.4rem; scroll-margin-top: 7rem; }
.ptest-card p { margin: 0 0 .8rem; }
.ptest-card h3 { font-family: var(--serif); font-size: 1.25rem; margin: 0 0 .6rem; }
.ptest-card h3:focus, .ptest-fs legend:focus { outline: none; }
.ptest-lead { color: var(--muted); }
.ptest-sub { font-size: .82rem; color: var(--muted); }
.ptest-error { color: var(--danger); font-size: .88rem; margin: .6rem 0 0; }
.ptest-actions { margin-top: 1.2rem; }
.ptest-actions .btn, .ptest-nav .btn { min-height: 44px; }
.ptest-genero { background: var(--surface-2); border-radius: var(--radius-sm); padding: .8rem 1rem; margin: 0 0 1rem; }
.ptest-genero .ptest-genero-ask { font-weight: 600; margin-bottom: .5rem; }
.ptest-genero .btn-row { margin-bottom: .5rem; }
.ptest-genero .btn { min-height: 44px; }

/* Una pregunta a la vez: altura fija para que la página no salte. */
.ptest-kicker { font-size: .75rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); margin-bottom: .4rem !important; }
.ptest-progress { height: 6px; background: var(--surface-2); border-radius: 3px; overflow: hidden; }
.ptest-progress-bar { height: 100%; background: var(--terracotta); transition: width .2s; }
.ptest-count { font-size: .85rem; color: var(--muted); margin: .35rem 0 .8rem !important; }
.ptest-q { min-height: 27rem; }
.ptest-scale-legend, .ptest-bloque { font-size: .85rem; color: var(--muted); }
.ptest-bloque { font-weight: 600; text-transform: uppercase; letter-spacing: .04em; font-size: .75rem; }
.ptest-fs { border: 0; margin: 0; padding: 0; min-width: 0; }
.ptest-fs legend { font-family: var(--serif); font-size: 1.12rem; line-height: 1.45; padding: 0; margin: 0 0 .9rem; }
.ptest-opts { display: flex; flex-direction: column; gap: .4rem; }
.ptest-opt { display: flex; align-items: center; gap: .6rem; min-height: 44px; padding: .35rem .8rem; border: 1px solid var(--field-border); border-radius: var(--radius-sm); background: var(--surface); cursor: pointer; transition: background .12s, border-color .12s; }
.ptest-opt:hover { background: var(--slot-hover); }
.ptest-opt:has(input:checked) { border-color: var(--terracotta); background: var(--tint); }
.ptest-opt:has(input:focus-visible) { outline: 2px solid var(--terracotta); outline-offset: 2px; }
.ptest-opt input { accent-color: var(--terracotta); width: 1.1rem; height: 1.1rem; margin: 0; flex: none; }
.ptest-opt-num { font-size: .75rem; color: var(--muted); }
.ptest-nav { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; margin-top: 1rem; }
.ptest-status { margin-left: auto; font-size: .8rem; color: var(--muted); }
.ptest-keys { margin: .6rem 0 0 !important; }
@media (hover: none) { .ptest-keys { display: none; } }
@media (min-width: 880px) {
  .ptest-q { min-height: 15rem; }
  .ptest-opts { flex-direction: row; }
  .ptest-opt { flex: 1 1 0; min-width: 0; flex-direction: column; justify-content: center; text-align: center; gap: .3rem; padding: .6rem .4rem; }
}

/* Resultado (maqueta del handoff del test de impulsores, con tokens). */
.ptest-box { background: var(--surface-2); border-radius: var(--radius-sm); padding: 1em 1.25em; margin: 0 0 1.75em; }
.ptest-box p { margin: .3em 0 0; }
.ptest-box ul { margin: .4em 0 0; padding-left: 1.2em; }
.ptest-item { margin: 0 0 2em; padding: 0 0 1.5em; border-bottom: 1px solid var(--border); }
.ptest-item-title { font-family: var(--serif); font-size: 1.12rem; margin: 0 0 .15em; display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem; }
.ptest-badge { font-family: var(--sans); font-size: .72rem; font-weight: 600; padding: .05em .6em; border: 1px solid var(--c, var(--border-2)); border-radius: 999px; color: var(--ink); }
.ptest-points { margin: 0 0 .6em !important; }
.ptest-points strong { font-size: 1.5em; line-height: 1; }
.ptest-track { position: relative; height: 14px; background: var(--surface-2); border-radius: 7px; overflow: hidden; }
.ptest-fill { height: 100%; background: var(--c, var(--terracotta)); }
.ptest-mark { position: absolute; top: 0; bottom: 0; left: var(--at); width: 1px; background: var(--surface); z-index: 2; }
.ptest-scale { position: relative; height: 1.2em; font-size: .75em; color: var(--muted); margin-bottom: .9em; }
.ptest-scale span { position: absolute; top: 0; }
.ptest-scale span:first-child { left: 0; }
.ptest-scale span:last-child { right: 0; }
.ptest-scale .ptest-at { left: var(--at); transform: translateX(-50%); }
.ptest-detail { margin: 0; }
.ptest-detail dt { font-weight: 600; font-size: .8em; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); margin-top: .9em; }
.ptest-detail dd { margin: .15em 0 0; }
.ptest-table { width: 100%; border-collapse: collapse; margin: 0 0 1rem; font-size: .92rem; }
.ptest-table th, .ptest-table td { padding: .4rem .5rem; border-bottom: 1px solid var(--border); text-align: right; }
.ptest-table th:first-child { text-align: left; }
.ptest-table thead th { font-size: .78rem; color: var(--muted); font-weight: 600; }
.ptest-dot { display: inline-block; width: .7em; height: .7em; border-radius: 50%; background: var(--c); margin-right: .45em; }
.ptest-quelle { margin-top: 2.5em !important; padding-top: 1em; border-top: 1px solid var(--border); font-size: .85em; color: var(--muted); }

/* Imprimir sólo la tarjeta (ptest.js marca con .ptest-print-hide todo lo
   demás: hermanos de la tarjeta y de cada ancestro). Colores fijos de papel. */
@media print {
  body.ptest-printing .ptest-print-hide { display: none !important; }
  body.ptest-printing .ptest-print-path { display: block !important; position: static !important; margin: 0 !important; padding: 0 !important; width: auto !important; max-width: none !important; height: auto !important; overflow: visible !important; }
  body.ptest-printing [data-ptest-print] { max-width: none; margin: 0; padding: 0; border: 0; box-shadow: none; font-size: 11pt; color: #2A2622; background: #fff; }
  body.ptest-printing [data-ptest-print] .ptest-actions,
  body.ptest-printing [data-ptest-print] .ptest-error { display: none; }
  body.ptest-printing [data-ptest-print] * { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  body.ptest-printing [data-ptest-print] .ptest-box { background: #f5f5f3; border: 1px solid #ddd; }
  body.ptest-printing [data-ptest-print] .ptest-track { background: #eee; border: 1px solid #bbb; }
  body.ptest-printing [data-ptest-print] .ptest-mark { background: #fff; }
  body.ptest-printing [data-ptest-print] .ptest-lead,
  body.ptest-printing [data-ptest-print] .ptest-sub,
  body.ptest-printing [data-ptest-print] .ptest-scale,
  body.ptest-printing [data-ptest-print] .ptest-detail dt,
  body.ptest-printing [data-ptest-print] .ptest-quelle { color: #555; }
  body.ptest-printing [data-ptest-print] .ptest-item,
  body.ptest-printing [data-ptest-print] .ptest-box,
  body.ptest-printing [data-ptest-print] .ptest-table { break-inside: avoid; page-break-inside: avoid; }
}

/* ─── Movimiento reducido ───
   Al final del archivo a propósito: con igual especificidad, las reglas de
   transición/animación de arriba (barra lateral, progreso, campos, marcas,
   avisos) ganarían si este bloque estuviera antes. book.js y app.js eligen
   además `behavior` de scrollIntoView con matchMedia. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; scroll-behavior: auto !important; }
  .feedback-item.is-highlight { background: var(--tint); }
}
