/* OJO: @import tiene que ser lo PRIMERO del archivo. Si se le pone una regla
   arriba (aunque sea un :root con variables), el navegador lo ignora entero y la
   app se queda sin Inter/Sora: cambian las métricas y se corre todo el layout. */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Sora:wght@600;700;800&family=JetBrains+Mono:wght@400;500&display=swap');

/* Ancho de página. DOS valores, no uno:

   - `--page-max`: pantallas tipo tablero (proyectos, un proyecto), que tienen
     columnas y aprovechan el espacio. Coincide EXACTO con el ancho y el padding de
     `.topbar-inner`, así el contenido arranca donde arranca el logo. Antes era
     1540/1rem contra 1440/20px de la barra: la página se veía corrida 70px a la
     izquierda del logo.
   - `--page-narrow`: pantallas de UNA sola columna de texto (notas, preview).
     A todo lo ancho las líneas quedan interminables y las tarjetas medio vacías. */
:root { --page-max: 1440px; --page-narrow: 1080px; --page-pad: 1.25rem; }

/* ── Línea superior = decorativa en reposo + barra de progreso al navegar ── */
.route-progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2.5px; z-index: 3000;
  transform: scaleX(1); transform-origin: 0 50%;   /* reposo: línea decorativa completa */
  background: linear-gradient(90deg, var(--brand) 0%, var(--brand-mid, var(--brand)) 60%, transparent 100%);
  opacity: .9; pointer-events: none; will-change: transform;
}
.route-progress.is-active {                          /* navegando: barra sólida con glow */
  height: 3px; opacity: 1;
  background: linear-gradient(90deg, var(--brand), var(--brand-mid, var(--brand)));
  box-shadow: 0 0 8px color-mix(in srgb, var(--brand) 55%, transparent);
}
@media (prefers-reduced-motion: reduce) {
  .route-progress.is-active { transform: scaleX(1) !important; height: 2.5px; box-shadow: none; }
}

/* ── Variables ─────────────────────────────────────────────────────────── */
:root {
  --bg: #f0f4f9;
  --panel: #ffffff;
  --panel-2: #f8fafc;
  --line: #e1e8f0;
  --line-2: #cdd8e7;
  --text: #0f1c2e;
  --text-2: #1e3050;
  --muted: #56687a;

  /* Color del texto que va ENCIMA del color de marca. Con el lila de la marca es
     blanco; el arcoiris lo pisa por negro, porque ahi el fondo se aclara. */
  --on-brand: #fff;

  /* Rojo de error/bloqueo. En oscuro se aclara: ver el bloque [data-theme]. */
  --danger: #b91c1c;
  --danger-2: #dc2626;
  --muted-2: #6e7d8e;   /* tertiary text — subido para contraste legible (~3.9:1 sobre blanco) */

  /* El acento es el de la cara del logo que está encendida: lila en los
     espacios (y donde no hay sección), azul en un proyecto, amarillo en una
     tarea. Ver el bloque "Acento por sección" y DESIGN.md. */
  --brand: #6a58d8;
  --brand-hover: #5846c4;
  --brand-light: #f1eefd;
  --brand-light-2: #ddd6fb;
  /* El acento como FONDO con texto blanco encima (el botón primario). En claro es
     el mismo de marca; en oscuro no: el tono aclarado de texto con
     blanco encima queda en 3.5:1. Los temas que cambian --brand lo arrastran. */
  --brand-solid: var(--brand);
  --brand-solid-hover: var(--brand-hover);

  --accent: #f59e42;
  --accent-light: #fff7ed;

  /* Violeta Compartido: lo que ven otros (un espacio que no es el personal).
     Informa, no decora: ver DESIGN.md, "El Color Informa". */
  --shared: #7c3aed;
  --shared-light: #f3eefe;

  /* Niveles ordinales de Ciclo Par (1-5): fuente única para la escala, la leyenda y el detalle. */
  --niv-1: var(--danger-2);  /* Insuficiente */
  --niv-2: #f59e0b;  /* Necesita mejorar */
  --niv-3: #16a34a;  /* Satisfactorio */
  --niv-4: #2563eb;  /* Muy satisfactorio */
  --niv-5: #7c3aed;  /* Excepcional */

  --ok: #059669;
  --ok-light: #ecfdf5;
  --bad: var(--danger-2);
  --bad-light: #fef2f2;
  --warn: #d97706;
  --warn-light: #fffbeb;

  --sidebar-w: 260px;
  --topbar-h: 56px;

  --radius-sm: 6px;
  --radius: 10px;
  --radius-lg: 14px;
  --radius-xl: 18px;

  --shadow-xs: 0 1px 2px rgba(12,32,60,0.06);
  --shadow-sm: 0 1px 4px rgba(12,32,60,0.08), 0 1px 2px rgba(12,32,60,0.04);
  --shadow: 0 4px 16px rgba(12,32,60,0.08);
  --shadow-lg: 0 8px 32px rgba(12,32,60,0.12);

  /* Curvas de easing (Emil: las built-in son débiles; ease-out da feedback inmediato). */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --transition: 150ms var(--ease-out);
}

/* ── Transición de tema ──────────────────────────────────
   El tema nuevo se abre en círculo desde el botón de apariencia, con el borde
   difuminado. Sale de donde lo tocaste: el gesto y lo que pasa en pantalla son
   el mismo lugar, y eso hace que se lea como consecuencia de haberlo tocado y
   no como un efecto encima.

   El viejo NO se anima: queda quieto debajo mientras el nuevo lo tapa. Animar
   los dos hacía que se vieran las dos versiones del mismo texto corridas.

   CÓMO se abre, que tiene truco:

   El degradado NO se anima. `mask-image` es una propiedad DISCRETA —no se
   interpola de un degradado a otro, salta de uno al otro por la mitad— así que
   animar las paradas no hace nada. Lo que se anima es `mask-size`, que es una
   medida común y corriente: el degradado está quieto dentro de su baldón y lo
   que crece es el baldón.

   Y el centro queda clavado gracias a cómo funcionan los porcentajes de
   `mask-position`: un `P%` alinea el punto P% DEL BALDÓN con el punto P% del
   contenedor. Si el degradado está centrado en el P% de su baldón —el mismo
   P%— su centro cae siempre en el P% de la pantalla, mida lo que mida el
   baldón. Por eso `--tema-px/py` aparecen dos veces: una en el `at` del
   degradado y otra en el `mask-position`. Cambiar una sola hace que el círculo
   se abra desde un lado y se vaya corriendo para el otro.

   El baldón es cuadrado, así que `ellipse 50% 50%` da un círculo de radio la
   mitad del lado. Lleno hasta el 75% y de ahí a transparente: el frente que
   avanza es una franja ancha y no una línea. El JS manda en `--tema-s` el lado
   final, ya estirado para que ese 75% alcance la esquina más lejana. */
::view-transition-old(root) {
  animation: none;
}
::view-transition-new(root) {
  /* La curva importa más que el número: casi todo el recorrido pasa en el
     primer tercio del tiempo y el resto es frenada larga. Al revés —salir
     lento y acelerar— se siente pesado, como si costara. */
  animation: 620ms cubic-bezier(.22, 1, .36, 1) both abrir-tema;
  -webkit-mask-image: radial-gradient(ellipse 50% 50%
    at var(--tema-px, 50%) var(--tema-py, 3%), #000 0 75%, transparent 100%);
  mask-image: radial-gradient(ellipse 50% 50%
    at var(--tema-px, 50%) var(--tema-py, 3%), #000 0 75%, transparent 100%);
  -webkit-mask-position: var(--tema-px, 50%) var(--tema-py, 3%);
  mask-position: var(--tema-px, 50%) var(--tema-py, 3%);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}
/* De baldón sin tamaño —nada pintado, nada de máscara, el tema nuevo entero
   invisible— al lado final. */
@keyframes abrir-tema {
  from { -webkit-mask-size: 0 0; mask-size: 0 0; }
  to {
    -webkit-mask-size: var(--tema-s, 300vmax) var(--tema-s, 300vmax);
    mask-size: var(--tema-s, 300vmax) var(--tema-s, 300vmax);
  }
}

/* Quien pidió menos movimiento se queda con el fundido de siempre, que es lo
   mínimo para que el cambio no sea un salto seco. */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root) { animation: 200ms ease out fade-out; }
  ::view-transition-new(root) { animation: 200ms ease in fade-in; mask-image: none; }
}
@keyframes fade-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes fade-in  { from { opacity: 0; } to { opacity: 1; } }

/* ── Dark mode ──────────────────────────────────────────────────────────── */
/* ── Modo oscuro ─────────────────────────────────────────────────────────
   Grises neutros, no azulados: el azul marino tine todo y compite con los colores
   de estado (una tarjeta azul sobre fondo azul no se despega). Los saltos entre
   fondo, panel y hover son chicos a proposito — el relieve lo dan los bordes, no
   los rellenos.
       #191919  fondo de la pagina
       #202020  tarjetas y paneles
       #1a1a1a  columnas y bloques que RECEDEN (para que la tarjeta resalte encima)
       #2f2f2f  bordes                                                            */
[data-theme="dark"] {
  --bg:      #191919;
  --panel:   #202020;
  --panel-2: #1a1a1a;
  --line:    #2f2f2f;
  --line-2:  #3d3d3d;
  --text:    #e6e6e4;
  --text-2:  #c9c9c6;
  --muted:   #9b9b98;
  --muted-2: #71716e;

  --brand:         #a99cf6;
  --brand-hover:   #bdb3f8;
  --brand-solid:       #6a58d8;   /* blanco encima 5:1 */
  --brand-solid-hover: #5846c4;
  --brand-mid:     #8b7cf0;
  /* Un rojo oscuro sobre fondo casi negro no se lee: en oscuro el rojo de error
     va MAS claro que el del tema claro, no mas oscuro. */
  --danger:   #f87171;
  --danger-2: #ef4444;
  /* Fondo de lo seleccionado (ej. la solapa activa). Apenas tenido: con mas
     color queda un bloque que pesa mas que el texto. */
  --brand-light:   #1f1c30;
  --brand-light-2: #2d2750;

  --shared:       #a78bfa;
  --shared-light: #221b33;

  --ok-light:     #14261a;
  --bad-light:    #2c1514;
  --warn-light:   #2a2010;
  --accent-light: #241c0e;
}

[data-theme="dark"] .card {
  box-shadow: none;
}

[data-theme="dark"] .md-body pre {
  background: #27272a;
  border-color: #3f3f46;
  color: #e4e4e7;
}

[data-theme="dark"] .md-body code {
  background: transparent;
  border-color: #3f3f46;
  color: #d4d4d8;
}

[data-theme="dark"] .toastui-editor-contents code {
  background: transparent !important;
  border-color: #3f3f46 !important;
  color: #d4d4d8 !important;
}

[data-theme="dark"] .modal-backdrop {
  background: rgba(0,0,0,0.6);
}

/* ── Toast UI Preview — igualar estilos a la vista pública ──────────────── */
.toastui-editor-contents code {
  font-family: 'JetBrains Mono', monospace !important;
  font-size: 0.82em !important;
  background: var(--brand-light) !important;
  color: var(--brand) !important;
  border-radius: 4px !important;
  padding: 0.1em 0.35em !important;
  border: 1px solid var(--brand-light-2) !important;
}
.toastui-editor-contents pre {
  background: #1e1e24 !important;
  color: #e4e4e7 !important;
  border-radius: 10px !important;
  padding: 1rem 1.1rem !important;
  font-family: 'JetBrains Mono', monospace !important;
  font-size: 0.82rem !important;
  border: 1px solid #3f3f46 !important;
  text-shadow: none !important;
}
.toastui-editor-contents code {
  text-shadow: none !important;
}
.toastui-editor-contents pre code {
  background: none !important;
  color: inherit !important;
  border: none !important;
  padding: 0 !important;
}

/* ── Toast UI Editor — dark mode ────────────────────────────────────────── */
[data-theme="dark"] .toastui-editor-defaultUI {
  border-color: var(--line) !important;
}
[data-theme="dark"] .toastui-editor-toolbar,
[data-theme="dark"] .toastui-editor-toolbar-group,
[data-theme="dark"] .toastui-editor-toolbar-item,
[data-theme="dark"] .toastui-editor-toolbar-wrap,
[data-theme="dark"] .toastui-editor-toolbar > div,
[data-theme="dark"] .toastui-editor-toolbar > ul,
[data-theme="dark"] .toastui-editor-toolbar > span {
  background: #1c1c20 !important;
  border-bottom-color: #27272a !important;
}
[data-theme="dark"] .toastui-editor-toolbar-icons {
  background-color: transparent !important;
  filter: invert(1) brightness(0.85) !important;
  border-color: transparent !important;
}
[data-theme="dark"] .toastui-editor-toolbar-icons:hover {
  background-color: transparent !important;
  box-shadow: 0 0 0 1px #71717a inset !important;
  filter: invert(1) brightness(1.3) !important;
}
[data-theme="dark"] .toastui-editor-toolbar-divider {
  background: #27272a !important;
}
[data-theme="dark"] .toastui-editor-tabs,
[data-theme="dark"] .toastui-editor-defaultUI .toastui-editor-md-tab-container {
  background: #1c1c20 !important;
  border-color: #27272a !important;
}
[data-theme="dark"] .toastui-editor-tabs .tab-item {
  color: #a1a1aa !important;
  background: transparent !important;
}
[data-theme="dark"] .toastui-editor-tabs .tab-item.active {
  color: #fafafa !important;
  border-bottom-color: var(--brand) !important;
  background: transparent !important;
}
[data-theme="dark"] .toastui-editor-main,
[data-theme="dark"] .toastui-editor-md-container,
[data-theme="dark"] .toastui-editor-ww-container {
  background: #18181b !important;
}
[data-theme="dark"] .toastui-editor-contents,
[data-theme="dark"] .ProseMirror,
[data-theme="dark"] .CodeMirror,
[data-theme="dark"] .CodeMirror-scroll,
[data-theme="dark"] .CodeMirror-lines {
  background: #18181b !important;
  color: #e4e4e7 !important;
}
[data-theme="dark"] .CodeMirror-cursor {
  border-left-color: #e4e4e7 !important;
}
[data-theme="dark"] .CodeMirror-selected,
[data-theme="dark"] .CodeMirror-focused .CodeMirror-selected {
  background: #3f3f46 !important;
}
[data-theme="dark"] .toastui-editor-md-splitter {
  background: #27272a !important;
}
[data-theme="dark"] .toastui-editor-mode-switch,
[data-theme="dark"] .toastui-editor-mode-switch .tab-item {
  background: #1c1c20 !important;
  border-color: #27272a !important;
  color: #a1a1aa !important;
}
[data-theme="dark"] .toastui-editor-mode-switch .tab-item.active {
  background: #27272a !important;
  color: #fafafa !important;
}
[data-theme="dark"] .cm-s-default .cm-header  { color: var(--brand) !important; }
[data-theme="dark"] .cm-s-default .cm-strong,
[data-theme="dark"] .cm-s-default .cm-em      { color: #e4e4e7 !important; }
[data-theme="dark"] .cm-s-default .cm-link,
[data-theme="dark"] .cm-s-default .cm-url     { color: #60a5fa !important; }
[data-theme="dark"] .cm-s-default .cm-quote   { color: #a1a1aa !important; }
[data-theme="dark"] .cm-s-default .cm-comment { color: #71717a !important; }
/* inline code en write mode (CodeMirror) — light */
.cm-s-default .cm-code,
.CodeMirror .cm-code,
.toastui-editor-defaultUI .cm-code,
.toastui-editor-md-code {
  background: var(--brand-light) !important;
  color: var(--brand) !important;
  border-radius: 3px !important;
}
/* inline code en write mode (CodeMirror) — dark */
[data-theme="dark"] .cm-s-default .cm-code,
[data-theme="dark"] .CodeMirror .cm-code,
[data-theme="dark"] .toastui-editor-defaultUI .cm-code,
[data-theme="dark"] .toastui-editor-md-code {
  background: #2d2d32 !important;
  color: #d4d4d8 !important;
  border-radius: 3px !important;
}
/* code block lines */
[data-theme="dark"] .toastui-editor-md-code-block-line-background {
  background: #27272a !important;
}
[data-theme="dark"] .toastui-editor-md-code-block-line-background span,
[data-theme="dark"] .toastui-editor-md-code-block-line-background .cm-string,
[data-theme="dark"] .toastui-editor-md-code-block-line-background .cm-keyword {
  color: #e4e4e7 !important;
}
[data-theme="dark"] .toastui-editor-contents h1,
[data-theme="dark"] .toastui-editor-contents h2,
[data-theme="dark"] .toastui-editor-contents h3,
[data-theme="dark"] .toastui-editor-contents p,
[data-theme="dark"] .toastui-editor-contents li { color: #e4e4e7 !important; }
[data-theme="dark"] .toastui-editor-contents hr { border-color: #27272a !important; }

[data-theme="dark"] .toastui-editor-contents blockquote {
  border-color: #3f3f46 !important;
  color: #a1a1aa !important;
}
[data-theme="dark"] .toastui-editor-contents table th { background: #1c1c20 !important; }
[data-theme="dark"] .toastui-editor-contents table th,
[data-theme="dark"] .toastui-editor-contents table td { border-color: #27272a !important; }

/* ── Reset ──────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

html { overflow-y: scroll;
  /* Sin el rectángulo azul que pinta el navegador del celular al tocar algo:
     aparecía antes del color real del botón, como un link. Cada control marca el
     toque con su propio :active. */
  -webkit-tap-highlight-color: transparent; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 14px/1.6 'Inter', sans-serif;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6 { margin: 0; font-family: 'Sora', sans-serif; line-height: 1.25; }
p { margin: 0; }
a { color: inherit; }
button { cursor: pointer; font: inherit; }

/* ── Topbar ─────────────────────────────────────────────────────────────── */
.topbar {
  position: sticky;
  top: 0;
  z-index: 100;
  height: var(--topbar-h);
  border-bottom: 1px solid var(--line);
  /* Sólida, sin vidrio: el sistema es plano (DESIGN.md). El borde la separa. */
  background: var(--panel);
  display: flex;
  align-items: center;
}

/* La línea roja superior ahora la dibuja .route-progress (que además hace de barra
   de progreso de navegación). Ver "Línea superior" arriba en este archivo. */

.topbar-inner {
  max-width: 1440px;
  width: 100%;
  margin: 0 auto;
  padding: 0 1.25rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
}

.brand {
  text-decoration: none;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: 'Sora', sans-serif;
  font-weight: 800;
  font-size: 1rem;
  color: var(--muted);
  letter-spacing: -0.01em;
  /* Los siete clicks rápidos del arcoíris seleccionaban el nombre. */
  user-select: none;
  -webkit-user-select: none;
}

.brand-logo-btn {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0; border: none; background: none; cursor: pointer; line-height: 0;
  /* Se toca siete veces seguidas (el arcoíris): sin esto el celular marcaba el
     dibujo como texto seleccionado. */
  -webkit-user-select: none; user-select: none;
}
/* Reaccion del logo al tocarlo. Alterna de lado: siempre para el mismo parece un
   icono cargando y no algo que responde. Se dispara sacando y volviendo a poner la
   clase por JS (hace falta un reflow en el medio). */
.brand-logo-btn.is-pop-a .brand-logo { animation: logoGolpeA .34s cubic-bezier(.34,1.4,.5,1); }
.brand-logo-btn.is-pop-b .brand-logo { animation: logoGolpeB .34s cubic-bezier(.34,1.4,.5,1); }
@keyframes logoGolpeA {
  0%   { transform: rotate(0) scale(1); }
  30%  { transform: rotate(-16deg) scale(1.18); }
  60%  { transform: rotate(6deg) scale(.97); }
  100% { transform: rotate(0) scale(1); }
}
@keyframes logoGolpeB {
  0%   { transform: rotate(0) scale(1); }
  30%  { transform: rotate(16deg) scale(1.18); }
  60%  { transform: rotate(-6deg) scale(.97); }
  100% { transform: rotate(0) scale(1); }
}
/* Variante mas marcada. */
.brand-logo-btn.is-cerca-a .brand-logo { animation: logoFuerteA .4s cubic-bezier(.34,1.5,.5,1); }
.brand-logo-btn.is-cerca-b .brand-logo { animation: logoFuerteB .4s cubic-bezier(.34,1.5,.5,1); }
@keyframes logoFuerteA {
  0%   { transform: rotate(0) scale(1); }
  28%  { transform: rotate(-30deg) scale(1.34); }
  62%  { transform: rotate(13deg) scale(.93); }
  100% { transform: rotate(0) scale(1); }
}
@keyframes logoFuerteB {
  0%   { transform: rotate(0) scale(1); }
  28%  { transform: rotate(30deg) scale(1.34); }
  62%  { transform: rotate(-13deg) scale(.93); }
  100% { transform: rotate(0) scale(1); }
}
/* Vuelta completa. */
.brand-logo-btn.is-premio .brand-logo { animation: logoVuelta .9s cubic-bezier(.22,.9,.3,1); }
@keyframes logoVuelta {
  0%   { transform: scale(1) rotate(0); }
  60%  { transform: scale(1.4) rotate(380deg); }
  100% { transform: scale(1) rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .brand-logo-btn .brand-logo { animation: none !important; }
}

.brand-logo {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  display: block;
}

/* ── El logo: cada cara es una parte del portal ──
   piso = espacio · pared izquierda = proyecto · pared derecha = tarea.
   La cara encendida dice dónde estás; en la home, el login y lo que no es
   ninguna de las tres, van las tres. Ver el macro logo_cubo (macros.html).
   El color de cada cara está recortado por un círculo con centro en la esquina
   del cubo: encenderla es hacer crecer ese círculo, así el color nace desde el
   centro y se derrama por la cara; apagarla lo retira hacia el centro. */
.rt-logo {
  --logo-hex: #161616;
  --logo-apagada: #f7f3ec;
  --logo-espacio: #8b7cf0;
  --logo-proyecto: #2b7fff;
  --logo-tarea: #ffb627;
}
.rt-hex { fill: var(--logo-hex); }
.rt-base { fill: var(--logo-apagada); }
.rt-cara--espacio { fill: var(--logo-espacio); }
.rt-cara--proyecto { fill: var(--logo-proyecto); }
.rt-cara--tarea { fill: var(--logo-tarea); }
.rt-tinta {
  transform-box: view-box;
  transform-origin: 256px 256px;
  transform: scale(0);
  transition: transform .7s cubic-bezier(.22, 1, .36, 1);
}
.rt-logo[data-cara="todas"] .rt-tinta,
.rt-logo[data-cara="espacio"] .rt-tinta--espacio,
.rt-logo[data-cara="proyecto"] .rt-tinta--proyecto,
.rt-logo[data-cara="tarea"] .rt-tinta--tarea { transform: scale(1); }
/* Las tres juntas se encienden una detrás de otra: piso, izquierda, derecha. */
.rt-logo[data-cara="todas"] .rt-tinta--proyecto { transition-delay: 120ms; }
.rt-logo[data-cara="todas"] .rt-tinta--tarea { transition-delay: 240ms; }
/* Para ponerlo en la cara anterior sin que se vea (ver el script del header). */
.rt-logo.rt-quieto .rt-tinta { transition: none; }
@media (prefers-reduced-motion: reduce) {
  .rt-tinta { transition: none; }
}

.brand-text { text-decoration: none; color: inherit; font: inherit; letter-spacing: inherit; }
/* El nombre en gris grafito en claro y en blanco en oscuro: el color lo pone el
   logo, que dice en qué parte del portal estás. */
.brand em { font-style: normal; color: #5c5c5c; font-weight: 500; }
[data-theme="dark"] .brand em, [data-theme="dark"] .login-brand em { color: #fff; }

.topbar-nav { display: flex; align-items: center; gap: 0.25rem; }

.nav-link {
  text-decoration: none;
  color: var(--muted);
  font-weight: 500;
  font-size: 0.875rem;
  padding: 0.35rem 0.65rem;
  border-radius: var(--radius-sm);
  transition: background var(--transition), color var(--transition);
}

.nav-link:hover { background: var(--panel-2); color: var(--text); }
.nav-link.active { background: var(--brand-light); color: var(--brand); }
.nav-link-ico { display: none; }
/* Con el contenedor adelante: `.nav-user-item` (más abajo) le pone display:flex
   y en la compu aparecía en el menú. */
.nav-user-dropdown .nav-apariencia, .nav-user-dropdown .nav-sub { display: none; }
/* El logo del inicio es para el celular: en la compu el logo ya está arriba. */
.brand-logo-btn--inicio { display: none; }

.theme-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: var(--radius-sm);
  border: none;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
  padding: 0;
}
.theme-toggle:hover {
  background: transparent;
  color: var(--text);
}

.nav-studio {
  background: var(--brand);
  color: #fff;
  border-radius: var(--radius-sm);
  padding: 0.35rem 0.75rem;
  font-weight: 600;
  font-size: 0.875rem;
  text-decoration: none;
  transition: background var(--transition);
}
.nav-studio:hover { background: var(--brand-hover); color: var(--on-brand); }
/* El tema, igual que notas y la campanita: 34px, sin margen propio y el mismo
   hover. Medía 30px con .75rem de margen a la izquierda: notas quedaba lejos
   del tema y el tema pegado a la campanita. */
.topbar-nav .theme-toggle { margin-left: 0; width: 34px; height: 34px; border-radius: 8px;
  transition: color .15s, background .15s; }
.topbar-nav .theme-toggle:hover { color: var(--brand); background: var(--panel-2); }
.topbar-nav .theme-toggle svg { width: 17px; height: 17px; }

/* ── Buttons ────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  border: none;
  border-radius: var(--radius);
  padding: 0.5rem 0.9rem;
  font: inherit;
  font-weight: 600;
  font-size: 0.875rem;
  text-decoration: none;
  transition: background var(--transition), box-shadow var(--transition), color var(--transition), transform 120ms var(--ease-out);
  white-space: nowrap;
  -webkit-user-select: none;
  user-select: none;
}

.btn-primary { background: var(--brand-solid); color: var(--on-brand); }
.btn-primary:hover { background: var(--brand-solid-hover); color: var(--on-brand); }

.btn-ghost { background: transparent; color: var(--text); border: 1px solid var(--line-2); }
.btn-ghost:hover { background: var(--panel-2); }

/* Rojo sólido y sobrio, con texto blanco (5.6:1): el rosado pálido con letras
   rojas se veía barato. Igual en claro y en oscuro. */
.btn-danger { background: #c92a2a; color: #fff; border: 1px solid #c92a2a; }
.btn-danger:hover { background: #a61e1e; border-color: #a61e1e; color: #fff; }

/* Foco visible y consistente para teclado en todos los botones. */
.btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
[data-theme="dark"] .btn:focus-visible { outline-color: var(--brand); }
/* Feedback táctil al presionar (Emil: scale sutil, no translate). */
.btn:active { transform: scale(0.97); box-shadow: none; }
@media (prefers-reduced-motion: reduce) { .btn:active { transform: none; } }

.btn-sm { padding: 0.3rem 0.6rem; font-size: 0.8rem; border-radius: var(--radius-sm); }
.btn.disabled,
.btn[aria-disabled="true"] {
  opacity: 0.5;
  pointer-events: none;
  cursor: not-allowed;
}
.btn-full { width: 100%; justify-content: center; }

/* ── Cards ──────────────────────────────────────────────────────────────── */
.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}

/* ── Form elements ──────────────────────────────────────────────────────── */
input, select, textarea {
  width: 100%;
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  padding: 0.45rem 0.65rem;
  font: inherit;
  font-size: 0.875rem;
  color: var(--text);
  background: var(--panel);
  transition: border-color var(--transition), box-shadow var(--transition);
}

input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 16%, transparent);
}

input::placeholder, textarea::placeholder { color: var(--muted); }

label {
  display: grid;
  gap: 0.22rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--muted);
  letter-spacing: 0.01em;
}

/* ── Chips & badges ─────────────────────────────────────────────────────── */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  border-radius: 999px;
  padding: 0.1rem 0.5rem;
  font-size: 0.75rem;
  font-weight: 600;
  white-space: nowrap;
}

.chip-green  { background: var(--ok-light); color: var(--ok); border: 1px solid #a7f3d0; }

.chip-gray   { background: var(--panel-2); color: var(--muted); border: 1px solid var(--line); }

.audit-action-chip {
  position: relative;
  cursor: help;
}

.audit-action-chip::after {
  content: attr(data-tooltip);
  position: absolute;
  left: 50%;
  bottom: calc(100% + 8px);
  transform: translateX(-50%);
  max-width: 420px;
  min-width: 180px;
  width: max-content;
  padding: 0.4rem 0.55rem;
  border-radius: 8px;
  background: #262626;
  color: #e6e6e4;
  border: 1px solid #3d3d3d;
  font-size: 0.72rem;
  line-height: 1.35;
  white-space: normal;
  box-shadow: 0 8px 22px rgba(2, 6, 23, 0.28);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  z-index: 20;
}

.audit-action-chip:hover::after {
  opacity: 1;
  visibility: visible;
}

/* ── Tooltip reutilizable: <span class="tip" data-tip="Texto">…</span> ── */
.tip { position: relative; }
.tip::after {
  content: attr(data-tip);
  position: absolute; left: 50%; bottom: calc(100% + 8px);
  transform: translateX(-50%) translateY(4px);
  width: max-content; max-width: 210px; padding: .5rem .7rem; border-radius: 9px;
  background: #262626; color: #e6e6e4; font-family: 'Inter', sans-serif; font-size: .72rem; font-style: normal; font-weight: 400; line-height: 1.45; letter-spacing: 0;
  white-space: normal; text-align: center; box-shadow: 0 6px 20px rgba(0,0,0,.18);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .15s ease, transform .15s ease; z-index: 1150;
}
.tip::before {  /* flechita hacia abajo */
  content: ''; position: absolute; left: 50%; bottom: calc(100% + 3px);
  transform: translateX(-50%) translateY(4px);
  border: 5px solid transparent; border-top-color: #262626;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .15s ease, transform .15s ease; z-index: 1150;
}
.tip:hover::after, .tip:hover::before, .tip:focus-visible::after, .tip:focus-visible::before {
  opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0);
}
[data-theme="dark"] .tip::after { background:#27272a; color:#fafafa; }
[data-theme="dark"] .tip::before { border-top-color:#27272a; }
/* Variante anclada a la DERECHA. El tooltip va centrado sobre su elemento, así que
   uno pegado al borde derecho se salía de la pantalla: como es `position:absolute`
   sin recorte, agrandaba el área scrolleable y aparecía scroll horizontal en TODA
   la página (pasó con el botón del clip). Anclado a la derecha entra. */
.tip--end::after { left: auto; right: 0; transform: translateX(0) translateY(4px); }
.tip--end::before { left: auto; right: 13px; transform: translateX(0) translateY(4px); }
.tip--end:hover::after, .tip--end:hover::before,
.tip--end:focus-visible::after, .tip--end:focus-visible::before { transform: translateX(0) translateY(0); }

/* Variante hacia abajo (para elementos de la barra superior, donde arriba se cortaría) */
.tip--down::after { top: calc(100% + 8px); bottom: auto; }
.tip--down::before { top: calc(100% + 3px); bottom: auto; border-top-color: transparent; border-bottom-color: #262626; }
[data-theme="dark"] .tip--down::before { border-top-color: transparent; border-bottom-color: #27272a; }

/* El globo real: un solo nodo colgado del <body>, `position:fixed`. Al no vivir
   adentro del elemento, no lo recorta ningún overflow (modales, paneles con
   scroll, tarjetas) — que era el bug de siempre. El ::after de arriba queda solo
   como respaldo si el JS no corrió: `tip-js` lo apaga apenas engancha. */
.tip-js .tip::after, .tip-js .tip::before { content: none; }
.tip-pop {
  position: fixed; top: -9999px; left: 0; z-index: 3000;
  max-width: 260px; padding: .5rem .7rem; border-radius: 9px;
  background: #262626; color: #e6e6e4;
  font-family: 'Inter', sans-serif; font-size: .72rem; font-style: normal; font-weight: 400;
  line-height: 1.45; letter-spacing: 0; text-align: center; white-space: normal;
  box-shadow: 0 6px 20px rgba(0,0,0,.18);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .15s ease;
}
.tip-pop--on { opacity: 1; visibility: visible; }
.tip-pop-arrow {
  position: absolute; top: 100%; transform: translateX(-50%);
  border: 5px solid transparent; border-top-color: #262626;
}
.tip-pop--abajo .tip-pop-arrow {
  top: auto; bottom: 100%; border-top-color: transparent; border-bottom-color: #262626;
}
[data-theme="dark"] .tip-pop { background: #27272a; color: #fafafa; }
[data-theme="dark"] .tip-pop-arrow { border-top-color: #27272a; }
[data-theme="dark"] .tip-pop--abajo .tip-pop-arrow { border-top-color: transparent; border-bottom-color: #27272a; }

/* Spinner reutilizable para botones en modo "cargando" (hereda el color del texto) */
.btn-spin { display:inline-block; width:14px; height:14px; border:2px solid currentColor; border-top-color:transparent;
  border-radius:50%; animation:btnSpin .6s linear infinite; vertical-align:-2px; margin-right:.4rem; }
@keyframes btnSpin { to { transform:rotate(360deg); } }
.btn.is-loading { opacity:.85; cursor:progress; }

/* ── Markdown body ──────────────────────────────────────────────────────── */
.md-body {
  color: var(--text);
  font-size: 0.9375rem;
  line-height: 1.7;
}

.md-body h1, .md-body h2, .md-body h3, .md-body h4 {
  margin-top: 1.75rem;
  margin-bottom: 0.5rem;
  letter-spacing: -0.01em;
}

.md-body h1 { font-size: 1.5rem; padding-bottom: 0.5rem; border-bottom: 1px solid var(--line); }
.md-body h2 { font-size: 1.2rem; padding-bottom: 0.35rem; border-bottom: 1px solid var(--line); }
.md-body h3 { font-size: 1rem; }
.md-body h4 { font-size: 0.9rem; color: var(--text-2); }

.md-body p { margin: 0.75rem 0; }

.md-body a { color: var(--brand); text-decoration: underline; text-decoration-color: var(--brand-light-2); }
.md-body a:hover { text-decoration-color: var(--brand); }

.md-code-block {
  margin: 1rem 0;
  border-radius: var(--radius);
  border: 1px solid #2c3342;
  overflow: hidden;
  box-shadow: 0 4px 20px rgba(0,0,0,0.18);
}

.md-code-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 14px;
  background: #13151f;
  border-bottom: 1px solid #2c3342;
}

.md-code-dots {
  display: flex;
  gap: 5px;
}

.md-code-dots span {
  display: block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
}

.md-code-dots span:nth-child(1) { background: #ff5f57; }
.md-code-dots span:nth-child(2) { background: #ffbd2e; }
.md-code-dots span:nth-child(3) { background: #28c840; }

.md-code-lang {
  flex: 1;
  font-size: 0.72rem;
  font-weight: 600;
  color: #6e7681;
  font-family: 'JetBrains Mono', monospace;
  letter-spacing: 0.03em;
}

.md-body pre {
  background: #1b1f2a;
  color: #e4e4e7;
  border-radius: 0;
  padding: 1rem 1.1rem;
  overflow-x: auto;
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.82rem;
  line-height: 1.6;
  margin: 0;
  border: none;
  text-shadow: none;
}

.md-body code {
  text-shadow: none;
}

.code-copy-btn {
  border: 1px solid #3b4658;
  background: #1f2937;
  color: #e6edf3;
  border-radius: 6px;
  padding: 0.22rem 0.5rem;
  font-size: 0.72rem;
  font-weight: 600;
  cursor: pointer;
}

.code-copy-btn:hover {
  background: #2d3748;
}

.md-body code {
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.82em;
  background: var(--brand-light);
  color: var(--brand);
  border-radius: 4px;
  padding: 0.1em 0.35em;
  border: 1px solid var(--brand-light-2);
}

.md-body pre code {
  background: none;
  color: inherit;
  border: none;
  padding: 0;
  font-size: inherit;
}

.md-body table {
  width: 100%;
  border-collapse: collapse;
  margin: 1rem 0;
  font-size: 0.875rem;
}

.md-body th {
  text-align: left;
  padding: 0.55rem 0.75rem;
  background: var(--panel-2);
  border: 1px solid var(--line);
  font-weight: 600;
  color: var(--text-2);
  font-size: 0.8rem;
}

.md-body td {
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--line);
  vertical-align: top;
}

.md-body tr:hover td { background: var(--panel-2); }

.md-body blockquote {
  border-left: 3px solid var(--brand-light-2);
  margin: 1rem 0;
  padding: 0.5rem 1rem;
  background: var(--brand-light);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  color: var(--muted);
}

.md-body ul, .md-body ol { padding-left: 1.5rem; margin: 0.75rem 0; }
.md-body li { margin: 0.25rem 0; }

.md-body hr {
  border: none;
  border-top: 1px solid var(--line);
  margin: 1.5rem 0;
}

/* Admonitions */
.admonition {
  border-radius: var(--radius);
  padding: 0.75rem 1rem;
  margin: 1rem 0;
  border-left: 4px solid;
}
.admonition.note    { background: var(--brand-light); border-color: var(--brand); }
.admonition.warning { background: var(--warn-light); border-color: var(--warn); }
.admonition.danger  { background: var(--bad-light); border-color: var(--bad); }
.admonition.tip     { background: var(--ok-light); border-color: var(--ok); }

.admonition-title { font-weight: 700; font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.35rem; }

.editor-area {
  flex: 1;
  overflow: hidden;
  padding: 0.75rem;
  display: flex;
  flex-direction: column;
}

#editor { flex: 1; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }

/* Modal layer */
.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1100;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Un modal más alto que la ventana se scrollea acá adentro (con el margin:auto
     de la tarjeta, que evita que el centrado le coma la parte de arriba). Antes
     dependía del scroll de la página, que ahora queda trabado. */
  overflow-y: auto;
  padding: 1rem;
  background: rgba(15, 28, 46, 0.25);
  backdrop-filter: blur(7px) saturate(150%);
}

/* Mientras hay un modal abierto no se scrollea la página de atrás (lo pone y lo
   saca el script de base.html). */
html.modal-abierto { overflow: hidden; }

/* «Qué hay de nuevo»: la pantalla que se abre sola después de un cambio. Es la
   tarjeta de siempre; lo único propio es el encabezado con el número de versión,
   el video y la lista.

   Se llama `nvv-` y no `nv-` porque `nv-` ya era del feed de Novedades de
   Pendientes. Compartían `nv-card` y `nv-lista`: el ancho de 600px de esta
   tarjeta achicaba la tarjeta del feed, y el scroll del feed se le aplicaba a
   la lista de acá. Dos features distintas no pueden compartir prefijo. */
.nvv-card { width:min(600px, 100%); }
.nvv-head { align-items:flex-start; }
.nvv-eyebrow { display:block; font-size:.68rem; font-weight:700; letter-spacing:.05em;
  text-transform:uppercase; color:var(--brand); margin-bottom:.15rem; }
.nvv-medio { display:block; width:100%; border-radius:.6rem; border:1px solid var(--line);
  background:var(--panel-2); margin-bottom:.9rem; }
/* Las pantallas viajan en una tira que se corre de a una: el que pasa ve de dónde
   viene y a dónde va, que es lo que una tira hace y un cambio de contenido no. */
/* El alto lo pone la pantalla que estás mirando, no la más alta de todas: con el
   alto compartido, el resumen —que es sólo texto— quedaba con medio modal vacío
   debajo. Lo mide el JS y acá se anima, para que el cambio de una a otra no sea un
   salto. */
/* El aire de los costados lo pone `modal-body`, que es de donde sale en todos los
   modales del portal: sin él, el texto arrancaba pegado al borde de la tarjeta. */
.nvv-viewport { overflow:hidden; transition:height .28s cubic-bezier(.22,1,.36,1);
  /* El alto que le escribe el JS es el del CONTENIDO. Con `border-box` —que es lo
     que usa todo el portal— ese número incluiría el aire de arriba y abajo, y el
     texto se quedaba sin los últimos veintinueve pixels: justo el renglón final. */
  box-sizing:content-box;
  /* Y el aire de los costados se lo pasa a cada página: acá adentro queda DENTRO
     del recorte, así que por el costado asomaba la punta de la página siguiente. */
  padding-left:0; padding-right:0; }
.nvv-tira { display:flex; align-items:flex-start;
  transition:transform .28s cubic-bezier(.22,1,.36,1); }
/* Un piso para que las pantallas de dos renglones no queden como una tirita, y un
   techo para el showcase: sin él, el modal pasaba de 225 a 536 de alto al cambiar
   de pantalla y eso se ve como un salto, no como pasar una hoja. */
.nvv-pag { flex:0 0 100%; min-width:0; padding:0 1rem; min-height:12.5rem; }
.nvv-medio { max-height:13rem; object-fit:contain; }
.nvv-medio--svg { max-height:none; padding:.5rem; }
.nvv-medio--svg svg { display:block; width:100%; height:auto; max-height:12rem; }
.nvv-pag-t { margin:0 0 .35rem; font-size:.95rem; font-weight:700; color:var(--text); }
.nvv-pag-p { margin:0; font-size:.86rem; line-height:1.55; color:var(--muted); }
.nvv-flecha { width:1.9rem; height:1.9rem; flex-shrink:0; border:1px solid var(--line);
  background:var(--panel); border-radius:999px; color:var(--muted); font-size:1rem;
  line-height:1; cursor:pointer; font-family:inherit; }
.nvv-flecha:hover:not(:disabled) { color:var(--brand); border-color:var(--brand); }
/* En las puntas se apaga en vez de irse: si desapareciera, los botones de al lado
   se correrían de lugar en cada paso. */
.nvv-flecha:disabled { opacity:.35; cursor:default; }
.nvv-puntos { display:flex; align-items:center; gap:.35rem; }
.nvv-punto { width:.45rem; height:.45rem; padding:0; border:none; border-radius:999px;
  background:var(--line-2); cursor:pointer; transition:background .15s, width .15s; }
.nvv-punto:hover { background:var(--muted-2); }
.nvv-punto.is-on { width:1.1rem; background:var(--brand); }
.nvv-listo { margin-left:auto; }
.nvv-lista { margin:0; padding-left:1.1rem; display:flex; flex-direction:column; gap:.65rem;
  font-size:.86rem; line-height:1.45; color:var(--text); }
.nvv-lista li::marker { color:var(--brand); }
.nvv-foot { align-items:center; gap:.5rem; }
/* El número de versión, al pie del menú de la persona. NO es un botón: las
   opciones de arriba son acciones y ésta es un dato, así que se ve como lo que
   es —un link chiquito, alineado a la derecha— y sin línea que lo separe, que
   sólo servía para darle el peso de una sección propia. */
/* Tan ancho como el texto y pegado a la derecha (no un bloque de todo el ancho
   con el texto corrido): el tooltip se centra sobre el elemento, y con el bloque
   entero quedaba en el medio del menú, lejos de "Versión". */
.nav-version { display:block; width:fit-content; margin-left:auto;
  padding:.15rem .7rem .1rem; border:none; background:none;
  text-align:right; font-family:inherit; font-size:.68rem; color:var(--muted-2);
  text-decoration:none; cursor:pointer; }
.nav-version:hover { color:var(--brand); text-decoration:underline; }
/* Sin notas escritas es un dato, no un link: no promete nada al pasarle por encima. */
span.nav-version { cursor:default; }
span.nav-version:hover { color:var(--muted-2); text-decoration:none; }

.modal-card {
  margin: auto;
  width: min(560px, 100%);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  /* Sin sombra: lo despega el fondo oscurecido de atrás y su borde. */
  overflow: hidden;
  /* Entrada: escala sutil + opacidad desde el centro (los modales no se anclan a un trigger). */
  transition: transform 200ms var(--ease-out), opacity 200ms var(--ease-out);
}
@starting-style {
  .modal-card { transform: scale(0.97); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .modal-card { transition: none; }
}

.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.85rem 1rem;
  border-bottom: 1px solid var(--line);
}

.modal-head h3 {
  font-size: 0.95rem;
  color: var(--text-2);
}

.modal-close {
  border: none;
  background: transparent;
  color: var(--muted);
  padding: 0.2rem 0.35rem;
  border-radius: var(--radius-sm);
}

.modal-close:hover {
  background: var(--panel-2);
  color: var(--text);
}

.modal-body {
  padding: 0.9rem 1rem;
  color: var(--text);
}

.modal-body p {
  margin: 0;
  font-size: 0.88rem;
  color: var(--text-2);
  line-height: 1.55;
}

.modal-form-grid {
  display: grid;
  gap: 0.6rem;
}

.modal-actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 0.5rem;
  padding: 0.85rem 1rem;
  border-top: 1px solid var(--line);
  background: var(--panel-2);
}

/* ── Nav user / logout ──────────────────────────────────────────────────── */
.nav-user {
  position: relative;
  padding-left: 0.55rem;
  border-left: 1px solid var(--line-2);
  margin-left: 0.35rem;
}

.nav-user-trigger {
  background: transparent;
  border: none;
  width: auto;
  height: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  position: relative;
  transition: transform var(--transition);
}

.nav-user-trigger:hover {
  transform: translateY(-1px);
}

.nav-avatar {
  position: relative;
  overflow: hidden;
  width: 1.6rem;
  height: 1.6rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  border: none;
  color: var(--on-brand);
  background: var(--brand);
  font-size: 0.64rem;
  font-weight: 700;
}

.nav-avatar-badge {
  position: absolute;
  top: -5px;
  right: -6px;
  min-width: 17px;
  height: 17px;
  padding: 0 4px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #ef4444;
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
  box-shadow: 0 0 0 2px var(--panel), 0 1px 3px rgba(0, 0, 0, 0.25);
  z-index: 2;
}

.nav-user-dropdown {
  position: absolute;
  top: calc(100% + 0.15rem);
  right: 0;
  z-index: 1200;
  min-width: 210px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  padding: 0.6rem;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  pointer-events: none;
  transition: opacity var(--transition), transform var(--transition), visibility var(--transition);
  transition-delay: 0.35s;   /* U1: gracia al salir, no se cierra al mover el mouse */
}

.nav-user-dropdown::before {
  content: '';
  position: absolute;
  top: -14px;
  left: 0;
  right: 0;
  height: 14px;              /* puente invisible que cubre TODO el gap trigger↔menú */
}

.nav-user:hover .nav-user-dropdown,
.nav-user-dropdown:hover {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  pointer-events: auto;
  transition-delay: 0s;      /* abre instantáneo */
}

.nav-user-name {
  font-size: 0.83rem;
  font-weight: 700;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nav-user-hint {
  font-size: 0.72rem;
  color: var(--muted);
  margin-bottom: 0.35rem;
}

.nav-user-meta-list {
  display: grid;
  gap: 0.2rem;
  margin-bottom: 0.45rem;
}

.nav-user-meta-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
}

.nav-user-meta-label {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted-2);
}

.nav-user-meta-value {
  max-width: 140px;
  font-size: 0.76rem;
  color: var(--text-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.nav-user-logout-form {
  margin: 0;
}

.nav-user-item,
.nav-user-logout {
  width: 100%;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  height: 34px;
  padding: 0 0.65rem;
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;
  gap: 0.5rem;
  font: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-2);
  cursor: pointer;
  text-decoration: none;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}

.nav-user-item:hover,
.nav-user-item:focus-visible {
  background: var(--panel-2);
  color: var(--text);
  border-color: var(--line-2);
}

.nav-user-item-badge {
  margin-left: auto;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #ef4444;
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.22);
}

.nav-user-logout:hover {
  background: var(--panel-2);
  color: var(--bad);
  border-color: #efb3b3;
}

/* ── LOGIN PAGE ─────────────────────────────────────────────────────────── */
html:has(> body.login-page) { overscroll-behavior: none; }
.login-page {
  /* Una pantalla fija: sin el rebote de arrastrar en el celular. */
  overscroll-behavior: none;
  min-height: 100vh;
  min-height: 100dvh;   /* en el celular 100vh cuenta la barra del navegador: sobraba y scrolleaba */
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
}

.login-shell {
  width: 100%;
  max-width: 400px;
  padding: 1.5rem;
}

.login-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
  padding: 2rem;
}

/* En el celular es una pantalla, no una tarjeta flotando: sin borde, sin
   sombra, sin el gris alrededor, de punta a punta. El contenido arranca un
   poco más abajo del borde y no centrado: con el teclado abierto, un
   formulario centrado se va para arriba y tapa el título. */
@media (max-width: 560px) {
  .login-page { align-items: stretch; background: var(--panel); }
  .login-shell { max-width: none; padding: 0; display: flex; }
  .login-card {
    flex: 1; border: none; border-radius: 0; box-shadow: none;
    padding: max(12vh, calc(env(safe-area-inset-top) + 2rem)) 1.35rem
             calc(env(safe-area-inset-bottom) + 2rem);
  }
  /* 16px: con menos, Safari del iPhone hace zoom al tocar el campo. */
  .login-card input, .login-card select, .login-card textarea { font-size: 16px; padding: .7rem .8rem; }
  .login-card .btn-full { padding-top: .75rem; padding-bottom: .75rem; }
}

.login-header {
  position: relative;
  text-align: center;
  margin-bottom: 1.75rem;
}

.login-back-btn {
  position: absolute;
  top: -0.35rem;
  left: -0.35rem;
  width: 32px;
  height: 32px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel-2);
  color: var(--text-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
  transition: background var(--transition), border-color var(--transition), color var(--transition), transform var(--transition);
}

.login-back-btn:hover {
  color: var(--text);
  border-color: var(--line-2);
  background: var(--panel);
  transform: translateX(-1px);
}

.login-brand {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  text-decoration: none;
  font-family: 'Sora', sans-serif;
  font-weight: 800;
  font-size: 1.25rem;
  color: var(--text);
}
.login-brand em { font-style: normal; color: #5c5c5c; font-weight: 500; }

.login-logo {
  width: 40px;
  height: 40px;
  object-fit: contain;
}

.login-subtitle {
  margin-top: 0.5rem;
  font-size: 0.875rem;
  color: var(--muted);
}

.login-info-dot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  margin-left: 0.3rem;
  border-radius: 999px;
  border: 1px solid var(--line-2);
  color: var(--muted);
  font-size: 0.67rem;
  font-weight: 700;
  vertical-align: middle;
  cursor: help;
}

.login-label-row {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}

.login-form {
  display: grid;
  gap: 0.75rem;
}

.login-error {
  background: var(--bad-light);
  color: var(--bad);
  border: 1px solid #fecaca;
  border-radius: var(--radius);
  padding: 0.6rem 0.875rem;
  font-size: 0.875rem;
  font-weight: 500;
  margin-bottom: 0.75rem;
}

.login-divider {
  margin: 0.95rem 0 0.85rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--muted-2);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.login-divider::before,
.login-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--line);
}

.login-helper {
  margin: 0.55rem 0 0;
  font-size: 0.78rem;
  color: var(--ok);
}

.login-helper.is-error {
  color: var(--bad);
}

.login-texto { margin: 0 0 1rem; line-height: 1.5; }
.login-nota { margin: .75rem 0 0; font-size: .8rem; color: var(--muted); text-align: center; }
.login-pie { margin: .6rem 0 0; text-align: center; font-size: .85rem; color: var(--muted); }

/* «Continuar con Google»: los colores son los de las guías de marca de Google
   para el botón de ingreso (claro: blanco con borde #747775; oscuro: #131314
   con borde #8e918f), no los tokens del portal. Es el único lugar donde entra
   otra marca, y entra así para que el botón se reconozca. */
.btn-google {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .65rem;
  width: 100%;
  min-height: 40px;
  padding: 0 12px;
  background: #fff;
  color: #1f1f1f;
  border: 1px solid #747775;
  border-radius: var(--radius);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: .01em;
  text-decoration: none;
  transition: background var(--transition), box-shadow var(--transition);
}
.btn-google:hover { background: #f8f9fa; box-shadow: 0 1px 2px rgba(60, 64, 67, .25); }
.btn-google:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.btn-google-g { flex: none; }
[data-theme="dark"] .btn-google { background: #131314; color: #e3e3e3; border-color: #8e918f; }
[data-theme="dark"] .btn-google:hover { background: #1f1f20; box-shadow: none; }

@keyframes submit-bounce-spin {
  to {
    transform: rotate(360deg);
  }
}

.btn-logo-spinner {
  width: 15px;
  height: 15px;
  object-fit: contain;
  border-radius: 999px;
  animation: submit-bounce-spin 700ms linear infinite;
}

@media (prefers-reduced-motion: reduce) {

  .btn-logo-spinner {
    animation: none;
  }
}

/* ── ADMIN USERS PAGE ───────────────────────────────────────────────────── */
.users-shell {
  max-width: 1100px;
  margin: 0 auto;
  padding: 1.75rem 1.25rem;
}

.users-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 1.25rem;
}

.users-title { font-size: 1.35rem; letter-spacing: -0.02em; }
.users-subtitle { font-size: 0.875rem; color: var(--muted); margin-top: 0.2rem; }

.users-tabs {
  display: flex;
  gap: 0.25rem;
  border-bottom: 1px solid var(--line);
  margin-bottom: 1.25rem;
}

.users-tab {
  background: transparent;
  border: none;
  padding: 0.55rem 1rem;
  font: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color var(--transition), border-color var(--transition);
}

.users-tab:hover { color: var(--text); }
.users-tab.active { color: var(--brand); border-bottom-color: var(--brand); }

.tab-panel { display: none; }
.tab-panel.active { display: block; }

.audit-pagination {
  margin-top: 0.85rem;
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.audit-page-info {
  font-size: 0.8rem;
  color: var(--muted);
}

.audit-pagination .btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.table-wrap { overflow: visible; }

.users-table-wrap { overflow: visible; }

.tab-panel { overflow: visible; }

.users-table-wrap {
  overflow: visible;
}

.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}
.data-table th {
  text-align: left;
  padding: 0.5rem 0.75rem;
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.data-table td {
  padding: 0.6rem 0.75rem;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}
.data-table tr:last-child td { border-bottom: none; }
.data-table tr:hover td { background: var(--panel-2); }

/* Usuarios en el celular: cinco columnas no entran en 375px y la tabla
   empujaba la página hacia el costado. Cada fila pasa a ser un bloque: el
   nombre y el mail arriba, lo demás (estado, rol, cómo, cuándo) en una línea,
   y las acciones abajo. Sirve igual para solicitudes e invitaciones. */
@media (max-width: 640px) {
  .users-table-wrap .data-table thead { display: none; }
  .users-table-wrap .data-table,
  .users-table-wrap .data-table tbody { display: block; }
  .users-table-wrap .data-table tr {
    display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .6rem;
    padding: .8rem 0; border-bottom: 1px solid var(--line);
  }
  .users-table-wrap .data-table tr:last-child { border-bottom: none; }
  .users-table-wrap .data-table td { display: block; padding: 0; border: none; background: none; }
  .users-table-wrap .data-table tr:hover td { background: none; }
  .users-table-wrap .data-table td:first-child { flex-basis: 100%; }
  .users-table-wrap .data-table td:nth-child(2) { flex-basis: 100%; color: var(--muted); overflow-wrap: anywhere; }
  .users-table-wrap .data-table td:last-child { flex-basis: 100%; margin-top: .3rem; }
  .users-table-wrap .data-table td:last-child .btn { min-height: 40px; }
}

.dot {
  width: 12px;
  height: 12px;
  border-radius: 999px;
  display: inline-block;
  margin-right: 0.55rem;
  vertical-align: middle;
}

#usersTable {
  width: 100%;
  table-layout: fixed;
}

#usersTable th:nth-child(1),
#usersTable td:nth-child(1) {
  width: 20%;
}

#usersTable th:nth-child(2),
#usersTable td:nth-child(2) {
  width: 24%;
}

#usersTable th:nth-child(3),
#usersTable td:nth-child(3) {
  width: 10%;
}

#usersTable th:nth-child(4),
#usersTable td:nth-child(4) {
  width: 10%;
}

#usersTable th:nth-child(5),
#usersTable td:nth-child(5) {
  width: 12%;
}

#usersTable th:nth-child(6),
#usersTable td:nth-child(6) {
  width: 24%;
  white-space: nowrap;
}

.user-actions-menu {
  position: relative;
  display: inline-block;
}

.user-actions-menu > summary {
  list-style: none;
  -webkit-user-select: none;
  user-select: none;
}

.user-actions-menu > summary::-webkit-details-marker {
  display: none;
}

.user-actions-popover {
  position: absolute;
  left: 0;
  top: calc(100% + 0.35rem);
  z-index: 1200;
  min-width: 180px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  padding: 0.4rem;
  display: grid;
  gap: 0.3rem;
}

.user-actions-popover .btn {
  justify-content: flex-start;
}

.row-actions { display: flex; gap: 0.3rem; justify-content: flex-end; white-space: nowrap; }

.check-list { display: grid; gap: 0.35rem; max-height: 300px; overflow-y: auto; }
.check-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  font-weight: 400;
  color: var(--text);
  cursor: pointer;
  padding: 0.2rem 0;
}
.check-item input[type=checkbox] { width: auto; accent-color: var(--brand); }

.inline-check {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  font-weight: 500;
}

.inline-check input[type=checkbox] {
  width: auto;
  margin: 0;
  flex-shrink: 0;
}

/* ── Variantes de oscuro ─────────────────────────────────────────────────
   La de arriba (gris neutro) es la que va sin elegir nada. Estas dos se ponen
   desde el menu del usuario y solo pisan los tokens. */

/* "Blue Ocean": el azul marino que tenia el portal antes del oscuro neutro. */
[data-theme="dark"][data-dark="oceano"] {
  --bg:      #0d1520;
  --panel:   #16202e;
  --panel-2: #111b28;
  --line:    #1e2e42;
  --line-2:  #263d58;
  --text:    #dde8f4;
  --text-2:  #b8cfe8;
  --muted:   #6b8fae;
  --muted-2: #4a6a88;

  --ok-light:      #071a12;
  --bad-light:     #1c0a0a;
  --warn-light:    #1a1205;
  --accent-light:  #1a1408;
}

/* "Midnight": la paleta oscura de GitHub. Azul muy desaturado, casi gris. */
[data-theme="dark"][data-dark="midnight"] {
  --bg:      #0d1117;
  --panel:   #161b22;
  --panel-2: #10161d;
  --line:    #30363d;
  --line-2:  #444c56;
  --text:    #e6edf3;
  --text-2:  #c9d1d9;
  --muted:   #8d96a0;
  --muted-2: #6e7681;

  --ok-light:      #0f2417;
  --bad-light:     #2a1618;
  --warn-light:    #241c0c;
  --accent-light:  #1c1a0e;
}

/* Variante de acento con matiz variable. Los fondos son los de Midnight; lo unico
   que cambia es el color de marca.

   Ojo con la degradacion: una custom property NO se valida al declararse, asi que
   un valor que el navegador no entiende igual se guarda y recien explota donde se
   usa — ahi `color: var(--brand)` cae al color heredado. Por eso `--arco` se
   declara siempre (si no, sin @property el calc queda vacio) y los colores van
   primero en hsl, con oklch pisando solo adentro de un @supports. */
/* El matiz lo mueve el JS y no una animacion de CSS. Motivo: animando la custom
   property, Chromium repinta los FONDOS que la usan pero no siempre el color de
   TEXTO de los descendientes — el valor calculado cambiaba y en pantalla quedaba
   el color viejo (se veia en Brave: los botones cambiaban y el texto no).
   Escribiendola desde JS el recalculo invalida a todos por igual. */
@property --arco { syntax: '<number>'; inherits: true; initial-value: 0; }

[data-theme="dark"][data-dark="arcoiris"] {
  --arco: 0;
  /* Los grises son los de Midnight: sobre ese fondo mas frio el matiz que rota se
     despega mas que sobre el gris parejo de Darkcula. */
  --bg:      #0d1117;
  --panel:   #161b22;
  --panel-2: #10161d;
  --line:    #30363d;
  --line-2:  #444c56;
  --text:    #e6edf3;
  --text-2:  #c9d1d9;
  --muted:   #8d96a0;
  --muted-2: #6e7681;

  --brand:       hsl(calc(var(--arco) * 1deg) 85% 72%);
  --brand-hover: hsl(calc(var(--arco) * 1deg) 85% 64%);
  --brand-mid:   hsl(calc(var(--arco) * 1deg) 85% 68%);
  --brand-light:   hsl(calc(var(--arco) * 1deg) 30% 16%);
  --brand-light-2: hsl(calc(var(--arco) * 1deg) 32% 24%);
  /* El color va claro y vivo, asi que encima va texto oscuro: es lo que se lee en
     TODOS los matices, y de paso hace que se vea como un highlighter. */
  --on-brand: #0d1117;
}
/* oklch cuando se puede: su L es PERCEPTUAL, asi que con L fija todos los matices
   se ven igual de claros. Con hsl al 72% el amarillo queda brillante y el azul mas
   oscuro — se lee igual, pero no parejo. */
@supports (color: oklch(0.5 0.1 0deg)) {
  [data-theme="dark"][data-dark="arcoiris"] {
    --brand:       oklch(0.78 0.17 calc(var(--arco) * 1deg));
    --brand-hover: oklch(0.72 0.17 calc(var(--arco) * 1deg));
    --brand-mid:   oklch(0.75 0.17 calc(var(--arco) * 1deg));
    --brand-light:   oklch(0.26 0.06 calc(var(--arco) * 1deg));
    --brand-light-2: oklch(0.34 0.09 calc(var(--arco) * 1deg));
  }
}
/* La paleta del modo oscuro esta arriba del todo, con el resto de los tokens.
   Aca quedan solo los ajustes puntuales que no se pueden expresar con variables. */
[data-theme="dark"] .topbar {
  /* Sale del fondo del tema, no de un rgba escrito a mano: cada variante repetia
     su propia regla y la que se agregaba sin ella quedaba con el color de otra
     paleta — paso con arcoiris. Asi cualquier tono nuevo funciona solo. */
  background: var(--bg);
  border-bottom-color: var(--line);
}

[data-theme="dark"] .md-body pre { background: #171717; border-color: #2f2f2f; }

/* ── Utility ────────────────────────────────────────────────────────────── */
/* Iconitos inline al lado de un texto (miembros, proyectos, fechas). Van con el
   mismo trazo que el resto del portal y heredan el color del texto — que es lo que
   un emoji no hace: viene con color propio y en modo oscuro queda como calcomania. */
.ic { display: inline-block; vertical-align: -2px; margin-right: .15rem; flex-shrink: 0; }

/* ── Apariencia: tema + tono, en un popover del navbar ─────────────────── */
.ap-wrap { position: relative; display: inline-flex; }
.ap-pop { position: absolute; top: calc(100% + 8px); right: 0; z-index: 1150; min-width: 11.5rem;
  padding: .3rem; border: 1px solid var(--line); border-radius: .65rem; background: var(--panel);
  box-shadow: 0 10px 30px rgba(0,0,0,.16); }
.ap-opt { display: flex; align-items: center; gap: .55rem; width: 100%; padding: .4rem .5rem;
  border: none; border-radius: .45rem; background: none; cursor: pointer; font-family: inherit;
  font-size: .82rem; color: var(--text); text-align: left; }
.ap-opt span { flex: 1; }
.ap-opt:hover { background: var(--panel-2); }
.ap-opt svg:first-child { color: var(--muted); flex-shrink: 0; }
/* El tilde marca el activo sin mover nada: siempre esta, cambia la opacidad. */
.ap-tilde { color: var(--brand); opacity: 0; flex-shrink: 0; }
.ap-opt[aria-checked="true"] { color: var(--brand); font-weight: 600; }
.ap-opt[aria-checked="true"] svg:first-child { color: var(--brand); }
.ap-opt[aria-checked="true"] .ap-tilde { opacity: 1; }
.ap-sep { margin-top: .3rem; padding-top: .4rem; border-top: 1px solid var(--line); }
/* En claro las muestras se ven igual de nitidas: atenuarlas con opacity las volvia
   el mismo gris (son tres colores oscuros sobre fondo blanco) y no se distinguia
   ninguna. Tocar una estando en claro pasa a oscuro sola, asi que no hay nada que
   deshabilitar. */
.ap-sep--off .ap-tit { color: var(--muted-2); }

/* ── Avisos de escritorio ──────────────────────────────────────────────────
   El estado del ítem en el menú de la persona ("Activados" / "Activar"), y la
   línea que explica por qué no se puede cuando no se puede. */
/* El interruptor: verde prendido, rojo apagado, y la bolita se corre. Una
   palabra al costado («ACTIVADOS») decía el estado pero no que se podía tocar;
   esto se lee de un vistazo y se entiende solo. */
.nav-notif { white-space: nowrap; }
.sw-riel { margin-left: auto; position: relative; flex-shrink: 0;
  width: 2.1rem; height: 1.15rem; border-radius: 999px;
  background: var(--danger); transition: background .16s ease; }
.sw-bola { position: absolute; top: 2px; left: 2px;
  width: calc(1.15rem - 4px); height: calc(1.15rem - 4px); border-radius: 50%;
  background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.25);
  transition: transform .16s ease; }
.nav-notif[aria-checked="true"] .sw-riel { background: var(--ok); }
.nav-notif[aria-checked="true"] .sw-bola { transform: translateX(.95rem); }
/* Bloqueado en el navegador: ni verde ni rojo, porque no es un estado que la
   persona pueda cambiar desde acá. La nota de abajo dice por qué. */
.nav-notif:disabled { cursor: default; }
.nav-notif:disabled .sw-riel { background: var(--line-2); }
/* Sin movimiento para quien pidió menos animación: el color y la posición
   siguen diciendo lo mismo. */
@media (prefers-reduced-motion: reduce) {
  .sw-riel, .sw-bola { transition: none; }
}
/* El «!» que reemplaza al interruptor cuando no se puede activar. En rojo: no
   es una aclaración que se puede leer o no, es que los avisos NO van a llegar y
   hay que hacer algo para que lleguen. El motivo va en el tooltip, que es lo que
   no entra en un renglón de menú. */
.nav-avisos-i { margin-left: auto; flex-shrink: 0; display: inline-flex;
  color: var(--danger); }

/* La invitación: una barra bajo el encabezado. Ocupa lugar y empuja la página a
   propósito — un cartel que no se ve no invita a nada— pero se va con un click
   y no vuelve. Nada de superponerla al contenido: taparle a alguien lo que
   estaba leyendo para ofrecerle algo es la forma más rápida de que lo cierre
   sin leerlo. */
.av-invita { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap;
  padding: .6rem 1.25rem; border-bottom: 1px solid var(--line);
  background: color-mix(in srgb, var(--brand) 7%, var(--panel)); }
.av-invita-ico { color: var(--brand); flex-shrink: 0; }
.av-invita-txt { margin: 0; flex: 1; min-width: 12rem; font-size: .82rem;
  line-height: 1.45; color: var(--text); }
.av-invita-txt strong { font-weight: 700; }
.av-invita-no { border: none; background: none; font-family: inherit; font-size: .8rem;
  color: var(--muted); cursor: pointer; padding: .35rem .5rem; border-radius: .4rem; }
.av-invita-no:hover { background: var(--panel-2); color: var(--text); }
/* Y si el intento falló, el mismo cartel dice por qué: es lo que la persona
   está mirando cuando pasa. */
.av-invita--mal { background: color-mix(in srgb, var(--danger) 8%, var(--panel)); }
.av-invita--mal .av-invita-ico { color: var(--danger); }
.av-invita--mal .av-invita-txt { color: var(--danger); }
.ap-tit { padding: 0 .5rem .3rem; font-size: .64rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .05em; color: var(--muted-2); }
.ap-tonos { display: flex; flex-direction: column; gap: .1rem; padding: 0 .2rem .2rem; }
.ap-tono { display: flex; align-items: center; gap: .5rem; width: 100%; padding: .3rem .35rem;
  border: 1px solid transparent; border-radius: .45rem; background: none; cursor: pointer;
  font-family: inherit; font-size: .78rem; color: var(--text); text-align: left; }
.ap-tono:hover { background: var(--panel-2); }
.ap-tono[aria-pressed="true"] { border-color: var(--brand); color: var(--brand); font-weight: 600; }
.ap-tono-txt { flex: 1; }
/* Mini-mockup en vez de un cuadrado liso: lo que distingue una paleta no es el tono
   en si (los tres fondos difieren un 3%) sino el salto entre sus capas. */
.ap-mini { width: 34px; height: 22px; border-radius: .28rem; flex-shrink: 0; padding: 3px;
  box-sizing: border-box; display: block; border: 1px solid rgba(255,255,255,.13); }
.ap-mini-card { display: block; height: 100%; border-radius: .18rem; border: 1px solid;
  padding: 3px 3px 0; box-sizing: border-box; }
.ap-mini-card i { display: block; height: 2px; border-radius: 2px; margin-bottom: 2px; }
.ap-mini-card i:first-child { width: 72%; }
.ap-mini-card i:last-child { width: 45%; }
.ap-mini--arco { background: linear-gradient(100deg, #f87171, #fbbf24, #4ade80, #38bdf8, #a78bfa, #f472b6); }

.hidden { display: none !important; }
.empty-state { color: var(--muted); font-size: 0.8125rem; text-align: center; padding: 1rem; }

.panel-card{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:.9rem;}

.progress{margin-top:.38rem;width:100%;height:8px;border-radius:999px;background:#e7edf5;}
.progress span{display:block;height:8px;border-radius:999px;background:linear-gradient(90deg,var(--brand),var(--brand-mid,var(--brand)));}

.timeline-pagination{margin-top:auto;display:flex;justify-content:center;align-items:center;gap:.75rem;padding-top:.6rem;}

/* ── Back button bar ────────────────────────────────────────── */
.page-back-bar { padding: .6rem 1.5rem 0; }
.page-back-bar:empty { display: none; }
.back-link {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  font-size: .82rem;
  font-weight: 500;
  color: var(--muted);
  text-decoration: none;
  padding: .3rem .55rem;
  border-radius: .4rem;
  transition: background .15s, color .15s;
  border: 1px solid transparent;
}
.back-link:hover { background: var(--line); color: var(--text); border-color: var(--line); }
.back-link svg { flex-shrink: 0; }

/* ── Action menu (⋮ dropdown) ───────────────────────────────── */
.action-menu-wrap{position:relative;}
.action-menu-trigger{background:none;border:none;cursor:pointer;color:var(--muted);font-size:1.1rem;line-height:1;padding:.1rem .35rem;border-radius:.35rem;transition:background .15s,color .15s;}
.action-menu-trigger:hover{background:var(--line);color:var(--text);}
/* Ícono ℹ de metadata de una tarea (macro task_info) */
.task-info-i{display:inline-flex;align-items:center;justify-content:center;color:var(--muted-2);cursor:help;vertical-align:middle;margin-left:.3rem;transition:color .15s;}
.task-info-i:hover,.task-info-i:focus{color:var(--brand);outline:none;}
/* Foto de perfil (macro avatar_photo): tapa las iniciales del avatar contenedor */
.av-photo{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;border-radius:inherit;display:block;}

@keyframes avz-in{from{opacity:0;}to{opacity:1;}}

/* Onboarding: modal de bienvenida + tour de pasos */
.tut-card{animation:avz-in .14s ease;}
.tut-welcome{background:var(--panel);border:1px solid var(--line);border-radius:1.1rem;box-shadow:0 20px 60px rgba(0,0,0,.22);width:min(92vw,380px);padding:2rem 1.75rem 1.6rem;text-align:center;animation:avz-in .16s ease;}
.tut-welcome-ico{width:56px;height:56px;margin:0 auto 1.1rem;border-radius:50%;display:flex;align-items:center;justify-content:center;color:var(--brand);background:color-mix(in srgb,var(--brand) 12%,transparent);box-shadow:0 0 0 6px color-mix(in srgb,var(--brand) 6%,transparent);}
.tut-welcome-ico svg{width:26px;height:26px;}
.tut-welcome-title{margin:0 0 .35rem;font-size:1.18rem;font-weight:700;letter-spacing:-.01em;}
.tut-welcome-sub{margin:0 0 1.5rem;color:var(--muted);font-size:.9rem;line-height:1.55;}
.tut-welcome-btns{display:flex;gap:.6rem;}
.tut-welcome-btns .btn{flex:1;justify-content:center;}
/* Panel colapsable (arranca contraído; se abre al pasar el mouse o al hacer click para fijarlo) */
.hover-collapse-head { cursor:pointer; user-select:none; }
.hover-collapse-hint { display:inline-flex; align-items:center; gap:.4rem; font-size:.78rem; color:var(--muted); }
.hover-collapse-chevron { transition:transform .22s cubic-bezier(.34,1.56,.64,1); }
.hover-collapse-body { max-height:0; opacity:0; overflow:hidden; transform:translateY(-4px); transform-origin:top; transition: max-height .35s cubic-bezier(.34,1.36,.64,1), opacity .18s ease, transform .25s ease; }
.hover-collapse:hover .hover-collapse-body,
.hover-collapse.is-pinned .hover-collapse-body { max-height:1600px; opacity:1; transform:translateY(0); }
.hover-collapse:hover .hover-collapse-chevron,
.hover-collapse.is-pinned .hover-collapse-chevron { transform:rotate(180deg); }

/* Notas de proyecto. Namespace .pjn- para NO chocar con las notas privadas. */
.pjn-form { display:flex; flex-direction:column; gap:.5rem; margin:0 0 1.2rem; }
.pjn-form-foot { display:flex; align-items:center; gap:.9rem; flex-wrap:wrap; }
.pjn-vis { display:inline-flex; align-items:center; gap:.3rem; font-size:.82rem; color:var(--text); cursor:pointer; }
.pjn-vis input { flex:none; width:auto; margin:0; }
.pjn-feed { display:flex; flex-direction:column; gap:.55rem; margin-top:.2rem; }
.pjn-item { position:relative; display:flex; gap:.65rem; padding:.7rem .85rem; border:1px solid var(--line); border-radius:.6rem; background:var(--panel); }
.pjn-item--public { border-left:3px solid #16a34a; }
.pjn-item--private { border-left:3px solid #7c3aed; }
.pjn-av { position:relative; overflow:hidden; flex:none; width:32px; height:32px; border-radius:50%; display:flex; align-items:center; justify-content:center; font-size:.7rem; font-weight:700; font-family:'Sora',sans-serif; color:var(--muted); background:var(--panel-2); }
.pjn-item--private .pjn-av { color:#6d28d9; background:#ede9fe; }
.pjn-item--public .pjn-av { color:#15803d; background:color-mix(in srgb,#15803d 12%,transparent); }
.pjn-body { flex:1; min-width:0; padding-right:1.6rem; }
.pjn-meta { display:flex; align-items:center; gap:.5rem; flex-wrap:wrap; margin-bottom:.25rem; }
.pjn-meta strong { font-size:.84rem; color:var(--text); }
.pjn-chip { flex:none; font-size:.62rem; font-weight:700; text-transform:uppercase; letter-spacing:.03em; padding:.06rem .4rem; border-radius:999px; }
.pjn-chip--public { color:#15803d; background:color-mix(in srgb,#15803d 12%,transparent); }
.pjn-chip--private { color:#6d28d9; background:#ede9fe; }
[data-theme="dark"] .pjn-chip--private { background:#7c3aed22; color:#c4b5fd; }
.pjn-ts { font-size:.72rem; color:var(--muted-2); }
.pjn-actions { position:absolute; top:.55rem; right:.55rem; display:flex; gap:.15rem; opacity:0; transition:opacity .12s; }
.pjn-item:hover .pjn-actions, .pjn-actions:focus-within { opacity:1; }
.pjn-act { border:none; background:transparent; color:var(--muted-2); cursor:pointer; font-size:.8rem; padding:.15rem .35rem; border-radius:.4rem; transition:color .12s,background .12s; }
.pjn-act:hover { color:var(--brand); background:var(--panel-2); }
.pjn-act--danger:hover { color:var(--danger); background:color-mix(in srgb,var(--danger) 10%,transparent); }
.pjn-text { margin:0; font-size:.88rem; color:var(--text); line-height:1.5; white-space:pre-wrap;
  overflow-wrap:anywhere; }
.pjn-edit { display:flex; flex-direction:column; gap:.5rem; margin-top:.5rem; }

/* Botón sutil para relanzar el recorrido */
.tut-replay{position:fixed;right:18px;bottom:calc(18px + var(--tabbar-h, 0px));width:34px;height:34px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:var(--panel);color:var(--muted-2);border:1px solid var(--line);box-shadow:0 3px 12px rgba(0,0,0,.1);cursor:pointer;z-index:1100;opacity:.65;transition:opacity .15s,color .15s,border-color .15s,transform .15s;}
.tut-replay:hover{opacity:1;color:var(--brand);border-color:color-mix(in srgb,var(--brand) 45%,var(--line));transform:translateY(-1px);}
.tut-replay svg{width:18px;height:18px;}

/* Animación de "llenado" de una barra de progreso durante un paso del tour */
.tut-fill-anim > span, .tut-fill-anim span { animation: tutFill 2.4s ease-in-out infinite; }
@keyframes tutFill { 0%{width:2%} 45%{width:72%} 80%{width:72%} 100%{width:2%} }
/* Contenido de ejemplo inyectado por el tour: entra con un fade/slide suave */
[data-tut-demo] .pd-task { animation: tutDemoIn .45s ease both; }
[data-tut-demo] .pd-task:nth-child(2){ animation-delay:.12s; }
[data-tut-demo] .pd-task:nth-child(3){ animation-delay:.24s; }
@keyframes tutDemoIn { from{ opacity:0; transform:translateY(8px); } to{ opacity:1; transform:none; } }

/* Tour anclado (coach-marks): globo oscuro con flecha, spotlight sobre el elemento */
.tut-overlay{position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:1200;animation:avz-in .15s ease;}
/* Con un elemento resaltado, el velo lo dibuja la sombra de .tut-ring, que tiene
   pointer-events:none: se veia tapado pero se podia clickear todo lo de atras.
   Esta variante no pinta nada y solo esta para atrapar los clicks. */
.tut-overlay--clear{background:transparent;animation:none;}
.tut-ring{position:fixed;z-index:1201;border-radius:10px;pointer-events:none;box-shadow:0 0 0 2px color-mix(in srgb,var(--brand) 85%,transparent),0 0 0 9999px rgba(0,0,0,.55),0 0 18px 2px color-mix(in srgb,var(--brand) 45%,transparent);transition:left .2s ease,top .2s ease,width .2s ease,height .2s ease;}
/* Durante un paso del tour, el modal cede su velo: lo pinta el ring, para que ese
   paso se vea igual de oscuro que todos los demas. */
.modal-backdrop.tut-sin-velo{background:transparent;}
.tut-coach{position:fixed;z-index:1203;width:min(90vw,320px);background:#262626;color:#e6e6e4;border-radius:12px;padding:.85rem 1rem 1rem;box-shadow:0 14px 44px rgba(0,0,0,.4);animation:avz-in .16s ease;}
[data-theme="dark"] .tut-coach{background:#27272a;}
.tut-coach-arrow{position:absolute;width:12px;height:12px;background:inherit;transform:rotate(45deg);border-radius:2px;}
.tut-coach-arrow--up{top:-6px;}
.tut-coach-arrow--down{bottom:-6px;}
.tut-coach-top{display:flex;align-items:center;justify-content:space-between;margin-bottom:.4rem;}
.tut-coach-badge{font-size:.66rem;font-weight:700;letter-spacing:.02em;color:var(--on-brand);background:var(--brand);border-radius:999px;padding:.12rem .5rem;}
.tut-coach-x{background:none;border:0;color:#9b9b98;font-size:.85rem;line-height:1;cursor:pointer;padding:2px 3px;border-radius:5px;}
.tut-coach-x:hover{color:#e6e6e4;background:rgba(255,255,255,.08);}
.tut-coach-title{margin:0 0 .3rem;font-size:.94rem;font-weight:700;color:#fff;}
.tut-coach-body{font-size:.82rem;line-height:1.5;color:#c9c9c6;}
.tut-coach-body b{color:#fff;font-weight:600;}
.tut-coach-foot{display:flex;align-items:center;justify-content:space-between;gap:.6rem;margin-top:.9rem;}
.tut-dots{display:flex;gap:.35rem;align-items:center;}
.tut-dot{width:6px;height:6px;border-radius:50%;background:#4a4a4a;transition:background .15s,transform .15s;}
.tut-dot--on{background:var(--brand);transform:scale(1.3);}
/* Tour largo: los puntitos se vuelven una mancha, asi que pasan a ser una barra.
   Ocupa lo mismo y se lee igual con 8 pasos que con 50. */
.tut-dots--barra{flex:1;height:4px;border-radius:99px;background:#4a4a4a;overflow:hidden;margin-right:.6rem;}
.tut-dots--barra > span{display:block;height:100%;border-radius:99px;background:var(--brand);transition:width .18s ease;}
.tut-coach-btns{display:flex;gap:.4rem;}
.tut-coach-btn{font-size:.76rem;font-weight:600;border:1px solid #4a4a4a;background:transparent;color:#e6e6e4;border-radius:7px;padding:.32rem .7rem;cursor:pointer;transition:background .12s,border-color .12s;}
.tut-coach-btn:hover{background:rgba(255,255,255,.09);}
.tut-coach-btn--primary{background:var(--brand);border-color:var(--brand);color:var(--on-brand);}
.tut-coach-btn--primary:hover{background:var(--brand);filter:brightness(1.1);}
.action-menu-dropdown{position:absolute;right:0;top:calc(100% + 4px);background:var(--panel);border:1px solid var(--line);border-radius:.5rem;min-width:150px;z-index:200;box-shadow:0 4px 16px rgba(0,0,0,.14);overflow:hidden;
  transform-origin:top right;transition:transform 150ms var(--ease-out),opacity 150ms var(--ease-out),display 150ms allow-discrete;}
@starting-style{.action-menu-dropdown:not(.hidden){opacity:0;transform:scale(0.96);}}
@media (prefers-reduced-motion:reduce){.action-menu-dropdown{transition:none;}}
.action-menu-item{display:block;width:100%;background:none;border:none;text-align:left;padding:.55rem .85rem;font-size:.85rem;color:var(--text);cursor:pointer;transition:background .12s;white-space:nowrap;text-decoration:none;}
.action-menu-item:hover{background:var(--line);}
.action-menu-item--danger{color:var(--danger-2);font-weight:600;}
.action-menu-item--danger:hover{background:#fff5f5;color:var(--danger);}
.action-menu-dropdown form{margin:0;}
@media (prefers-color-scheme:dark){.action-menu-item--danger:hover{background:#2b1515;color:#f87171;}}

.text-muted{color:var(--muted);}

/* ── Modal form fields ──────────────────────────────────────── */
.form-label{display:block;font-size:.78rem;font-weight:700;color:var(--muted);margin-bottom:.25rem;text-transform:uppercase;letter-spacing:.04em;}
.form-input{background:var(--panel);border:1px solid var(--line);border-radius:8px;color:var(--text);padding:.45rem .65rem;font-size:.9rem;width:100%;box-sizing:border-box;font-family:inherit;}
.form-input:focus{outline:2px solid var(--brand);outline-offset:1px;}
textarea.form-input{resize:vertical;}

/* Input con botón "x" para limpiar (reutilizable: ver macro clearable_input) */
.input-clear-wrap{position:relative;display:block;}
.input-clear-wrap .form-input{padding-right:2.1rem;}
.input-clear{position:absolute;top:50%;right:.45rem;transform:translateY(-50%);display:none;
  border:none;background:transparent;color:var(--muted);cursor:pointer;font-size:1.15rem;line-height:1;
  padding:0 .25rem;border-radius:50%;transition:background .12s,color .12s;}
.input-clear:hover{background:var(--panel-2);color:var(--text);}
/* La "x" aparece solo cuando el input tiene texto */
.input-clear-wrap input:not(:placeholder-shown) ~ .input-clear{display:block;}
select.form-input{appearance:auto;}

      
/* ── Modal de detalle de tarea ──────────────────────────────────────────
   Vive aca y no en project_detail.html: el detalle se inyecta por fetch y lo
   abre también el enlace compartido. */
/* Modal de detalle de tarea */
  .pd-task-name--link { cursor:pointer; }
  .pd-task-name--link:hover { text-decoration:underline; text-decoration-color:var(--line-2); text-underline-offset:2px; }
  .tm-card { max-width:880px; width:min(880px,100%); }
  /* Mientras la tarjeta se mueve, el blur del velo se recalcula en CADA cuadro
     sobre toda la pantalla: es lo más caro de la animación y lo primero que se
     nota en una máquina con video integrado. Se apaga durante el movimiento. */
  #taskModal.tm-animando { backdrop-filter:none; -webkit-backdrop-filter:none; }
  /* Y la transición CSS de .modal-card no puede correr a la vez que la nuestra:
     eran dos animaciones peleándose por el mismo transform. */
  #taskModal.tm-animando .modal-card { transition:none; }

  /* El esqueleto: el modal se abre YA con esto y el detalle entra cuando llega.
     Ocupa parecido al detalle real para que no haya salto al reemplazarlo. */
  .tm-esq { display:grid; grid-template-columns:minmax(0,1fr) 15.5rem; gap:1.6rem 2rem;
    align-items:start; min-height:22rem; }
  @media (max-width: 820px) { .tm-esq { grid-template-columns:minmax(0,1fr); min-height:16rem; } }
  .tm-esq-col { display:flex; flex-direction:column; gap:.9rem; min-width:0; }
  .tm-esq-l { height:.85rem; border-radius:.4rem; background:var(--panel-2);
    animation:tm-esq-late 1.2s ease-in-out infinite; }
  @keyframes tm-esq-late { 50% { opacity:.45; } }
  /* Sin movimiento se ve igual, pero quieto: un latido infinito es justo lo que
     molesta a quien pidió menos animación. */
  @media (prefers-reduced-motion: reduce) { .tm-esq-l { animation:none; } }
  .tm-esq-error { margin:0; padding:2rem; text-align:center; color:var(--muted); }
  /* Dos columnas: a la izquierda lo que se lee y se escribe, a la derecha las
     propiedades. En una sola había que scrollear medio modal para ver quién era
     responsable. Abajo de 820px vuelve a una sola: al lado no entra. */
  .tm-grid { display:grid; grid-template-columns:minmax(0,1fr) 15.5rem; gap:1.6rem 2rem;
    align-items:start; }
  .tm-col { min-width:0; display:flex; flex-direction:column; gap:1.35rem; }
  .tm-side { display:flex; flex-direction:column; gap:1.15rem; min-width:0; }
  @media (max-width: 820px) { .tm-grid { grid-template-columns:minmax(0,1fr); }
  }
  /* «Me gusta» de un comentario. Apagado es un contorno gris que casi no se ve:
     tiene que estar disponible sin competir con el texto, que es lo que se vino
     a leer. Prendido se llena y toma el color de marca. */
  .tm-c-pie { display:flex; align-items:center; gap:.4rem; margin-top:.25rem; }
  .tm-like { display:inline-flex; align-items:center; gap:.28rem; padding:.15rem .4rem;
    border:none; border-radius:.4rem; background:none; cursor:pointer;
    font-family:inherit; font-size:.72rem; color:var(--muted-2);
    transition:color .14s, background .14s; }
  .tm-like:hover { color:var(--brand); background:var(--panel-2); }
  .tm-like--on { color:var(--brand); }
  .tm-like--on svg { fill:currentColor; }
  .tm-like-n { font-weight:700; font-variant-numeric:tabular-nums; }
  /* La manito late UNA vez al marcarlo: es la confirmación de que agarró, sin
     tener que mirar el número. */
  .tm-like--late svg { animation:tm-like-pum .32s ease; }
  @keyframes tm-like-pum { 40% { transform:scale(1.35); } }
  @media (prefers-reduced-motion: reduce) { .tm-like--late svg { animation:none; } }
  /* Copiar el link de la tarea: un ícono discreto al lado del estado, que al
     copiar se vuelve un tilde con la palabra «Copiado» al costado. */
  .tm-copiar { display:inline-flex; align-items:center; gap:.3rem; flex-shrink:0;
    padding:.3rem .4rem; border:none; border-radius:.45rem; background:none; cursor:pointer;
    font-family:inherit; color:var(--muted-2); transition:color .15s, background .15s; }
  .tm-copiar:hover { color:var(--brand); background:var(--panel-2); }
  .tm-copiar-listo { display:none; }
  .tm-copiar-txt { font-size:.72rem; font-weight:600; }
  .tm-copiar-txt:empty { display:none; }
  .tm-copiar--ok, .tm-copiar--ok:hover { color:var(--ok); }
  .tm-copiar--ok .tm-copiar-ico { display:none; }
  .tm-copiar--ok .tm-copiar-listo { display:inline; }
  /* ── Chips con buscador ────────────────────────────────────────────
     Chips con lo elegido y un desplegable que suma (los usa «Editar proyecto»). */
  .sec-campo { display:flex; flex-direction:column; gap:.45rem; }
  .sec-chips { display:flex; flex-wrap:wrap; gap:.35rem; }
  .sec-chips:empty { display:none; }
  .sec-chip { display:inline-flex; align-items:center; gap:.15rem; padding:.18rem .2rem .18rem .6rem;
    border-radius:999px; border:1px solid var(--line); background:var(--panel-2);
    font-size:.78rem; font-weight:600; color:var(--text); }
  .sec-chip-x { border:none; background:none; cursor:pointer; color:var(--muted-2); font-size:.95rem;
    line-height:1; padding:.05rem .3rem; border-radius:999px; }
  .sec-chip-x:hover { color:var(--danger); background:color-mix(in srgb, var(--danger) 10%, transparent); }
  /* La lista de opciones: cinco a la vista y el resto se scrollea. */
  .sec-panel { border:1px solid var(--line); border-radius:.5rem; background:var(--panel); overflow:hidden; }
  .sec-ops { max-height:calc(5 * 2.3rem); overflow-y:auto; }
  .sec-op { display:flex; align-items:center; gap:.45rem; width:100%; box-sizing:border-box;
    min-height:2.3rem; text-align:left; border:none; background:none; padding:.35rem .65rem;
    font-family:inherit; font-size:.82rem; color:var(--text); cursor:pointer; }
  .sec-op:hover, .sec-op:focus-visible { background:var(--panel-2); outline:none; }
  .sec-op-txt { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .sec-op-tag { flex-shrink:0; font-size:.68rem; color:var(--muted-2); }
  .sec-op--nuevo { color:var(--brand); font-weight:600; border-top:1px solid var(--line); }
  .sec-aviso { margin:0; padding:.7rem .65rem; font-size:.78rem; color:var(--muted); }
  /* El panel del «+» flota por encima del borde del modal: la tarjeta recorta lo
     que sobresale (`overflow:hidden` de .modal-card) y lo cortaba. El encabezado
     no tiene fondo propio, así que soltar el recorte no le deja esquinas cuadradas. */
  .modal-card:has(.ep-pop) { overflow:visible; }

  /* ── «Editar proyecto» ──────────────────────────────────────────────────
     Una sola línea: cada campo es rótulo + chips + un buscador. Mismos rótulos, mismos chips, mismo aire
     entre campos; las explicaciones van en la «i», no en párrafos en el medio. */
  .ep-body { display:flex; flex-direction:column; gap:1.05rem; }
  /* El título de cada campo, con su «+» a la derecha. Abierto, el «+» gira a ×. */
  .ep-t-fila { display:flex; align-items:center; justify-content:space-between; gap:.5rem; min-height:1.65rem; }
  .ep-mas { flex-shrink:0; width:1.65rem; height:1.65rem; padding:0; border-radius:.45rem; cursor:pointer;
    display:inline-flex; align-items:center; justify-content:center;
    border:1px solid var(--line); background:var(--panel); color:var(--muted);
    transition:transform .15s var(--ease-out), color .12s linear, border-color .12s linear, background .12s linear; }
  .ep-mas:hover { color:var(--brand); border-color:var(--brand); }
  .ep-mas.is-abierto { transform:rotate(45deg); color:var(--brand); border-color:var(--brand);
    background:color-mix(in srgb, var(--brand) 8%, var(--panel)); }
  /* El campo con el panel abierto va por encima de los demás: si no, el panel de
     uno pasaba por DEBAJO del campo de abajo. */
  .ep-campo { position:relative; }
  .ep-campo:has(.ep-pop.is-abierto) { z-index:4; }
  /* El panel: blanco, con sombra, flotando. Cuelga de un ancla de alto cero, así
     que abrirlo no mueve ni agranda nada del modal. Rápido: 120ms en aparecer y
     180ms en bajar la lista. */
  .ep-ancla { position:relative; height:0; }
  .ep-pop { position:absolute; left:0; right:0; top:.3rem; z-index:5; padding:.35rem;
    background:var(--panel); border:1px solid var(--line); border-radius:.7rem; box-shadow:var(--shadow-lg);
    opacity:0; visibility:hidden; transform:translateY(-4px); pointer-events:none;
    transition:opacity .12s var(--ease-out), transform .12s var(--ease-out), visibility 0s linear .12s; }
  .ep-pop.is-abierto { opacity:1; visibility:visible; transform:none; pointer-events:auto;
    transition:opacity .12s var(--ease-out), transform .12s var(--ease-out); }
  .ep-pop-buscar { display:flex; align-items:center; gap:.45rem; padding:.4rem .55rem; border-radius:.5rem;
    background:var(--panel-2); color:var(--muted-2); cursor:text; }
  .ep-pop-inp { flex:1; min-width:0; border:none; background:none; padding:0; font-family:inherit;
    font-size:.84rem; color:var(--text); }
  .ep-pop-inp:focus { outline:none; box-shadow:none; border-color:transparent; }
  /* Lo de abajo baja un instante después del buscador (segundo paso). */
  .ep-pop-lista { display:grid; grid-template-rows:0fr; transition:grid-template-rows .18s var(--ease-out); }
  .ep-pop.is-lista .ep-pop-lista { grid-template-rows:1fr; }
  .ep-pop-lista > div { min-height:0; overflow:hidden; }
  .ep-pop.is-quieto .ep-pop-lista > div { overflow:visible; }
  .ep-pop .sec-panel { border:none; box-shadow:none; background:none; margin-top:.3rem; }
  /* Un campo sin nada lo dice, en vez de quedar el título solo. */
  .ep-body .sec-chips:empty { display:flex; }
  .ep-body .sec-chips:empty::before { content:attr(data-vacio); font-size:.8rem; font-style:italic; color:var(--muted-2); }
  @media (prefers-reduced-motion: reduce) { .ep-pop, .ep-pop-lista, .ep-mas { transition:none; } }
  .ep-campo { display:flex; flex-direction:column; gap:.45rem; margin:0; scroll-margin-top:1rem; }
  .ep-t { display:inline-flex; align-items:center; gap:.3rem; font-size:.8rem; font-weight:600; color:var(--text); }
  .ep-opc { font-weight:400; color:var(--muted-2); }
  .ep-i { display:inline-flex; color:var(--muted-2); cursor:help; }
  .ep-i:hover, .ep-i:focus-visible { color:var(--brand); outline:none; }
  .ep-sep { border:none; border-top:1px solid var(--line); margin:.1rem 0; }
  /* El nombre del chip, cortado si no entra. */
  .sec-chip-txt { max-width:14rem; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .ep-pie { display:flex; align-items:center; justify-content:flex-end; gap:.6rem;
    border-top:1px solid var(--line); padding-top:.9rem; margin-top:.15rem; }
  .ep-error { margin:0 auto 0 0; font-size:.78rem; color:var(--danger); }

  

  

  

  

  

  

  

  @keyframes cv-giro { to { transform:rotate(360deg); } }

  /* ── Diagramas de draw.io (ver app/core/diagramas.py) ────────────────────
     La grilla: miniaturas del mismo tamaño, con el nombre abajo. */
  .dg-lista { display:grid; grid-template-columns:repeat(auto-fill, minmax(10.5rem, 1fr)); gap:.75rem; }
  .dg-item { display:flex; flex-direction:column; gap:.3rem; min-width:0; }
  .dg-mini { display:flex; align-items:center; justify-content:center; aspect-ratio:4 / 3; width:100%;
    padding:.4rem; border:1px solid var(--line); border-radius:.6rem; background:#fff; cursor:pointer;
    overflow:hidden; transition:border-color .12s linear, box-shadow .12s linear; }
  .dg-mini:hover { border-color:var(--brand); box-shadow:0 0 0 3px color-mix(in srgb, var(--brand) 12%, transparent); }
  .dg-mini img { max-width:100%; max-height:100%; object-fit:contain; }
  .dg-mini-vacio { font-size:.76rem; font-style:italic; color:var(--muted-2); }
  .dg-item-pie { display:flex; align-items:center; gap:.2rem; min-width:0; }
  .dg-item-t { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
    font-size:.8rem; font-weight:600; color:var(--text); }
  .dg-item-inp { flex:1; min-width:0; padding:.15rem .35rem; font-size:.8rem; }
  .dg-item-acc { flex-shrink:0; display:inline-flex; align-items:center; justify-content:center;
    width:1.4rem; height:1.4rem; padding:0; border:none; border-radius:.35rem; background:none;
    color:var(--muted-2); cursor:pointer; font-size:.78rem; }
  .dg-item-acc:hover { background:var(--panel-2); color:var(--text); }
  .dg-item-x:hover { color:var(--danger); }
  .dg-nuevo { display:flex; flex-direction:column; align-items:center; justify-content:center; gap:.3rem;
    aspect-ratio:4 / 3; width:100%; border:1.5px dashed var(--line-2); border-radius:.6rem;
    background:none; color:var(--muted); font-family:inherit; font-size:.8rem; font-weight:600; cursor:pointer; }
  .dg-nuevo:hover { border-color:var(--brand); color:var(--brand); }
  /* El editor: a pantalla completa, por encima de todo (incluido el modal de la
     tarea, desde el que se puede abrir). */
  .dg-backdrop { position:fixed; inset:0; z-index:1200; display:flex; padding:1rem;
    background:rgba(15, 28, 46, .35); backdrop-filter:blur(4px); }
  .dg-backdrop.hidden { display:none; }
  .dg-card { flex:1; display:flex; flex-direction:column; min-width:0; overflow:hidden;
    border:1px solid var(--line); border-radius:.9rem; background:var(--panel); box-shadow:var(--shadow-lg); }
  .dg-head { display:flex; align-items:center; gap:.7rem; padding:.55rem .8rem .55rem 1rem;
    border-bottom:1px solid var(--line); }
  .dg-titulo { font-weight:700; font-size:.92rem; color:var(--text); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .dg-estado { margin-right:auto; font-size:.76rem; color:var(--muted-2); }
  .dg-caja { position:relative; flex:1; min-height:0; }
  .dg-frame { position:absolute; inset:0; width:100%; height:100%; border:none; background:#fff; }
  .dg-cargando { position:absolute; inset:0; display:flex; flex-direction:column; align-items:center;
    justify-content:center; gap:.6rem; background:var(--panel); color:var(--muted); font-size:.86rem; }
  .dg-cargando.hidden { display:none; }
  .dg-giro { width:22px; height:22px; border-radius:50%; border:2.5px solid var(--line-2);
    border-top-color:var(--brand); animation:cv-giro .8s linear infinite; }
  @media (prefers-reduced-motion: reduce) { .dg-giro { animation:none; } }

  

  

  

  

  .tm-side-ro { margin:0; font-size:.82rem; color:var(--text); }
  /* La «i» de un encabezado del panel: la aclaración que se lee una vez y
     después estorba. Apagada, y toma color al pasarle por encima. */
  .tm-sh-i { display:inline-flex; margin-left:.25rem; color:var(--muted-2); cursor:help;
    vertical-align:middle; }
  .tm-sh-i:hover { color:var(--brand); }
  /* Sin padding propio: lo pone .modal-body. Si se define acá, se pisa el lateral
     y el contenido queda pegado al borde. */
  .tm-body { max-height:78vh; overflow-y:auto; display:flex; flex-direction:column; gap:1.1rem; }
  .tm-head { display:flex; align-items:flex-start; justify-content:space-between; gap:.8rem; }
  .tm-title-wrap { flex:1; min-width:0; }
  .tm-title { margin:0; font-size:1.22rem; line-height:1.35; word-break:break-word; padding:.15rem .3rem; border-radius:.4rem; }
  .tm-title:hover { background:var(--panel-2); }
  .tm-meta { margin:0; display:flex; align-items:center; flex-wrap:wrap; gap:.4rem;
    font-size:.78rem; color:var(--muted); line-height:1.5; }
  .tm-meta-2 { flex-basis:100%; }
  /* El estado se lee por el puntito de color, no por el fondo teñido: con el fondo
     competía con el título por la atención. */
  .tm-estado { display:inline-flex; align-items:center; gap:.4rem; flex-shrink:0;
    border:1px solid var(--line); background:var(--panel); border-radius:999px;
    padding:.25rem .65rem; font-family:inherit; font-size:.75rem; font-weight:600;
    color:var(--text); cursor:pointer; }
  .tm-estado:hover { border-color:var(--muted-2); }
  .tm-estado-dot { width:8px; height:8px; border-radius:50%; background:var(--st); flex-shrink:0; }
  .tm-block { border:1px solid color-mix(in srgb,var(--danger-2) 22%,transparent); background:color-mix(in srgb,var(--danger-2) 7%,transparent); border-radius:.6rem; padding:.55rem .7rem; }
  .tm-block-label { display:flex; align-items:center; gap:.35rem; font-size:.75rem; font-weight:700; color:var(--danger); margin-bottom:.35rem; }
  .tm-block-input { width:100%; box-sizing:border-box; border:1px solid var(--line); border-radius:.45rem; padding:.35rem .5rem; font-family:inherit; font-size:.83rem; resize:vertical; background:var(--panel); color:var(--text); }
  .tm-block-text { margin:0; font-size:.83rem; color:var(--danger); }
  /* Cada bloque separado por una línea suave: se lee por partes en vez de un chorizo. */
  .tm-section + .tm-section { border-top:1px solid var(--line); padding-top:1.1rem; }
  /* Un titulo que no abre la seccion necesita aire arriba: sin esto, RESPONSABLES
     quedaba pegado al ultimo item de la checklist. */
  .tm-section-h:not(:first-child) { margin-top:1.15rem; }
  .tm-section-h { font-size:.82rem; font-weight:700; color:var(--text); margin-bottom:.6rem;
    display:flex; align-items:center; gap:.45rem; }
  .tm-sh-ico { display:inline-flex; color:var(--muted-2); flex-shrink:0; }
  .tm-count { font-size:.7rem; font-weight:700; color:var(--muted); background:var(--panel-2);
    border-radius:999px; padding:.05rem .45rem; }
  .tm-count--end { margin-left:auto; }

  
  /* Una descripcion larga empujaba todo lo de abajo (checklist, archivos, comentarios)
     fuera de la primera pantalla: se scrolleaba medio modal para llegar. Con tope, la
     descripcion scrollea sola y el resto de la tarea queda a la vista. */
  .tm-desc { font-size:.88rem; color:var(--text); line-height:1.5; white-space:pre-wrap;
    overflow-wrap:anywhere; word-break:break-word; cursor:pointer; border:1px solid transparent;
    border-radius:.5rem; padding:.4rem .5rem; max-height:11.5rem; overflow-y:auto; }
  /* Editando, el editor vive ADENTRO del .tm-desc: sin esto quedaba recortado. */
  .tm-desc--placeholder, .tm-desc:has(textarea),
  .tm-desc:has(.toastui-editor-defaultUI) { max-height:none; overflow:visible; cursor:default; }
  /* Ya dibujada en markdown: los saltos los pone el formato, no el pre-wrap. */
  .tm-desc.md-ver { white-space:normal; }
  .tm-desc:hover { background:var(--panel-2); }
  .tm-desc--placeholder { color:var(--muted-2); font-style:italic; }
  .tm-desc--ro { cursor:default; }

  
  .tm-av { position:relative; overflow:hidden; width:24px; height:24px; border-radius:50%; background:color-mix(in srgb,var(--brand) 14%,transparent); color:var(--brand); display:inline-flex; align-items:center; justify-content:center; font-size:.6rem; font-weight:700; font-family:'Sora',sans-serif; flex-shrink:0; }
  .tm-av--sm { width:20px; height:20px; font-size:.55rem; }
  /* Los responsables son caras, no chips con el nombre al lado: en la columna
     angosta entraban dos y se cortaba el resto. El nombre va en el tooltip. */
  .tm-caras { display:flex; flex-wrap:wrap; align-items:center; gap:.3rem; }
  .tm-caras .tm-av { width:28px; height:28px; font-size:.62rem; cursor:default;
    box-shadow:0 0 0 2px var(--panel); }
  .tm-cara-add { display:inline-flex; align-items:center; justify-content:center;
    width:28px; height:28px; border:1px dashed var(--line-2, var(--line)); border-radius:50%;
    background:none; color:var(--muted-2); font-family:inherit; font-size:.95rem; line-height:1;
    cursor:pointer; }
  .tm-cara-add:hover { color:var(--brand); border-color:var(--brand); }
  .tm-assignee-edit { margin-top:.6rem; display:flex; flex-direction:column; gap:.6rem; }
  .tm-asg-list { display:flex; flex-direction:column; gap:.1rem; max-height:180px; overflow-y:auto; border:1px solid var(--line); border-radius:.5rem; padding:.3rem; }
  .tm-asg { display:flex; align-items:center; gap:.5rem; padding:.3rem .45rem; border-radius:.4rem; cursor:pointer; font-size:.85rem; }
  .tm-asg:hover { background:var(--panel-2); }
  .tm-asg input { width:auto; margin:0; }
  .tm-comments { display:flex; flex-direction:column; gap:.7rem; margin-bottom:.85rem; }
  .tm-comment { border:1px solid var(--line); border-radius:.55rem; padding:.7rem .85rem; background:var(--panel); }
  .tm-c-top { display:flex; align-items:center; gap:.5rem; margin-bottom:.35rem; }
  .tm-c-author { font-size:.82rem; font-weight:700; color:var(--text); }
  .tm-c-date { font-size:.7rem; color:var(--muted-2); }
  .tm-c-acts { margin-left:auto; display:flex; gap:.1rem; }

  

  .tm-c-text { font-size:.86rem; color:var(--text); line-height:1.45; white-space:pre-wrap; word-break:break-word; }

  .tm-files { display:flex; flex-wrap:wrap; gap:.5rem; }
  .tm-file { position:relative; }
  .tm-file--img img { width:104px; height:76px; object-fit:cover; border-radius:.5rem;
    border:1px solid var(--line); display:block; }
  .tm-file-doc { display:inline-flex; align-items:center; gap:.35rem; max-width:15rem;
    border:1px solid var(--line); border-radius:.5rem; padding:.35rem .55rem;
    font-size:.78rem; color:var(--text); text-decoration:none; background:var(--panel); }
  .tm-file-doc:hover { border-color:var(--brand); color:var(--brand); }
  .tm-file-name { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .tm-file-size { font-size:.68rem; color:var(--muted-2); flex-shrink:0; }
  .tm-file-x { position:absolute; top:-6px; right:-6px; width:18px; height:18px; padding:0;
    border:1px solid var(--line); border-radius:50%; background:var(--panel); color:var(--muted);
    font-size:.6rem; line-height:1; cursor:pointer; opacity:0; transition:opacity .12s; }
  .tm-file:hover .tm-file-x { opacity:1; }
  .tm-file-x--armed { opacity:1; background:var(--danger); border-color:var(--danger); color:#fff; }

  /* Cada propiedad en su cajita: se distinguen de un vistazo sin líneas divisorias. */
  .tm-side-b { border:1px solid var(--line); border-radius:.6rem; padding:.7rem .75rem;
    background:var(--panel); }
  .tm-fecha { width:100%; box-sizing:border-box; font-size:.84rem; }
  .tm-fecha-nota { display:inline-block; margin-top:.3rem; font-size:.72rem; color:var(--muted); }
  .tm-fecha-nota--tarde { color:var(--danger); font-weight:700; }
  .tm-colores { display:flex; flex-wrap:wrap; gap:.3rem; }
  .tm-color { width:22px; height:22px; border-radius:50%; border:2px solid transparent;
    cursor:pointer; padding:0; box-shadow:0 0 0 1px var(--line) inset; }
  .tm-color--none { background:var(--panel-2); display:inline-flex; align-items:center;
    justify-content:center; color:var(--muted-2); }
  .tm-color--on { border-color:var(--text); }

  /* El "+" del encabezado de una sección del modal (comentarios). */
  .tm-participan { display:flex; align-items:center; flex-wrap:wrap; gap:.35rem; margin-top:.55rem;
    padding-top:.5rem; border-top:1px dashed var(--line); }
  .tm-participan-lbl { font-size:.68rem; font-weight:700; text-transform:uppercase;
    letter-spacing:.04em; color:var(--muted-2); margin-right:.15rem; }
  .tm-participan-it { display:inline-flex; align-items:center; gap:.2rem; font-size:.78rem;
    color:var(--muted); }
  .tm-participan-add { display:inline-flex; align-items:center; justify-content:center;
    width:17px; height:17px; border:1px solid var(--line); background:var(--panel);
    border-radius:.3rem; color:var(--muted-2); font-family:inherit; font-size:.75rem;
    line-height:1; cursor:pointer; }
  .tm-participan-add:hover { color:var(--brand); border-color:var(--brand); }

  /* Checklist: los pasos de la tarea. */
  .tm-checks { display:flex; flex-direction:column; gap:.1rem; }
  .tm-check-bar { display:block; height:4px; border-radius:99px; background:var(--line);
    overflow:hidden; margin:0 0 .45rem; }
  .tm-check-bar > span { display:block; height:100%; background:#16a34a; border-radius:99px;
    transition:width .18s ease; }
  .tm-check-bar--full { background:color-mix(in srgb,#16a34a 22%,transparent); }
  .tm-check { display:flex; align-items:flex-start; gap:.4rem; padding:.2rem .1rem;
    border-radius:.35rem; }
  .tm-check:hover { background:var(--panel-2); }
  /* El label envuelve SOLO la casilla: el texto quedó afuera para que tocarlo
     abra la edición en vez de tildar el ítem. */
  .tm-check-lbl { display:flex; align-items:flex-start; flex-shrink:0; cursor:pointer; }
  .tm-check-lbl input { width:auto; margin:.15rem 0 0; flex-shrink:0; accent-color:#16a34a; }
  .tm-check-txt { flex:1; min-width:0; font-size:.85rem; color:var(--text); line-height:1.4;
    overflow-wrap:anywhere; }
  /* Editable: el cursor de texto lo anticipa, sin agregar ningún adorno. */
  .tm-check-txt[role="button"] { cursor:text; }
  .tm-check-txt[role="button"]:hover { text-decoration:underline dotted var(--muted-2); }
  /* Los seis puntitos para ordenar. Como las acciones: aparecen al pasar por la
     fila, para que la lista en reposo siga siendo sólo la lista. */
  .tm-check-mover { flex-shrink:0; display:inline-flex; align-items:center; align-self:center;
    color:var(--muted-2); cursor:grab; opacity:0; transition:opacity .12s, color .15s; }
  .tm-check:hover .tm-check-mover, .tm-check:focus-within .tm-check-mover { opacity:.55; }
  .tm-check-mover:hover { color:var(--brand); opacity:1; }
  .tm-check-mover:active { cursor:grabbing; }
  .tm-check--drag { opacity:.45; }
  .tm-check--done .tm-check-txt { color:var(--muted); text-decoration:line-through; }
  /* Quien lo tildo, al costado del item. Se achica antes de empujar al texto. */
  .tm-check-by { font-size:.68rem; color:var(--muted-2); white-space:nowrap; flex-shrink:1;
    overflow:hidden; text-overflow:ellipsis; align-self:center; }
  .tm-check-acts { display:flex; gap:.1rem; opacity:0; flex-shrink:0; transition:opacity .12s; }
  .tm-check:hover .tm-check-acts, .tm-check:focus-within .tm-check-acts { opacity:1; }
  .tm-check-btn { border:none; background:none; padding:0 .2rem; color:var(--muted-2);
    font-size:.78rem; line-height:1; cursor:pointer; border-radius:.3rem; }
  .tm-check-btn:hover { color:var(--brand); }
  .tm-check-btn--x:hover { color:var(--danger); }
  .tm-check-btn--armed { color:#fff !important; background:var(--danger); }
  /* Alta de items: una linea discreta al pie de la lista, no un "+" en el titulo.
     Ahi arriba competia con el contador y no se leia como "agregar". */
  .tm-add-linea { display:block; width:100%; margin-top:.5rem; border:1px dashed var(--line);
    background:none; border-radius:.5rem; padding:.4rem; font-family:inherit; font-size:.78rem;
    font-weight:600; color:var(--muted-2); cursor:pointer; }
  .tm-add-linea:hover { color:var(--brand); border-color:var(--brand);
    background:color-mix(in srgb, var(--brand) 5%, transparent); }
  .tm-check-new { display:flex; gap:.4rem; align-items:center; margin-top:.5rem; }
  .tm-check-new input { flex:1; font-size:.84rem; }

  
  .tm-add-comment { display:flex; flex-direction:column; gap:.45rem; }
  .tm-add-comment.tm-c-drop { outline:2px dashed var(--brand); outline-offset:3px; border-radius:.5rem; }
  /* Radio fijo y no 999px: con una linea da lo mismo (media altura = pildora),
     pero al crecer el textarea el borde se curvaba hacia adentro y los botones
     de la esquina quedaban fuera de la curva. */
  .tm-c-fila { display:flex; align-items:flex-end; gap:.45rem; border:1px solid var(--line);
    border-radius:1.05rem; padding:.3rem .4rem .3rem .45rem; background:var(--panel); }
  .tm-c-fila:focus-within { border-color:var(--brand); }
  .tm-c-fila .tm-av { align-self:center; }
  /* Centrado, como el clip: con `align-items:flex-end` en la fila, al crecer el
     textarea el boton se iba al fondo y quedaba desalineado del clip. */
  .tm-c-enviar { display:inline-flex; align-items:center; justify-content:center; flex-shrink:0;
    align-self:center;
    width:28px; height:28px; border:none; border-radius:50%; background:var(--brand); color:var(--on-brand);
    cursor:pointer; }
  .tm-c-enviar:hover { filter:brightness(1.08); }

  .tm-c-clip { display:inline-flex; align-items:center; justify-content:center; width:26px; height:26px;
    flex-shrink:0; align-self:center;
    border:1px solid var(--line); border-radius:.45rem; color:var(--muted); cursor:pointer; }
  .tm-c-clip:hover { color:var(--brand); border-color:var(--brand); }
  /* Lo pegado/arrastrado, antes de mandarse. */
  .tm-c-adj { display:flex; flex-wrap:wrap; gap:.35rem; }
  .tm-c-adj--con { margin:.1rem 0; }
  .tm-c-adj-it { display:inline-flex; align-items:center; gap:.25rem; padding:.15rem .3rem;
    border:1px solid var(--line); border-radius:.4rem; background:var(--panel-2);
    font-size:.72rem; color:var(--muted); }
  .tm-c-adj-it img { width:34px; height:34px; object-fit:cover; border-radius:.25rem; display:block; }
  .tm-c-adj-x { border:none; background:none; padding:0 .1rem; color:var(--muted-2);
    font-size:.7rem; line-height:1; cursor:pointer; }
  .tm-c-adj-x:hover { color:var(--danger); }
  .tm-files--c { margin-top:.35rem; }
  .tm-add-comment input, .tm-add-comment textarea { flex:1; }
  .tm-c-input { flex:1; min-width:0; border:none; background:none; padding:.3rem .1rem;
    font-family:inherit; font-size:.85rem; color:var(--text);
    resize:none; overflow-y:auto; min-height:1.5rem; max-height:10rem;
    font-family:inherit; line-height:1.45; }
  .tm-audit { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:.6rem; }
  .tm-audit-item { display:flex; align-items:baseline; gap:.5rem; font-size:.8rem; }
  .tm-audit-dot { width:7px; height:7px; border-radius:50%; flex-shrink:0; background:var(--muted-2); position:relative; top:1px; }
  .tm-audit-dot--creacion { background:#15803d; } .tm-audit-dot--eliminacion { background:var(--danger); } .tm-audit-dot--modificacion { background:#1d4ed8; }
  .tm-audit-msg { flex:1; min-width:0; color:var(--text); line-height:1.4; }
  .tm-audit-when { font-size:.7rem; color:var(--muted-2); white-space:nowrap; }
  .tm-empty { font-size:.82rem; color:var(--muted-2); margin:0; }
  .tm-hist-link { display:inline-flex; align-items:center; gap:.45rem; align-self:flex-start;
    border:none; background:none; padding:.2rem 0; font-family:inherit; font-size:.8rem;
    font-weight:600; color:var(--muted); cursor:pointer; }
  .tm-hist-link:hover { color:var(--brand); }
  .tm-hist-link:hover .tm-sh-ico { color:var(--brand); }
  .tm-hist-pag { display:flex; align-items:center; justify-content:center; gap:.6rem; margin-top:.8rem; }
  /* Subir una captura era abrir el explorador si o si: ahora tambien se suelta acá. */
  .tm-drop { display:flex; flex-direction:column; align-items:center; justify-content:center;
    gap:.15rem; margin-top:.5rem; padding:1rem .6rem; border:1px dashed var(--line);
    border-radius:.6rem; color:var(--muted-2); text-align:center; cursor:pointer; }
  .tm-drop:hover, .tm-drop--on { border-color:var(--brand);
    background:color-mix(in srgb, var(--brand) 5%, transparent); }
  .tm-drop--on { border-style:solid; }
  .tm-drop svg { color:var(--brand); }
  .tm-drop-t { font-size:.78rem; font-weight:700; color:var(--brand); }
  .tm-drop-s { font-size:.7rem; }
  /* En la columna angosta, una miniatura de 104px desbordaba. */
  .tm-side .tm-file--img img { width:100%; height:82px; }
  .tm-side .tm-file { flex:1 1 100%; }
  .tm-side .tm-file-doc { max-width:100%; box-sizing:border-box; }
  .pd-task[draggable="true"] button, .pd-task[draggable="true"] input,
  .pd-task[draggable="true"] .pd-task-name--link { cursor:pointer; }
  /* Los controles de adentro conservan su cursor propio. */
  .pdk-card[draggable="true"] button, .pdk-card[draggable="true"] .pd-task-name--link { cursor:pointer; }
  .tm-desc-acts { display:flex; justify-content:flex-end; gap:.4rem; margin-top:.45rem; }

  

  

/* ── Filas de tarea ─────────────────────────────────────────────────────
   Las dibujan el tablero del proyecto, la pantalla de un sprint y el enlace
   compartido. Por eso viven aca y no en project_detail.html. */
.pd-view-btn { font-size:.76rem; font-weight:600; color:var(--muted); text-decoration:none; padding:.25rem .6rem; border-radius:.4rem; transition:color .15s,background .15s; white-space:nowrap; }
  .pd-view-btn:hover { color:var(--text); }
  /* La vista elegida: sin esto no habia forma de saber cual estabas mirando. */
  .pd-view-btn--on { background:var(--panel); color:var(--brand); box-shadow:0 1px 3px rgba(0,0,0,.08); }
  .pd-group-divider { display:flex; align-items:center; gap:.45rem; font-size:.72rem; font-weight:700; text-transform:uppercase; letter-spacing:.03em; color:var(--muted); margin:1.1rem 0 .1rem; padding:0 .2rem; }
  .pd-group-divider:first-child { margin-top:0; }
  .pd-group-dot { width:8px; height:8px; border-radius:50%; flex-shrink:0; }
  .pd-group-count { font-size:.68rem; font-weight:700; color:var(--muted-2); background:var(--panel-2); border-radius:999px; padding:.05rem .4rem; text-transform:none; }
  .pd-groups { display:flex; flex-direction:column; gap:1.2rem; }
  .pd-group-tasks { display:flex; flex-direction:column; gap:.6rem; min-height:14px; border-radius:.6rem; transition:background .12s,outline .12s; }
  /* La marca de "solta acá" va en las DOS: `.pd-group-tasks` es el contenedor de
     las vistas agrupadas y `.pd-tasks` el de la lista. Estaba solo en la primera,
     asi que arrastrando en vista lista no
     se veia absolutamente nada y parecia que el arrastre no funcionaba. */
  .pd-group-tasks.pd-drop-over,
  .pd-tasks.pd-drop-over { outline:2px dashed var(--brand); outline-offset:3px; background:color-mix(in srgb,var(--brand) 5%,transparent); border-radius:.6rem; }
  .pd-group-empty { margin:0; padding:.7rem; font-size:.78rem; color:var(--muted-2); text-align:center; border:1px dashed var(--line-2); border-radius:.6rem; }
  .pdk-board { display:flex; gap:.9rem; overflow-x:auto; padding-bottom:.6rem; align-items:flex-start; }
  .pdk-col { flex:1 1 0; min-width:230px; max-width:340px; background:var(--panel-2); border:1px solid var(--line); border-radius:.7rem; padding:.6rem; display:flex; flex-direction:column; }
  .pdk-col-head { display:flex; align-items:center; gap:.45rem; font-size:.72rem; font-weight:700; text-transform:uppercase; letter-spacing:.03em; color:var(--muted); padding:.1rem .2rem .55rem; }
  .pdk-col-tasks { display:flex; flex-direction:column; gap:.5rem; min-height:44px; flex:1; border-radius:.5rem; }
  /* El padding de abajo es mayor que el de arriba a proposito: es la franja donde
     se apoya el numero de la tarea (.pd-task-id), que va absolute en la esquina. */
  .pdk-card { border:1px solid var(--line); border-radius:.6rem; padding:.55rem .65rem 1.25rem; background:var(--panel); box-shadow:0 1px 2px rgba(0,0,0,.04); }
  /* Descripción en la tarjeta del tablero: acotada a 3 líneas para no romper la columna. */
  .pdk-desc { overflow-wrap:anywhere; word-break:break-word; margin:.35rem 0 0; font-size:.78rem; color:var(--muted); line-height:1.4;
    display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical; overflow:hidden; word-break:break-word; }
  .pdk-card-head { display:flex; align-items:flex-start; gap:.3rem; }
  /* El grip, la "i" y el menu, fijos arriba; el nombre es el unico que crece. */
  .pdk-card-head > .pd-grip, .pdk-card-head > .task-info-i,
  .pdk-card-head > .action-menu-wrap { flex-shrink:0; margin-top:.05rem; }
  /* La "i" al mismo alto que los tres puntitos. Las dos arrancan arriba de todo,
     pero la "i" es solo su icono (13px) y el boton de los puntitos trae padding:
     quedaban con los centros a 4px, la "i" flotando mas arriba. El calc repite la
     caja de .action-menu-trigger (font-size 1.1rem, line-height 1, padding .1rem)
     para que los dos centros caigan en el mismo lugar. */
  .pdk-card-head > .task-info-i { height:calc(1.1rem + .2rem); }
  .pdk-name { flex:1; min-width:0; font-size:.85rem; color:var(--text); line-height:1.35; word-break:break-word; }
  .pdk-card--done .pdk-name { text-decoration:line-through; color:var(--muted-2); }
  /* El pie muestra los datos con su rótulo: quién la tiene, para cuándo, de qué
     módulo. Se separa del texto con una línea, y solo aparece si hay algún dato. */
  .pdk-card-foot { display:flex; align-items:center; flex-wrap:wrap; gap:.55rem 1.1rem;
    margin-top:.6rem; }
  .pdk-card-foot:not(:empty) { padding-top:.55rem; border-top:1px solid var(--line); }
  .pdk-dato { display:inline-flex; align-items:center; gap:.35rem; color:var(--muted-2); }
  .pdk-dato-txt { display:flex; flex-direction:column; line-height:1.15; min-width:0; }
  .pdk-dato-txt small { font-size:.62rem; color:var(--muted-2); }
  .pdk-dato-txt strong { font-size:.75rem; font-weight:700; color:var(--text);
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:8rem; }
  .pdk-dato--tarde { color:var(--danger); }
  .pdk-dato--tarde .pdk-dato-txt strong, .pdk-dato--tarde .pdk-dato-txt small { color:var(--danger); }
  .pdk-checks { display:inline-flex; align-items:center; gap:.35rem; margin-top:.45rem;
    margin-right:.55rem; font-size:.74rem; font-weight:700; color:var(--muted-2); }
  .pdk-checks-bar { display:inline-block; width:44px; height:4px; border-radius:99px;
    background:var(--line); overflow:hidden; }
  .pdk-checks-bar > span { display:block; height:100%; background:var(--muted-2); }
  .pdk-checks-bar--full > span { background:#16a34a; }
  .pd-task-checks { display:inline-flex; align-items:center; gap:.2rem; flex-shrink:0;
    font-size:.7rem; font-weight:700; color:var(--muted-2); }
  .pdk-coment { display:inline-flex; align-items:center; gap:.25rem; margin-top:.45rem;
    font-size:.74rem; font-weight:700; color:var(--muted-2); }
  /* En la tarjeta del tablero el globito va clavado a la derecha: así está en el
     mismo lugar en todas, y no se corre según cuántas marcas tenga cada una.
     Float y no un flex, por lo mismo que «espera a»: estos indicadores tienen
     reglas como hijos directos de la tarjeta y envolverlos en una fila se las
     rompe. El `clear:both` del pie ya estaba puesto para el otro float. */
  .pdk-card > .pdk-coment { float:right; margin-left:.5rem; }
  /* Cuánto se consumió del plazo (de cuando nació la tarea a su fecha estimada). */
  .pdk-plazo { display:block; width:4.2rem; height:3px; margin-top:.25rem; border-radius:99px;
    background:var(--line); overflow:hidden; }
  .pdk-plazo > span { display:block; height:100%; background:var(--muted-2); }
  .pdk-dato--tarde .pdk-plazo > span { background:var(--danger); }
  /* El motivo del bloqueo no lleva caja: la caja roja translúcida se mezclaba con el
     color de la tarea y quedaba un rectángulo de un tono raro adentro de otro. Con
     solo el ícono y el texto en rojo se lee igual sobre cualquier fondo. */
  .pdk-reason { display:flex; align-items:center; gap:.3rem; margin:.4rem 0 0;
    font-size:.74rem; line-height:1.35; color:var(--danger); }
  .pd-tasks { display:flex; flex-direction:column; gap:.6rem; }
  .pd-task { border:1px solid var(--line); border-radius:.7rem; padding:.7rem .85rem; background:var(--panel); }
  .pd-task-row { display:flex; align-items:center; gap:.6rem; }
  .pd-check { flex-shrink:0; display:inline-flex; align-items:center; background:none; border:none; cursor:pointer; padding:0; color:var(--muted-2); }
  .pd-grip { flex-shrink:0; display:inline-flex; align-items:center; color:var(--muted-2); cursor:grab; padding:.1rem; opacity:.45; transition:opacity .15s,color .15s; }
  .pd-task:hover .pd-grip { opacity:1; }
  .pd-grip:active { cursor:grabbing; }
  .pd-grip:hover { color:var(--brand); }
  .pd-task[draggable="true"] { cursor:grab; }
  .pd-task[draggable="true"]:active { cursor:grabbing; }
  .pd-task[draggable="true"] input { cursor:text; }
  .pdk-card[draggable="true"] { cursor:grab; }
  .pdk-card[draggable="true"]:active { cursor:grabbing; }
  .pd-task.dragging { opacity:.45; }
  .pd-task-name { flex:1; min-width:0; font-size:.92rem; color:var(--text); }
  .pd-task--done .pd-task-name { text-decoration:line-through; color:var(--muted-2); }
  .pd-task-controls { display:flex; align-items:center; gap:.5rem; flex-shrink:0; }
  .pd-status-pill { display:inline-flex; align-items:center; gap:.25rem; font-size:.66rem; font-weight:700; text-transform:uppercase; letter-spacing:.02em; padding:.18rem .55rem; border-radius:999px; cursor:pointer; font-family:inherit; }
  .pd-assignees { display:flex; align-items:center; }
  .pd-avatar { position:relative; overflow:hidden; width:22px; height:22px; border-radius:50%; background:color-mix(in srgb,var(--brand) 14%,transparent); color:var(--brand); display:inline-flex; align-items:center; justify-content:center; font-size:.58rem; font-weight:700; font-family:'Sora',sans-serif; border:2px solid var(--panel); }
  .pd-avatar:not(:first-child) { margin-left:-6px; }
  .pd-task-desc { margin:.3rem 0 0 1.6rem; font-size:.8rem; color:var(--muted);
    overflow-wrap:anywhere; word-break:break-word; }
  .pd-block-reason { display:flex; align-items:center; gap:.4rem; margin:.4rem 0 0 1.6rem; font-size:.8rem; line-height:1.4; color:var(--danger); background:color-mix(in srgb,var(--danger-2) 8%,transparent); border:1px solid color-mix(in srgb,var(--danger-2) 22%,transparent); border-radius:.5rem; padding:.35rem .6rem; }
  .pd-comments { display:flex; flex-direction:column; gap:.3rem; margin:.5rem 0 0; padding-left:1.6rem; }
  /* `min-width:0`: un ítem de flex no se achica por debajo de su contenido salvo
     que se le diga, y un comentario con un link largo pegado —trescientos
     caracteres sin un solo espacio— se salía de la tarjeta por la derecha,
     encima de todo lo demás. */
  .pd-comment { display:flex; align-items:baseline; gap:.35rem; flex-wrap:wrap;
    font-size:.8rem; color:var(--muted); min-width:0; }
  .pd-comment .action-menu-wrap { margin-left:auto; }
  .pd-c-author { font-weight:700; color:var(--text); }
  /* `anywhere` y no `break-word`: `break-word` corta sólo si la palabra no entra
     en un renglón vacío, y adentro de un flex eso llegaba tarde. Se corta donde
     haga falta, que en un link es cualquier lado. */
  .pd-c-text { color:var(--muted); min-width:0; overflow-wrap:anywhere; }
  .pd-c-date { font-size:.68rem; color:var(--muted-2); }
  .pd-task-hecha { display:inline-flex; align-items:center; gap:.2rem; flex-shrink:0;
    font-size:.7rem; font-weight:600; color:#16a34a; }
  .pd-task-mod { flex-shrink:0; font-size:.68rem; font-weight:700; color:var(--muted); background:var(--panel-2);
    border:1px solid var(--line); border-radius:999px; padding:.05rem .4rem; }
    /* El numero de la tarea. Va antes del titulo y en tono apagado: tiene que poder
     leerse cuando uno lo busca y desaparecer cuando lee la lista. Tabular para que
     los numeros de una columna queden alineados entre si. */
  /* Gris suave a proposito: es un dato de referencia, no algo que haya que leer al
     recorrer el tablero. Se baja con opacity y no con un hex propio para que el tema
     oscuro lo siga sin tener que definirlo de nuevo. */
  .pd-task-id { flex-shrink:0; font-size:.68rem; font-weight:600; color:var(--muted-2);
    opacity:.55; font-variant-numeric:tabular-nums; letter-spacing:-.01em; margin-right:.1rem; }
  /* En el tablero el chip NO va en el encabezado: la columna es angosta y le comia
     el ancho al titulo, que terminaba envuelto en tres lineas. Va clavado en la
     esquina inferior derecha, fuera del flujo. */
  .pdk-card > .pd-task-id { position:absolute; right:.65rem; bottom:.4rem; margin:0;
    line-height:1; pointer-events:auto; }
  /* En una tarea hecha el titulo va tachado; el numero no, que si no parece que el
     numero tambien se dio de baja. */
  .pd-task--done .pd-task-id, .pdk-card--done .pd-task-id { text-decoration:none; }
  /* De que se trata la tarea: bug, feature, estilo. Un icono y no una palabra —el
     rotulo entero le come el ancho al titulo, que es lo que uno viene a leer— con
     su nombre en el tooltip. Cada tipo con su color, que es lo que hace que la
     columna se lea de un vistazo sin mirar los dibujos de cerca. */
  .pd-task-tipo { display:inline-flex; align-items:center; flex-shrink:0; margin-right:.3rem;
    line-height:0; color:var(--muted); }

  

  /* En una tarea hecha el icono acompaña al titulo apagado: sigue diciendo de que
     era, sin pelearle la atencion a lo que falta. */
  .pd-task--done .pd-task-tipo, .pdk-card--done .pd-task-tipo { opacity:.45; }
  /* Color de la tarea: SOLO un tinte del fondo (8%). Ni filete ni borde de color: el
     borde teñido dejaba un contorno lavado alrededor de cada tarjeta y era justo lo
     que las hacia ver mal. El borde sigue siendo el de siempre. */
  .pd-task { position:relative; }
  /* En LISTA y POR ESTADO la banderita va al borde izquierdo, que es el que se recorre
     al leer una lista. En el tablero va al 20% de la derecha (ver .pdk-card). */
  .pd-task--color:not(.pdk-card)::after { content:''; position:absolute; top:0; left:1.55rem;
    width:11px; height:19px; background:var(--task-color);
    clip-path:polygon(0 0, 100% 0, 100% 100%, 50% 70%, 0 100%);
    filter:drop-shadow(0 1px 1px rgba(0,0,0,.12)); }
  /* La fila deja lugar para la banderita, que si no le pisa el nombre. */
  .pd-task--color:not(.pdk-card) .pd-task-row { padding-top:.55rem; }

  /* En el TABLERO el color no pinta la tarjeta: cuelga como una banderita desde el
     borde de arriba, a un 20% del lado derecho. El fondo pintado se mezclaba con el
     rojo del motivo de bloqueo y daba un tono raro. */
  .pdk-card { position:relative; }
  /* ── Dependencias entre tareas ──────────────────────────────────────────
     El nodo es un círculo blanco con borde: casi transparente hasta que pasás
     por la tarjeta, porque en un tablero de treinta tareas treinta círculos a
     pleno son ruido. El cable es del color de marca y con un brillo suave: se
     ve moderno sin romper lo limpio del tablero. */
  .pdk-board { position:relative; }
  .dep-host { position:relative; }
  /* Fuera del tablero y con su posición puesta por el JS: el tablero scrollea en
     horizontal y recortaba los cables que se salían de su caja. El recorte de la
     capa misma (su caja = tablero + margen) es a propósito: un cable que apunta a
     una tarjeta que scrolleó fuera de la vista no tiene que cruzar medio panel. */
  .dep-capa { position:absolute; z-index:3; pointer-events:none; overflow:hidden; }
  /* La capa de cables se sale 40px del tablero para que un cable pueda combar
     hacia afuera. En el celular el tablero va casi pegado al borde y esos 40px
     empujaban la página hacia el costado: se recorta en su contenedor. `clip`
     y no `hidden`: no arma otro scroll adentro de la página. */
  @media (max-width: 700px) { .dep-host { overflow-x:clip; } }
  .dep-cable { fill:none; stroke:var(--brand); stroke-width:1.8; stroke-linecap:round;
    opacity:.75; transition:opacity .15s, stroke-width .15s; }
  .dep-cable--ok { stroke:var(--muted-2); stroke-dasharray:4 4; }
  .dep-punta { fill:var(--brand); }
  .dep-punta--ok { fill:var(--muted-2); }
  /* Con una tarjeta bajo el mouse, sus cables se prenden y el resto se apaga. */
  .dep-hay-foco .dep-cable { opacity:.18; }
  .dep-capa .dep-cable.dep-cable--foco { opacity:1; stroke-width:2.2;
    filter:drop-shadow(0 0 3px color-mix(in srgb, var(--brand) 55%, transparent)); }
  /* El cable que se está arrastrando: a pleno y con más brillo. */
  .dep-capa .dep-cable.dep-cable--vivo { opacity:1; stroke-width:2.4; stroke-dasharray:none;
    filter:drop-shadow(0 0 4px color-mix(in srgb, var(--brand) 65%, transparent)); }
  .dep-nodo { flex-shrink:0; width:14px; height:14px; margin-top:.2rem; padding:0;
    border-radius:50%; border:2px solid var(--line-2); background:var(--panel);
    box-shadow:0 1px 2px rgba(0,0,0,.14), inset 0 1px 0 rgba(255,255,255,.55);
    cursor:crosshair; touch-action:none; opacity:.5;
    transition:opacity .15s, border-color .15s, box-shadow .18s, transform .15s; }
  .pd-task:hover .dep-nodo, .dep-nodo:focus-visible, .dep-enganchando .dep-nodo { opacity:1; }
  .dep-nodo:hover { border-color:var(--brand); transform:scale(1.12); }
  .dep-nodo--origen { opacity:1; border-color:var(--brand);
    box-shadow:0 0 0 4px color-mix(in srgb, var(--brand) 18%, transparent); }
  /* El destino listo para recibir: halo rojizo, que se lea de lejos sin buscarlo. */
  .dep-nodo--destino { opacity:1; border-color:var(--brand); transform:scale(1.3);
    box-shadow:0 0 0 6px color-mix(in srgb, var(--brand) 20%, transparent),
               0 0 14px color-mix(in srgb, var(--brand) 45%, transparent); }
  .dep-enganchando, .dep-enganchando * { cursor:crosshair !important; user-select:none; }
  /* La marca de la tarjeta: a qué espera, aunque la otra no esté en pantalla.
     Flota a la DERECHA de la línea de los indicadores (checklist,
     comentarios). Float y no una fila flex: esos indicadores tienen reglas como
     hijos directos de la tarjeta (`.pdk-card > .di-marca`), y envolverlos en una
     fila se las rompía. */
  .dep-espera { float:right; display:inline-flex; align-items:center; gap:.3rem;
    margin:.45rem 0 0 .4rem; padding:.12rem .5rem; border-radius:999px; font-size:.7rem;
    font-weight:600; color:var(--brand); background:color-mix(in srgb, var(--brand) 9%, transparent); }
  /* El pie arranca abajo de la marca: en una tarjeta sin ningún indicador, el
     float no tiene renglón propio y el pie se le metía al costado. */
  .pdk-card-foot { clear:both; }
  /* En la fila de Lista y Por estado: el nodo va centrado como todo lo de la
     fila, y la marca en línea con los otros datitos (en un flex el float no
     aplica, y el margen de arriba la desalineaba). */
  .pd-task-row > .dep-nodo { margin-top:0; }
  .dep-espera--fila { float:none; margin:0; }
  /* En el modal: las dos listas, con el ✕ para deshacer. */
  .tm-dep-tit { margin:.1rem 0 .25rem; font-size:.66rem; font-weight:700; text-transform:uppercase;
    letter-spacing:.04em; color:var(--muted-2); }
  .tm-deps { list-style:none; margin:0 0 .5rem; padding:0; display:flex; flex-direction:column; gap:.2rem; }
  .tm-dep { display:flex; align-items:center; gap:.35rem; font-size:.8rem; color:var(--text); }
  .tm-dep-nom { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .tm-dep--ok .tm-dep-nom { color:var(--muted-2); text-decoration:line-through; }
  .tm-dep-x { flex-shrink:0; border:none; background:none; color:var(--muted-2); cursor:pointer;
    padding:.1rem .3rem; border-radius:.3rem; font-size:.72rem; line-height:1; }
  .tm-dep-x:hover { color:var(--danger); background:var(--panel-2); }
  @media (prefers-reduced-motion: reduce) {
    .dep-nodo, .dep-cable { transition:none; }
    .dep-nodo--destino, .dep-nodo:hover { transform:none; }
  }
  /* El `:not(.pd-task--sel)` es para que seleccionar una tarjeta CON color se
     siga viendo: esta regla tiene dos clases y le ganaba a `.pd-task--sel`, que
     tiene una, asi que a las pintadas les devolvia el fondo blanco. Quedaban con
     el borde rojo pero sin el rosa, y al lado de las otras no parecian elegidas. */
  .pdk-card.pd-task--color:not(.pd-task--sel) { background:var(--panel); }
  .pdk-card.pd-task--color:not(.pd-task--sel):hover { background:var(--panel); }
  /* Cuelga del borde de arriba, en la fila del titulo y antes de la "i". Absoluta se
     le montaba al texto cuando el nombre ocupa varias lineas. */
  .pdk-flag { flex-shrink:0; align-self:flex-start; width:12px; height:20px;
    margin:-.75rem .2rem 0 .3rem; background:var(--task-color);
    clip-path:polygon(0 0, 100% 0, 100% 100%, 50% 68%, 0 100%);
    filter:drop-shadow(0 1px 1px rgba(0,0,0,.12)); }
  /* La bandera asoma fuera de la tarjeta: la columna no puede recortarla. */
  .pdk-col-tasks { overflow:visible; }

  /* Hecha + pintada: con el gris de "hecha" sobre el fondo pastel el texto quedaba
     en 3.4:1. Se oscurece lo justo para que se siga leyendo tachado. */
  .pdk-card--done.pd-task--color .pdk-name,
  .pd-task--done.pd-task--color .pd-task-name { color:color-mix(in srgb, var(--text) 62%, transparent); }
  .pd-task-due { display:inline-flex; align-items:center; gap:.2rem; flex-shrink:0;
    font-size:.68rem; font-weight:700; color:var(--muted); background:var(--panel-2);
    border:1px solid var(--line); border-radius:999px; padding:.05rem .4rem; }
  .pd-task-due--tarde { color:var(--danger); background:color-mix(in srgb,var(--danger) 8%,transparent);
    border-color:color-mix(in srgb,var(--danger) 25%,transparent); }
  .pd-inline-form { margin:.35rem 0 0; }
  /* Boton de comentar: reemplaza al input que vivia abierto debajo de cada tarea. */
  .pd-cbtn { display:inline-flex;align-items:center;gap:.2rem;border:1px solid transparent;background:none;
    color:var(--muted-2);cursor:pointer;padding:.2rem .3rem;border-radius:.4rem;font-family:inherit;
    transition:color .12s,background .12s,border-color .12s; }
  .pd-cbtn:hover { color:var(--brand);background:var(--panel-2); }
  .pd-cbtn--con { color:var(--muted); }
  .pd-cbtn-n { font-size:.68rem;font-weight:700;line-height:1; }
  /* Sin comentarios y con el form cerrado, el contenedor no debe dejar aire muerto. */
  .pd-comments--vacia { margin:0; }
  .pd-comments--vacia:not(.pd-comments--abierta) { display:none; }
  .pd-inline-input { font-size:.82rem; padding:.35rem .55rem; }        /* que entren las 4 columnas sin scroll */
  #tutKbMock .pdk-col { min-width:0; flex:1 1 0; }
  #tutKbMock .pdk-col-tasks { background:color-mix(in srgb, var(--line) 22%, transparent); border-radius:.5rem; }

/* ── Selector de menciones ──────────────────────────────────────────────
   Capa fija sobre todo, como los tooltips: adentro de un modal, un desplegable
   absoluto lo recorta el .modal-card con overflow:hidden. */
.mn-pop { position: fixed; z-index: 4000; max-height: 12rem; overflow-y: auto;
  border: 1px solid var(--line); border-radius: .5rem; background: var(--panel);
  box-shadow: 0 8px 22px rgba(0,0,0,.16); }
.mn-op { display: flex; align-items: center; gap: .5rem; width: 100%; text-align: left;
  border: none; background: none; padding: .4rem .6rem; font-family: inherit;
  font-size: .82rem; color: var(--text); cursor: pointer;
  /* Un nombre largo se corta con puntos suspensivos en vez de partir la fila en
     dos: con dos renglones la lista deja de leerse como lista. */
  white-space: nowrap; overflow: hidden; }
.mn-op > span:first-child, .mn-op::first-line { min-width: 0; }
.mn-op:hover, .mn-op--on { background: var(--panel-2); }

.mn-vacio { padding: .45rem .6rem; font-size: .78rem; color: var(--muted-2); }

/* ── Proyecto de una nota: dropdown propio ──────────────────────────────
   Un <select> nativo dibuja su lista con el sistema operativo: no sigue el tema
   y con muchos proyectos tapa media pantalla. */
.nt-proy-wrap { position: relative; display: inline-flex; }
.nt-proy-btn { display: inline-flex; align-items: center; gap: .3rem; border: none;
  background: none; padding: 0; font-family: inherit; font-size: .78rem;
  font-weight: 600; color: var(--muted); cursor: pointer; }
.nt-proy-btn:hover { color: var(--text); }
.nt-proy-pop { position: absolute; left: 0; bottom: calc(100% + 6px); z-index: 60;
  width: 17rem; border: 1px solid var(--line); border-radius: .55rem;
  background: var(--panel); box-shadow: 0 8px 22px rgba(0,0,0,.16); overflow: hidden; }
.nt-proy-buscar { width: 100%; box-sizing: border-box; border: none;
  border-bottom: 1px solid var(--line); background: none; padding: .5rem .6rem;
  font-family: inherit; font-size: .82rem; color: var(--text); }
.nt-proy-buscar:focus { outline: none; }
.nt-proy-lista { max-height: 12rem; overflow-y: auto; }
.nt-proy-op { display: block; width: 100%; text-align: left; border: none;
  background: none; padding: .42rem .6rem; font-family: inherit; font-size: .82rem;
  color: var(--text); cursor: pointer; }
.nt-proy-op:hover { background: var(--panel-2); }
.nt-proy-aviso { padding: .42rem .6rem; font-size: .76rem; color: var(--muted-2); }

/* El enlace compartido, en su modal. */
/* El aviso de arriba y el primer campo: sin esto la etiqueta quedaba pegada a
   la caja gris de arriba. */
.cp-aviso { margin-top: 0; }
.cp-lbl { display: block; margin-top: 1.2rem; margin-bottom: .3rem; }

.cp-copiar { display:flex; gap:.4rem; align-items:center; }
.cp-copiar .form-input { flex:1; font-family:'JetBrains Mono', monospace; font-size:.78rem; }
.cp-datos { margin:.6rem 0 0; font-size:.76rem; color:var(--muted); }

/* ── El editor de una nota (_nota_modal.html) ───────────────────────────
   Lo abre /notas. Los estilos viven acá y no en notas.html para que el modal
   no dependa de la pantalla que lo incluye. */
.nt-modal-txt { width:100%; box-sizing:border-box; min-height:11rem; resize:vertical;
  font-family:inherit; font-size:.88rem; line-height:1.6; }
.nt-modal-fila { display:flex; gap:.5rem; align-items:center; margin-bottom:.6rem; }

/* Título: se ve como encabezado, no como campo. El input aparece recién al
   tocar el lápiz, y sin caja para que no salte la altura. */
.nt-tit { display:flex; align-items:center; gap:.3rem; margin-bottom:.7rem; }
.nt-tit-ver, .nt-tit-input { max-width:100%; min-width:0; border:none; background:none; padding:0;
  font-family:inherit; font-size:1rem; font-weight:700; color:var(--text); line-height:1.4;
  text-align:left; }
.nt-tit-input { flex:1; }
.nt-tit-ver { cursor:text; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.nt-tit-ver--vacio { color:var(--muted-2); font-weight:600; }
.nt-tit-input:focus { outline:none; box-shadow:none; }
.nt-tit-lapiz { border:none; background:none; padding:.2rem; color:var(--muted-2);
  cursor:pointer; border-radius:.35rem; display:inline-flex; }
.nt-tit-lapiz:hover { color:var(--brand); background:var(--panel-2); }

/* Personas: van debajo del texto, así sumar gente no mueve nada de arriba. */
.nt-pers-pie { display:flex; align-items:center; flex-wrap:wrap; gap:.35rem; margin-top:.6rem; }
.nt-pers-chips { display:flex; flex-wrap:wrap; gap:.3rem; }
.nt-proy { display:inline-flex; align-items:center; gap:.3rem; color:var(--muted);
  font-size:.78rem; font-weight:600; }
.nt-proy-sel { border:none; background:none; padding:0 .1rem; font-family:inherit;
  font-size:.78rem; font-weight:600; color:inherit; cursor:pointer; max-width:11rem; }
.nt-proy-sel:focus { outline:none; }
.nt-proy:hover, .nt-proy:focus-within { color:var(--brand); }
.nt-pie-sep { width:1px; height:14px; background:var(--line); }

.nt-pers-sumar { display:inline-flex; align-items:center; gap:.3rem; border:none;
  background:none; padding:0; font-family:inherit; font-size:.78rem; font-weight:600;
  color:var(--muted); cursor:pointer; }
.nt-pers-sumar span { text-decoration:underline; text-underline-offset:3px;
  text-decoration-color:var(--line); }
.nt-pers-sumar:hover { color:var(--brand); }
.nt-pers-sumar:hover span { text-decoration-color:currentColor; }
.nt-pers-sumar--con { color:var(--brand); }
.nt-pers-i { display:inline-flex; color:var(--muted-2); cursor:help; }

.nt-modal2 { z-index:1200; }   /* por encima del modal de la nota */
/* La tarjeta recorta por defecto (esquinas redondeadas) y se comia el desplegable. */
#ntPersModal .modal-card { overflow:visible; }
#ntPersModal .modal-head { border-top-left-radius:inherit; border-top-right-radius:inherit; }
#ntPersModal .modal-actions { border-bottom-left-radius:inherit; border-bottom-right-radius:inherit; }
/* Espacio para que el desplegable tenga donde caer sin tapar el boton Listo. */
#ntPersModal .modal-body { min-height:9rem; }
.nt-pers { position:relative; }
.nt-pers-elegidas { display:flex; flex-wrap:wrap; gap:.3rem; }
.nt-pers-elegidas:not(:empty) { margin-top:.6rem; }
.nt-pers-nadie { margin:.6rem 0 0; font-size:.75rem; color:var(--muted-2); }
.nt-pers-chip { display:inline-flex; align-items:center; gap:.25rem; font-size:.72rem;
  font-weight:700; color:var(--brand); background:color-mix(in srgb, var(--brand) 8%, transparent);
  border:1px solid color-mix(in srgb, var(--brand) 25%, transparent); border-radius:999px;
  padding:.18rem .35rem .18rem .55rem; }
.nt-pers-chip-x { border:none; background:none; padding:0 .1rem; color:inherit; opacity:.7;
  font-size:.7rem; line-height:1; cursor:pointer; }
.nt-pers-chip-x:hover { opacity:1; }
/* Flota sobre lo que haya debajo en vez de empujarlo: el modal no cambia de
   tamaño mientras buscás. Necesita que la tarjeta no recorte (ver .nt-modal2). */
.nt-pers-lista { position:absolute; z-index:5; left:0; right:0; top:100%; margin-top:.35rem;
  max-height:13rem; overflow-y:auto; background:var(--panel); border:1px solid var(--line);
  border-radius:.5rem; box-shadow:0 10px 28px rgba(0,0,0,.16); padding:.25rem; }
.nt-pers-op { display:block; width:100%; text-align:left; border:none; background:none;
  padding:.35rem .5rem; border-radius:.35rem; font-size:.8rem; color:var(--text); cursor:pointer; }
.nt-pers-op:hover { background:var(--panel-2); }
.nt-pers-hint { position:absolute; z-index:5; left:0; right:0; top:100%; margin:.35rem 0 0;
  background:var(--panel); border:1px solid var(--line); border-radius:.5rem;
  box-shadow:0 10px 28px rgba(0,0,0,.16); padding:.4rem .5rem; font-size:.75rem; color:var(--muted); }

  .nt-card-adj { display:inline-flex; align-items:center; gap:.15rem; margin-left:.35rem;
    font-size:.7rem; font-weight:700; color:var(--muted-2); cursor:help; vertical-align:middle; }
  /* Adjuntos de una nota. */
  .nt-arch { display:flex; flex-wrap:wrap; gap:.35rem; margin-top:.5rem; }
  .nt-arch-mini { width:26px; height:26px; border-radius:.25rem; object-fit:cover;
    flex-shrink:0; background:var(--panel); }
  .nt-arch-ico { display:inline-flex; align-items:center; justify-content:center;
    width:26px; height:20px; border-radius:.25rem; flex-shrink:0;
    background:var(--panel); border:1px solid var(--line);
    font-size:.54rem; font-weight:700; color:var(--muted); letter-spacing:.02em; }
  .nt-arch-it { display:inline-flex; align-items:center; gap:.35rem; padding:.15rem .3rem .15rem .25rem;
    border:1px solid var(--line); border-radius:999px; background:var(--panel-2); font-size:.76rem; }
  .nt-arch-ver { font-size:.76rem; color:var(--text); text-decoration:none; }
  .nt-arch-ver:hover { color:var(--brand); text-decoration:underline; }
  .nt-arch-x { border:none; background:none; color:var(--muted-2); cursor:pointer;
    padding:0 .15rem; font-size:.72rem; line-height:1; }
  .nt-arch-x:hover { color:var(--danger); }

/* ── El formulario de un modal ──────────────────────────────────────────
   Lo comparten los modales donde se CARGA algo (anotar una tarea). Vivía adentro de una plantilla, pero una copia por pantalla es como
   se van desincronizando: el mismo campo opcional se veía distinto en cada una. */
/* El modal de anotar una tarea. */
.mf-modal .modal-head h3 { display:flex; align-items:center; gap:.55rem; }
.mf-ico {
  display:inline-flex; align-items:center; justify-content:center;
  width:30px; height:30px; border-radius:.6rem; flex-shrink:0;
  background: color-mix(in srgb, var(--brand) 10%, transparent); color: var(--brand);
}
/* Cuál es el único campo obligatorio: era una pila de cuatro y la gente los
   llenaba todos creyendo que hacían falta. */
.mf-lbl { display:flex; align-items:center; gap:.45rem; margin-top:1.1rem; line-height:1; }
.mf-modal .modal-body > .mf-lbl:first-child { margin-top:0; }
.mf-req, .mf-opc {
  display:inline-flex; align-items:center; line-height:1;
  padding:.2rem .4rem; border-radius:.35rem;
  font-size:.66rem; font-weight:700; letter-spacing:.02em; text-transform:none;
}
.mf-req { background: color-mix(in srgb, var(--brand) 11%, transparent); color: var(--brand); }
.mf-opc { background: var(--panel-2); color: var(--muted-2); }
.mf-fila { display:grid; grid-template-columns:repeat(auto-fit, minmax(11rem,1fr)); gap:0 .9rem; }
/* `.modal-body p` de portal.css pone margin:0 y le ganaba por especificidad: por
   eso la nota quedaba pegada a los selects aunque acá dijera otra cosa. */
.mf-modal .modal-body .mf-nota {
  display:flex; align-items:flex-start; gap:.5rem; margin:1.5rem 0 0;
  padding:.6rem .7rem; border-radius:.55rem; background:var(--panel-2);
  font-size:.76rem; color:var(--muted); line-height:1.45;
}
.mf-modal .mf-nota svg { flex-shrink:0; margin-top:.1rem; color:var(--muted-2); }

/* ── Select propio ──────────────────────────────────────────────────────
   La lista de un <select> la dibuja el SISTEMA OPERATIVO: fondo blanco y azul
   Windows aunque el portal esté en oscuro, tipografía ajena, y adentro de un
   modal se recorta sola. El <select> se queda (es el que tiene el valor y tira
   el change); lo único que se reemplaza es la lista que se abre.
   Se prende con data-selp en el <select>. */
.selp-pop { position: fixed; z-index: 1300; border: 1px solid var(--line);
  border-radius: .55rem; background: var(--panel);
  box-shadow: 0 8px 22px rgba(0,0,0,.16); overflow-y: auto; max-height: 15rem;
  padding: .25rem; }
.selp-op { display: block; width: 100%; text-align: left; border: none;
  background: none; padding: .42rem .55rem; border-radius: .4rem;
  font-family: inherit; font-size: .82rem; color: var(--text); cursor: pointer;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.selp-op:hover, .selp-op.selp-op--foco { background: var(--panel-2); }
.selp-op--sel { font-weight: 600; color: var(--brand); }
/* Un sprint cerrado se muestra pero no se elige: que desaparezca de la lista
   haría pensar que la tarea nunca estuvo ahí. */
.selp-op--off { color: var(--muted-2); cursor: default; }
.selp-op--off:hover { background: none; }
/* Pegado arriba y OPACO. Tenía dos `background` y ganaba el segundo, que era
   `none`: la lista scrolleaba por debajo del buscador y se veían las dos cosas
   encimadas — el placeholder «Buscar…» arriba del primer proyecto. Con fondo
   propio, lo que pasa por atrás no se ve. */
.selp-buscar { position: sticky; top: 0; z-index: 1; background: var(--panel);
  width: 100%; box-sizing: border-box; border: none;
  border-bottom: 1px solid var(--line); padding: .45rem .55rem;
  margin-bottom: .25rem; font-family: inherit; font-size: .82rem; color: var(--text); }
.selp-buscar:focus { outline: none; }
.selp-nada { padding: .5rem .55rem; font-size: .78rem; color: var(--muted-2); }

/* Rastro de menciones: un punto donde hay algo que te nombra más adentro. */
.mn-punto { display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--brand); flex-shrink: 0; cursor: help; }
.mn-punto--esq { position: absolute; top: .55rem; right: .55rem; }
/* En una tarea el número sí es real: son las menciones de ESA tarea. */
.mn-cuenta { display: inline-flex; align-items: center; justify-content: center;
  min-width: 16px; height: 16px; padding: 0 4px; border-radius: 999px;
  background: var(--brand); color: var(--on-brand); font-size: .62rem;
  font-weight: 700; cursor: help; flex-shrink: 0; }
.mn-nombre { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Una mención, ya escrita: se lee como una referencia y no como texto suelto. */
.mn-chip { display: inline-block; padding: 0 .3rem; border-radius: .3rem;
  font-weight: 600; color: var(--brand);
  background: color-mix(in srgb, var(--brand) 10%, transparent); }

/* El nombre de lo adjuntado o enlazado, DENTRO del texto de la nota. Mismo
   mecanismo que la mencion (se pinta al mostrar, lo guardado sigue siendo texto)
   pero con otra forma: la mencion es una cajita porque nombra a una PERSONA a la
   que le llega un aviso; esto lleva a un archivo, y lo que lleva a algun lado en
   esta app se ve como un enlace. Con dos cajitas en el mismo renglon no se
   distinguia una cosa de la otra.
   (Las clases siguen diciendo "chip" por lo que eran; lo que importa es a donde
   llevan, no como se llaman.) */
.cv-ref-chip, .mn-ref { color: var(--brand); text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--brand) 45%, transparent);
  text-underline-offset: 2px; }
a.cv-ref-chip { cursor: pointer; }
a.cv-ref-chip:hover { text-decoration-color: var(--brand); }
/* En el editor no navega: ahi es un bloque atomico que se escribe alrededor, y
   el cursor de mano prometeria un click que no hace nada. */
.mn-ref { cursor: default; }

/* Editor con chips: reemplaza al textarea al enfocarlo (ver _menciones_js.html). */
.mn-editor { min-height: 5.5rem; max-height: 16rem; overflow-y: auto;
  white-space: pre-wrap; word-break: break-word; text-align: left; cursor: text; }
.mn-editor:empty::before { content: attr(data-vacio); color: var(--muted); }
.mn-editor:focus { outline: none; border-color: var(--brand);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 16%, transparent); }
/* Adentro del editor el chip no se edita: por eso el backspace se lo lleva entero. */
.mn-editor .mn-chip { user-select: none; }

/* Tabla pegada dentro de una nota o un comentario. Se arma al mostrar, a partir
   del texto separado por tabs (Excel, Sheets) o por pipes (Markdown a mano). */
.tx-tabla { border-collapse: collapse; margin: .5rem 0; font-size: .82rem;
  /* En un ancho chico scrollea ella sola, no la pagina. */
  display: block; max-width: 100%; overflow-x: auto; white-space: normal; }
.tx-tabla th, .tx-tabla td { border: 1px solid var(--line); padding: .3rem .55rem;
  text-align: left; vertical-align: top; }
.tx-tabla th { background: var(--panel-2); font-weight: 700; color: var(--text); }
.tx-tabla td { color: var(--text-2); }

/* ── El editor de markdown (Toast UI) ──
   Lo usan la descripción de una tarea y sus comentarios: la clase `md-ed`
   va en la caja donde se monta, así el mismo aspecto vale para los dos.
   Se escribe y se lee con el MISMO motor, así que lo que uno ve mientras
   escribe es lo que queda. Acá sólo se lo mete en la caja: el editor trae su
   propio CSS (/static/vendor/toastui), y lo que sigue es para que no imponga su
   tipografía ni su blanco encima del portal. */
.md-ed .toastui-editor-defaultUI { border-radius: 8px; border-color: var(--line); }

/* La tarjeta del modal recorta lo que se sale (`overflow: hidden`), y los
   desplegables de la barra del editor se salen a propósito: quedaban cortados a
   la mitad. Donde hay editor, la tarjeta no recorta. */
.modal-card:has(.md-ed) { overflow: visible; }
.tm-desc-ed { margin: 0 0 .2rem; }
/* Adentro del modal el editor es un campo, no una hoja: barra y texto más
   compactos, y el alto lo pone lo que se escribe (height: auto) con un piso
   bajo. Con los tamaños de fábrica ocupaba media pantalla en blanco.
   Los iconos son UN PNG con las posiciones en píxeles: achicar el botón —o
   dibujar la barra con zoom— los recorta. Se los deja en su tamaño y lo que se
   recorta es el aire de alrededor. */
.md-ed .toastui-editor-toolbar, .md-ed .toastui-editor-defaultUI-toolbar { height: 36px; }
.md-ed .toastui-editor-defaultUI-toolbar { padding: 0 .25rem; }
/* Los dibujos son UN PNG y el botón de fábrica mide 32: la celda del dibujo queda
   pegada a la izquierda y sobra aire a la derecha. Con el botón del tamaño de la
   celda (26) el aire va afuera, en el margen. */
.md-ed .toastui-editor-defaultUI-toolbar button { height: 22px; width: 22px; margin: 7px 2px; }
/* Y cada dibujo, más chico (82%) y centrado en su botón. De fábrica vienen a
   distinto tamaño aparente y un par de píxeles corridos, y con el botón justo se
   nota. Estas posiciones están MEDIDAS sobre el PNG de esta versión del editor
   (3.2.2): dónde empieza y dónde termina la tinta de cada dibujo, escalado y
   centrado en la caja de 26. Si algún día se actualiza el editor, hay que volver
   a medirlas. */
/* background-origin: el botón trae un borde de 1px, y el dibujo se apoya por
   defecto ADENTRO del borde: eso lo corre un píxel a la derecha y para abajo
   respecto del cuadrado que uno ve. Apoyándolo en el borde, las cuentas de abajo
   —que están hechas sobre los 22px del botón— caen donde tienen que caer. */
.md-ed .toastui-editor-toolbar-icons { background-size: 382.1px 119.7px;
  background-origin: border-box; }
.md-ed .toastui-editor-toolbar-icons.heading { background-position: 1.2px 1.2px; }
.md-ed .toastui-editor-toolbar-icons.bold { background-position: -20.2px 1.2px; }
.md-ed .toastui-editor-toolbar-icons.italic { background-position: -41.1px 1.2px; }
.md-ed .toastui-editor-toolbar-icons.strike { background-position: -62.8px 1.2px; }
.md-ed .toastui-editor-toolbar-icons.hrline { background-position: -84.1px 1.2px; }
.md-ed .toastui-editor-toolbar-icons.quote { background-position: -105.4px 1.6px; }
.md-ed .toastui-editor-toolbar-icons.bullet-list { background-position: -126.8px 1.2px; }
.md-ed .toastui-editor-toolbar-icons.ordered-list { background-position: -148.1px 1.6px; }
.md-ed .toastui-editor-toolbar-icons.task-list { background-position: -169.4px 1.2px; }
.md-ed .toastui-editor-toolbar-icons.indent { background-position: -190.7px 1.2px; }
.md-ed .toastui-editor-toolbar-icons.outdent { background-position: -212px 1.2px; }
.md-ed .toastui-editor-toolbar-icons.table { background-position: -233.4px 1.2px; }
.md-ed .toastui-editor-toolbar-icons.image { background-position: -254.7px 1.2px; }
.md-ed .toastui-editor-toolbar-icons.link { background-position: -276px 1.2px; }
.md-ed .toastui-editor-toolbar-icons.code { background-position: -296.9px 1.2px; }
.md-ed .toastui-editor-toolbar-icons.codeblock { background-position: -318.6px 1.2px; }
.md-ed .toastui-editor-toolbar-icons.more { background-position: -340px 1.6px; }
.md-ed .toastui-editor-toolbar-divider { height: 16px; margin: 10px .3rem; }
/* El editor va siempre en WYSIWYG y sin interruptor (hideModeSwitch), así que
   las pestañas «Escribir / Vista previa» del modo markdown no se ven nunca. Se
   las esconde igual por si alguna vez se vuelve a ofrecer el modo: en esta
   columna angosta se meten a la IZQUIERDA de la barra, se comen media fila de
   botones y el texto arranca corrido. El !important es porque ese display lo
   pone el editor por JS, en el atributo style. */
.md-ed .toastui-editor-defaultUI .toastui-editor-md-tab-container { display: none !important; }
.md-ed .toastui-editor-defaultUI .toastui-editor-md-container .toastui-editor,
.md-ed .toastui-editor-defaultUI .ProseMirror { font-size: .86rem; }
/* Lo escribible tiene que llegar hasta abajo del todo. El editor deja el área de
   texto del alto del CONTENIDO, así que en un campo vacío los tres cuartos de
   abajo eran un hueco muerto: se tocaba ahí para escribir, no entraba el cursor
   —y el editor se llevaba el foco a la barra, que abría el desplegable de
   encabezados—. Con el editor en columna, lo escribible estira. */
.md-ed .toastui-editor-ww-container .toastui-editor,
.md-ed .toastui-editor-md-container .toastui-editor { display: flex; flex-direction: column; }
.md-ed .toastui-editor-ww-container .ProseMirror { flex: 1 1 auto; }
.md-ed .toastui-editor-mode-switch { height: 26px; font-size: .72rem; }
.md-ed .toastui-editor-mode-switch .tab-item { height: 24px; line-height: 22px; padding: 0 .6rem; }
/* El globito de cada botón de la barra, igual que el del portal (.tip-pop).
   Lleva `body` adelante porque el CSS del editor se inyecta DESPUÉS que este
   archivo: empatando en especificidad, gana el último. */
body .toastui-editor-tooltip { background: #262626; border-radius: 9px;
  width: auto; height: auto; padding: .4rem .6rem; line-height: 1;
  white-space: nowrap; box-shadow: 0 6px 20px rgba(0,0,0,.18); z-index: 3000; }
body .toastui-editor-tooltip .text { display: inline-block;
  font-family: 'Inter', sans-serif; font-size: .72rem; font-weight: 400;
  line-height: 1.2; color: #e6e6e4; }
body .toastui-editor-tooltip .arrow { display: none; }
[data-theme="dark"] body .toastui-editor-tooltip { background: #27272a; }
/* La barra y los menús del editor, con la letra del portal. */
.toastui-editor-defaultUI, .toastui-editor-contents, .toastui-editor-popup { font-family: inherit; }
/* Lo ya escrito, mostrado. Compacto: adentro del modal, los márgenes de un
   documento dejaban la descripción con más aire que texto. */
.md-ver .toastui-editor-contents { font-size: .88rem; color: var(--text); }
.md-ver .toastui-editor-contents p,
.md-ver .toastui-editor-contents ul,
.md-ver .toastui-editor-contents ol { margin: .25rem 0; color: var(--text); }
.md-ver .toastui-editor-contents h1,
.md-ver .toastui-editor-contents h2,
.md-ver .toastui-editor-contents h3,
.md-ver .toastui-editor-contents h4 { margin: .6rem 0 .3rem; padding: 0; border: none;
  color: var(--text); font-weight: 700; }
.md-ver .toastui-editor-contents h1 { font-size: 1.08rem; }
.md-ver .toastui-editor-contents h2 { font-size: 1rem; }
.md-ver .toastui-editor-contents h3, .md-ver .toastui-editor-contents h4 { font-size: .92rem; }
.md-ver .toastui-editor-contents table { margin: .45rem 0; }
.md-ver .toastui-editor-contents th { background: var(--panel-2); color: var(--text); }
.md-ver .toastui-editor-contents td, .md-ver .toastui-editor-contents th { border-color: var(--line); }
.md-ver .toastui-editor-contents blockquote { border-left-color: var(--line); color: var(--muted); }
.md-ver .toastui-editor-contents pre, .md-ver .toastui-editor-contents code {
  background: var(--panel-2); color: var(--text); }
/* Los checkboxes de una lista de tareas del markdown se ven, pero no se tocan:
   la checklist de verdad es la de abajo, con su historial y su gente. */
.md-ver .toastui-editor-contents input[type="checkbox"] { pointer-events: none; }
.md-ver .toastui-editor-contents :first-child { margin-top: 0; }
.md-ver .toastui-editor-contents :last-child { margin-bottom: 0; }

/* ── Selección múltiple de tareas ──
   Ctrl + click marca varias y arrastrar una las arrastra a todas. Mientras se
   arrastran NO se mueven los nodos: se dibuja un mazo flotante (.pd-mazo) que
   sigue al cursor, y las tarjetas se quedan en su lugar. Por eso soltar en la
   nada no necesita deshacer nada. Ver app/templates/_tareas_js.html. */
.pd-task--sel { outline: 2px solid var(--brand); outline-offset: 1px;
  background: var(--brand-light, color-mix(in srgb, var(--brand) 6%, transparent)); }

.pd-sel-barra { position: fixed; left: 50%; bottom: calc(1.4rem + var(--tabbar-h, 0px)); z-index: 190;
  transform: translateX(-50%); display: flex; align-items: center; gap: .5rem;
  padding: .5rem .75rem; border-radius: 999px; font-size: .82rem;
  background: var(--panel); color: var(--text); border: 1px solid var(--line);
  box-shadow: 0 8px 24px rgba(0,0,0,.18); }
.pd-sel-n { display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.35rem; height: 1.35rem; padding: 0 .35rem; border-radius: 999px;
  background: var(--brand); color: var(--on-brand); font-weight: 700; font-size: .78rem; }
.pd-sel-tip { color: var(--muted); font-size: .76rem; }
.pd-sel-tip kbd { font: inherit; border: 1px solid var(--line-2); border-radius: .25rem;
  padding: 0 .25rem; }
.pd-sel-x { border: none; background: none; color: var(--muted-2); cursor: pointer;
  font-size: .8rem; line-height: 1; padding: .15rem .2rem; }
.pd-sel-x:hover { color: var(--text); }

/* El mazo. `pointer-events:none` es lo que lo hace funcionar: si interceptara el
   mouse, taparía la zona sobre la que estás por soltar. */
.pd-mazo { position: fixed; top: 0; left: 0; z-index: 300; pointer-events: none;
  will-change: transform; }
.pd-mazo-it { position: absolute; box-shadow: 0 6px 18px rgba(0,0,0,.22);
  opacity: .95; background: var(--panel); border-radius: var(--radius-sm); }
/* El contador va arriba a la DERECHA: el mazo cuelga abajo-derecha del cursor, y
   a la izquierda quedaba justo debajo del puntero. */
.pd-mazo-n { position: absolute; top: -.55rem; right: -.55rem; z-index: 20;
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.5rem; height: 1.5rem; padding: 0 .35rem; border-radius: 999px;
  background: var(--brand); color: var(--on-brand); font-weight: 700; font-size: .8rem;
  box-shadow: 0 2px 8px rgba(0,0,0,.25); }

/* El tacho aparece recién al arrastrar: un botón de borrar siempre visible en la
   esquina es una invitación a tocarlo sin querer. */
.pd-tacho { position: fixed; top: 4.6rem; right: 1.4rem; z-index: 295;
  display: flex; align-items: center; gap: .5rem; padding: .7rem 1rem;
  border-radius: .7rem; font-size: .82rem; font-weight: 600;
  background: var(--bad-light); color: var(--bad); border: 1.5px dashed var(--bad);
  animation: pdTachoIn .18s ease; }
.pd-tacho--on { background: var(--bad); color: #fff; border-style: solid;
  transform: scale(1.06); }
@keyframes pdTachoIn { from { opacity: 0; transform: translateY(-6px); } }
@media (prefers-reduced-motion: reduce) {
  .pd-tacho { animation: none; }
  .pd-tacho--on { transform: none; }
}

/* Un sprint del costado, marcado como destino del arrastre. */
.pd-side-it--drop { outline: 2px solid var(--brand); outline-offset: -2px;
  background: var(--panel-2); }

/* "Historial" mientras arrastrás una tarjeta: se marca y, si te quedás, se abre
   solo. No lleva .pd-side-it--drop porque ese lo limpia el dragover del documento
   —el botón no es un destino, abre la lista— y la marca desaparecía al instante. */
.pd-side-hist-btn--drop { outline: 2px dashed var(--brand); outline-offset: -2px;
  background: var(--panel-2); }

/* El id de la tarea, a la izquierda del título del modal. Gris y en peso normal:
   sirve para nombrarla ("mirá la #412"), no compite con el título. */
.tm-id { color: var(--muted-2); font-weight: 500; margin-right: .4rem; }

/* ── Visor de adjuntos ──
   Un modal grande (no pantalla completa: se probó y se sentía "otra pantalla",
   no una vista de algo del portal). Es el mismo para un adjunto de una tarea o
   de una nota, y se alimenta del fragmento que ya existía
   (_archivo_preview.html), así que no reimplementa cómo se muestra cada tipo. */
/* El velo tapa TODO, navbar incluido: probamos dejándolo afuera y quedaba una
   franja nítida arriba, como si el modal no le llegara. Y va por ENCIMA de los
   otros modales: se abre desde el modal de una tarea, y con un z-index menor
   quedaba atrás. */
/* Con el visor abierto, el velo del modal de atrás sólo asomaría en la franja del
   navbar, borroso y solo, encima del velo del visor: se veía como un error. Se
   apaga mientras dura el visor. */
body.visor-abierto .modal-backdrop { background: transparent; backdrop-filter: none; }

.vs-back { position: fixed; inset: 0; z-index: 2300;
  display: flex; align-items: center; justify-content: center;
  padding: 1.1rem;
  background: rgba(15, 28, 46, 0.25);
  backdrop-filter: blur(7px) saturate(150%);
  animation: vsEntra .16s ease-out; }
@keyframes vsEntra { from { opacity: 0; } }

/* Grande igual: la gracia del visor es ver la imagen, no la tarjeta. */
.vs-caja { width: min(1400px, 100%); height: 100%; display: flex; flex-direction: column;
  background: var(--panel); border: 1px solid var(--line); border-radius: .8rem;
  overflow: hidden; box-shadow: 0 18px 48px rgba(0,0,0,.22);
  animation: vsSube .16s ease-out; }
@keyframes vsSube { from { transform: translateY(8px) scale(.99); } }

.vs-bar { display: flex; align-items: center; gap: .6rem; flex-shrink: 0;
  padding: .5rem .8rem; border-bottom: 1px solid var(--line); background: var(--panel); }
.vs-nombre { font-weight: 600; font-size: .9rem; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1; min-width: 0; }
.vs-ctrls { display: flex; align-items: center; gap: .25rem; flex-shrink: 0; }
.vs-nivel { font-size: .78rem; color: var(--muted); min-width: 3.2rem; text-align: center;
  font-variant-numeric: tabular-nums; }

.vs-btn { border: 1px solid var(--line-2); background: var(--panel); color: var(--text);
  border-radius: .4rem; width: 28px; height: 28px; font: inherit; font-size: .95rem;
  line-height: 1; cursor: pointer; display: inline-flex; align-items: center;
  justify-content: center; text-decoration: none; }
.vs-btn:hover { background: var(--panel-2); }
.vs-btn--txt { width: auto; padding: 0 .55rem; font-size: .78rem; }
.vs-cerrar { font-size: .8rem; }
.vs-cerrar:hover { background: var(--bad-light); color: var(--bad); border-color: var(--bad); }

/* `overflow:hidden` y no auto: la imagen se mueve por transform, no por scroll.
   Con scroll quedaban dos formas de mover lo mismo y peleaban entre sí. */
.vs-cuerpo { flex: 1; min-height: 0; overflow: hidden; display: flex;
  align-items: center; justify-content: center; padding: 1rem; }
.vs-cargando { color: var(--muted); font-size: .9rem; }

.vs-cuerpo .vs-img { max-width: 100%; max-height: 100%; width: auto; height: auto;
  object-fit: contain; transform-origin: center center; user-select: none;
  border-radius: .4rem; will-change: transform; }
.vs-cuerpo .pv-texto { max-width: 1000px; max-height: 100%; overflow: auto; margin: 0; }
.vs-cuerpo .pv-pdf { width: 100%; height: 100%; border: 1px solid var(--line);
  border-radius: .5rem; }
/* La cabecera del fragmento no va: el visor ya tiene su barra con el nombre y
   el botón de descargar. */
.vs-cuerpo .pv-modal-head { display: none; }

@media (max-width: 640px) {
  .vs-btn--txt { display: none; }     /* en el celu, sólo +/− y cerrar */
}
@media (prefers-reduced-motion: reduce) { .vs-back, .vs-caja { animation: none; } }

/* Entra volando desde la derecha, se pasa de largo y vuelve — el frenado de
   dibujito. El `translate(-50% ...)` va en TODOS los pasos: sin eso la etiqueta
   pierde el centrado a mitad de la animación y salta al costado al terminar.

   El `scaleX` es el squash & stretch de toda la vida: se estira mientras viaja
   rápido y se achata cuando clava el freno. Sin eso el rebote se lee como una
   transición de software; con eso, como una caricatura. */

/* La onda sale del CENTRO del logo, no de su borde: arrancando en el borde la
   expansión era de apenas 6px y no se notaba. Nace casi en cero, aparece
   mientras crece y se apaga antes de llegar al borde de la etiqueta — el tope
   de 1.14 sobre un logo de 40px da ~46px, y la caja interna mide 56px. */

/* El cuadro de confirmar SIEMPRE arriba de cualquier otra modal: es lo que se
   pregunta SOBRE lo que ya está abierto. Comparte `.modal-backdrop` con el resto
   (z-index 1100), así que sin esto gana el que va después en el documento — y
   quedaba tapado justo cuando hay que leerlo. */
#modalConfirm { z-index: 1180; }

/* Modal del sprint (_sprint_modal.html). */
/* Modal de un sprint: misma forma que el de una nota — el nombre como título con
   lápiz, los datos como una fila liviana al pie, y las acciones abajo. */
.sp-tit { display:flex; align-items:center; gap:.3rem; margin-bottom:.15rem; }
.sp-tit-ver, .sp-tit-input { max-width:100%; min-width:0; border:none; background:none;
  padding:0; font-family:inherit; font-size:1rem; font-weight:700; color:var(--text);
  line-height:1.4; text-align:left; }
.sp-tit-input { flex:1; }
.sp-tit-ver { cursor:text; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.sp-tit-ver--vacio { color:var(--muted-2); font-weight:600; }
.sp-tit-input:focus { outline:none; box-shadow:none; }
.sp-tit-lapiz { border:none; background:none; padding:.2rem; color:var(--muted-2);
  cursor:pointer; border-radius:.35rem; display:inline-flex; }
.sp-tit-lapiz:hover { color:var(--brand); background:var(--panel-2); }
/* Vacío no ocupa: en un sprint nuevo no hay nada que resumir y el hueco se notaba. */
.sp-resumen { margin:0; font-size:.82rem; color:var(--muted); line-height:1.5; }
.sp-resumen:not(:empty) { margin:.1rem 0 .2rem; }
.sp-nro { margin:.1rem 0 0; font-size:.72rem; color:var(--muted-2); }

.sp-pie { display:flex; align-items:center; flex-wrap:wrap; gap:.5rem;
  margin-top:1rem; padding-top:.85rem; border-top:1px solid var(--line); }
.sp-pie-item { display:inline-flex; align-items:center; gap:.35rem; font-size:.78rem;
  font-weight:600; color:var(--muted); }
.sp-pie-item input[type="checkbox"] { width:auto; margin:0; }
.sp-pie-sep { width:1px; height:14px; background:var(--line); }
/* Calendario del periodo del sprint (reemplaza los dos input[type=date]). */
.sp-cal-btn { border:none; background:none; padding:.1rem .15rem; font-family:inherit;
  font-size:.78rem; font-weight:600; color:inherit; cursor:pointer; border-radius:.35rem; }
.sp-cal-btn:hover, .sp-cal-btn--on { color:var(--brand); }
.sp-cal-btn--vacio { color:var(--muted-2); font-weight:500; }
.sp-cal { margin-top:.85rem; border:1px solid var(--line); border-radius:.6rem;
  padding:.6rem; background:var(--panel); }
.sp-cal-head { display:flex; align-items:center; justify-content:space-between;
  font-size:.8rem; font-weight:700; color:var(--text); text-transform:capitalize; margin-bottom:.5rem; }
.sp-cal-nav { border:none; background:none; cursor:pointer; color:var(--muted);
  font-size:1.1rem; line-height:1; padding:0 .45rem; border-radius:.3rem; }
.sp-cal-nav:hover { color:var(--brand); background:var(--panel-2); }
.sp-cal-dow, .sp-cal-grid { display:grid; grid-template-columns:repeat(7, 1fr); gap:2px; }
.sp-cal-dow { font-size:.65rem; font-weight:700; color:var(--muted-2); text-align:center;
  text-transform:uppercase; margin-bottom:.2rem; }
.sp-cal-d { border:none; background:none; font-family:inherit; font-size:.76rem;
  color:var(--text); cursor:pointer; padding:.34rem 0; border-radius:.35rem; }
.sp-cal-d--vacio { visibility:hidden; }
.sp-cal-d:hover { background:var(--panel-2); }
/* El "hoy" se marca con el borde y no con fondo: el fondo ya lo usa el rango. */
.sp-cal-d--hoy { box-shadow:inset 0 0 0 1px var(--muted-2); }
.sp-cal-d--medio { background:color-mix(in srgb, var(--brand) 12%, var(--panel)); border-radius:0; }
.sp-cal-d--punta { background:var(--brand); color:var(--on-brand); font-weight:700; box-shadow:none; }
.sp-cal-d--ini { border-radius:.35rem 0 0 .35rem; }
.sp-cal-d--fin { border-radius:0 .35rem .35rem 0; }
.sp-cal-d--ini.sp-cal-d--fin { border-radius:.35rem; }
.sp-cal-pie { display:flex; align-items:center; justify-content:space-between; gap:.5rem;
  margin-top:.5rem; padding-top:.5rem; border-top:1px solid var(--line);
  font-size:.72rem; color:var(--muted); }
.sp-pie-btn { margin-left:auto; border:1px solid var(--line); background:var(--panel);
  border-radius:.45rem; padding:.25rem .6rem; font-family:inherit; font-size:.76rem;
  font-weight:600; color:var(--muted); cursor:pointer; }
.sp-pie-btn:hover { color:var(--brand); border-color:var(--brand); }

.sp-tag { font-size:.62rem; font-weight:700; text-transform:uppercase; letter-spacing:.03em;
  padding:.05rem .35rem; border-radius:999px; flex-shrink:0; }
.sp-tag--activo { color:#16a34a; background:#16a34a1a; }
.sp-tag--cerrado { color:var(--muted-2); background:var(--panel-2); }
.sp-tag--vencido { color:#b45309; background:#f59e0b1a; }

/* Filtros: boton de lupa/embudo + su panel. */
.pd-filtros { display:inline-flex; }
.pd-filtro-btn { display:inline-flex; align-items:center; gap:.25rem; padding:.3rem .55rem;
  border:1px solid var(--line); background:var(--panel); border-radius:.5rem;
  color:var(--muted); font-family:inherit; font-size:.78rem; cursor:pointer; }
.pd-filtro-btn:hover { color:var(--brand); border-color:var(--brand); }
.pd-filtro-btn--on { color:var(--brand); border-color:var(--brand);
  background:color-mix(in srgb, var(--brand) 7%, transparent); }
.pd-filtro-n { font-size:.66rem; font-weight:700; }
.pd-mod--add { border:1px dashed var(--line-2); background:transparent; color:var(--muted);
  font-family:inherit; cursor:pointer; }
.pd-mod--add:hover { color:var(--brand); border-color:var(--brand); }
.pd-filtro-pop { min-width:240px; padding:.7rem .75rem; }
.pd-filtro-campo { display:block; margin-bottom:.7rem; }
.pd-filtro-campo .form-input { width:100%; box-sizing:border-box; font-size:.82rem; }
.pd-filtro-colores { display:flex; flex-wrap:wrap; gap:.3rem; }
.pd-filtro-color { width:20px; height:20px; border-radius:50%; border:2px solid transparent;
  cursor:pointer; box-shadow:0 0 0 1px var(--line) inset; }
.pd-filtro-color--todos { width:auto; height:auto; border-radius:999px; padding:.1rem .45rem;
  font-size:.7rem; font-weight:600; color:var(--muted); background:var(--panel-2);
  box-shadow:none; border:1px solid var(--line); }
/* La marca la pone el radio, no una clase del servidor: al tocar un color se veia
   igual que antes hasta apretar Aplicar, asi que no habia forma de saber que habias
   elegido. La clase del servidor queda para el estado inicial. */
.pd-filtro-color:has(input:checked) { border-color:var(--text); }
.pd-filtro-color--todos:has(input:checked) { color:var(--brand); border-color:var(--brand); }
/* "Todos" es un boton, no un input: se prende solo cuando no hay ningun color tildado. */
.pd-filtro-color--btn { font-family:inherit; cursor:pointer; }
.pd-filtro-color--on { color:var(--brand); border-color:var(--brand); }
.pd-filtro-pie { display:flex; justify-content:flex-end; gap:.4rem; }

.pd-add-btn { display:inline-flex; align-items:center; justify-content:center;
  width:26px; height:26px; flex-shrink:0; border:1px solid var(--line);
  background:var(--panel); border-radius:.5rem; color:var(--muted);
  font-family:inherit; font-size:1rem; line-height:1; cursor:pointer; }
.pd-add-btn:hover { color:var(--brand); border-color:var(--brand); }

.pd-modal-txt { width:100%; box-sizing:border-box; resize:vertical; min-height:7rem;
  font-family:inherit; font-size:.88rem; line-height:1.6; }
.pd-modal-pie { display:flex; align-items:center; gap:.7rem; margin-top:.6rem; }
/* Alta dentro de un modal: el campo aparece al pedirlo, no vive abierto. */
.pd-nuevo-btn { margin-top:.8rem; border:1px dashed var(--line-2); background:none;
  border-radius:999px; padding:.3rem .8rem; font-family:inherit; font-size:.78rem;
  font-weight:600; color:var(--brand); cursor:pointer; }
.pd-nuevo-btn:hover { border-color:var(--brand); background:color-mix(in srgb,var(--brand) 6%,transparent); }

.pd-team--add { border:1.6px dashed currentColor; background:none; color:var(--brand);
  cursor:pointer; font-family:inherit; }
.pd-team--add:hover { color:color-mix(in srgb, var(--brand) 80%, #000); }


/* Lista de calificaciones del proyecto */
.pd-obj-list { list-style:none; margin:.3rem 0 0; padding:0; display:flex; flex-direction:column; gap:.1rem; }
.pd-obj { display:flex; align-items:flex-start; gap:.6rem; padding:.45rem .1rem; border-top:1px solid var(--line); font-size:.88rem; }
.pd-obj:first-child { border-top:0; }
.pd-obj-mark { flex-shrink:0; width:20px; text-align:center; color:var(--muted-2); font-weight:700; }
.pd-obj-text { flex:1; min-width:0; display:flex; flex-direction:column; }

/* Aviso: proyecto Listo pero con tareas sin terminar */
.pd-warn { display:inline-flex; align-items:center; justify-content:center; width:19px; height:19px;
  border-radius:50%; background:#fef3c7; color:#b45309; border:1px solid #fcd34d;
  font-weight:800; font-size:.72rem; cursor:help; flex-shrink:0; }
[data-theme="dark"] .pd-warn { background:#f59e0b1f; border-color:#f59e0b55; color:#fcd34d; }

/* «Nadie todavía» en los datos del proyecto (Participantes). */
.pd-pos-none { color:var(--muted-2); font-style:italic; }

/* Participantes. Se pisan un poco entre si (margin negativo) para que se lean como
   un grupo y no como una lista mas de chips. */
.pd-part { display:flex; align-items:center; gap:.35rem; flex-wrap:wrap;
  margin:-.2rem 0 .6rem; }
.pd-part-av { position:relative; width:22px; height:22px; border-radius:50%; flex-shrink:0;
  display:inline-flex; align-items:center; justify-content:center; overflow:hidden;
  font-size:.6rem; font-weight:800; color:var(--muted); background:var(--panel-2);
  border:1.5px solid var(--panel); box-shadow:0 0 0 1px var(--line); }
.pd-part-av + .pd-part-av { margin-left:-.5rem; }
.pd-part-av .av-photo { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
.pd-part-mas { margin-left:.15rem; font-size:.7rem; font-weight:700; color:var(--muted-2); }

/* Estrellas de calificación (mismo look que el rate del feedback 360) */
.pd-stars { display:inline-flex; align-items:center; gap:.15rem; }
.pd-star { background:none; border:none; cursor:pointer; padding:.1rem; font-size:1.6rem; line-height:1;
  color:#d1d5db; font-family:inherit; transition:color .12s; }
.pd-star.is-on { color:#f59e0b; }
.pd-stars-val { font-size:.8rem; color:var(--muted); margin-left:.25rem; }
/* Opción del modal de cierre: checkbox a la izquierda, texto pegado */
.pd-close-obj { display:flex; align-items:flex-start; gap:.55rem; padding:.25rem 0; font-size:.87rem; }
.pd-close-obj input { width:auto; margin:.2rem 0 0; flex-shrink:0; }

.pd-asg-list { display:flex; flex-direction:column; gap:.15rem; max-height:280px; overflow-y:auto; border:1px solid var(--line); border-radius:.6rem; padding:.3rem; }
.pd-asg { display:flex; align-items:center; gap:.55rem; padding:.4rem .5rem; border-radius:.5rem; cursor:pointer; }
.pd-asg:hover { background:var(--panel-2); }
.pd-asg input { flex:none; width:auto; margin:0; }
.pd-notif-pref { display:flex; align-items:center; gap:.55rem; padding:.45rem .5rem; border-radius:.5rem; cursor:pointer; font-size:.88rem; color:var(--text); }
.pd-notif-pref:hover { background:var(--panel-2); }
.pd-notif-pref input { flex:none; width:auto; margin:0; }
/* Módulos: chips que filtran las tres vistas. */
.pd-mods { display:flex; align-items:center; flex-wrap:wrap; gap:.35rem; margin:0 0 .7rem; }
.pd-mod { display:inline-flex; align-items:center; gap:.35rem; padding:.28rem .6rem; border-radius:999px;
  border:1px solid var(--line-2); background:var(--panel); color:var(--text); font-size:.8rem;
  font-weight:600; text-decoration:none; font-family:inherit; cursor:pointer; transition:border-color .12s,background .12s,color .12s; }
.pd-mod:hover { border-color:var(--brand); color:var(--brand); }
/* El seleccionado ya es rojo lleno: el hover NO puede pintarle el texto de rojo. */
.pd-mod--on:hover { color:var(--on-brand); background:color-mix(in srgb, var(--brand) 88%, #000); }
.pd-mod--on { background:var(--brand); border-color:var(--brand); color:var(--on-brand); }
/* El contador del chip activo va del mismo color que el texto, apenas mas tenue:
   con blanco fijo desaparecia sobre los acentos claros. */
.pd-mod--on .pd-mod-n { color:var(--on-brand); opacity:.72; }
.pd-mod-n { font-size:.7rem; font-weight:700; color:var(--muted-2); }
.pd-count-de { font-size:.72rem; font-weight:600; color:var(--muted-2); margin-left:.2rem; }
.pd-mod--suelto { border-style:dashed; }
/* Con una tarjeta encima: el mismo aviso que dan los sprints del costado —esto
   recibe lo que estás arrastrando—. Pisa también al chip activo, que si no se
   quedaba rojo lleno y no se notaba que era el destino. */
.pd-mod--drop, .pd-mod--on.pd-mod--drop { border-color:var(--brand); color:var(--brand);
  background:color-mix(in srgb, var(--brand) 14%, transparent);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--brand) 20%, transparent); }
.pd-mod--add { color:var(--muted); border-style:dashed; }
.action-menu-sep { padding:.4rem .6rem .15rem; font-size:.66rem; font-weight:700; text-transform:uppercase;
  letter-spacing:.04em; color:var(--muted-2); border-top:1px solid var(--line); margin-top:.25rem; }
.action-menu-item--on { font-weight:700; color:var(--brand); }
.mm-list { display:flex; flex-direction:column; max-height:min(50vh,320px); overflow-y:auto; }
.mm-op { display:flex; align-items:center; gap:.5rem; width:100%; text-align:left; border:none;
  background:none; font-family:inherit; font-size:.88rem; color:var(--text); padding:.5rem .55rem;
  border-radius:.45rem; cursor:pointer; }
.mm-op:hover { background:var(--panel-2); }
.mm-op--on { color:var(--brand); font-weight:700; }
.mm-n { margin-left:auto; font-size:.72rem; color:var(--muted-2); }
.mm-vacio { margin:.4rem 0 0; font-size:.82rem; color:var(--muted); text-align:center; }

.pd-mod-list { display:flex; flex-direction:column; margin-bottom:1rem; }
.pd-mod-row { border-bottom:1px solid var(--line); }
.pd-mod-row:last-child { border-bottom:none; }
.pd-mod-ver { display:flex; align-items:center; gap:.6rem; padding:.5rem .1rem; }
.pd-mod-nom { font-size:.9rem; font-weight:600; color:var(--text); }
.pd-mod-meta { font-size:.75rem; color:var(--muted); margin-left:auto; }
.pd-mod-ver .action-menu-wrap { flex-shrink:0; }
.pd-mod-edit { display:flex; gap:.4rem; align-items:center; margin:0; padding:.15rem .1rem .6rem; }
.pd-mod-edit .form-input { font-size:.84rem; padding:.35rem .5rem; }
.pd-mod-owner { max-width:11rem; }
.pd-mod-new { display:flex; gap:.4rem; align-items:center; margin:0; padding-top:.8rem; border-top:1px solid var(--line); }
.pd-mod-new .form-input { flex:1; font-size:.84rem; padding:.35rem .5rem; }
.pd-cbtn--on { color:var(--brand);background:var(--panel-2);border-color:var(--line-2); }
.pd-addtask { display:flex; gap:.5rem; align-items:center; margin:0 0 1rem; }
.pd-demo-tag { display:inline-block; font-size:.6rem; font-weight:700; text-transform:uppercase; letter-spacing:.04em; color:var(--muted-2); background:var(--panel-2); border:1px solid var(--line); border-radius:999px; padding:.1rem .5rem; margin:0 0 .6rem; }
/* Tablero de ejemplo del tour + tarjeta que se mueve entre columnas (movida por JS) */
#tutKbMock { min-height:150px; overflow-x:hidden; }
.tut-kb-ghost { position:absolute; box-sizing:border-box; z-index:3; pointer-events:none; box-shadow:0 12px 28px rgba(0,0,0,.24); outline:2px solid var(--brand); transition:transform .6s cubic-bezier(.22,.61,.36,1); }
.pd-addtask input { flex:1; }
/* El campo que abre el alta: es un boton, pero tiene que leerse como el campo
   que era antes — si no, nadie entiende que ahi se anota una tarea. */
.pd-addtask-abre { flex:1; text-align:left; cursor:pointer; color:var(--muted); }
.pd-addtask-abre:hover { border-color:var(--line-2); color:var(--text-2); }
.pd-pagination { display:flex; align-items:center; justify-content:center; gap:.6rem; margin-top:1rem; }
.pd-empty { color:var(--muted); font-size:.88rem; }
.pd-cierre-fecha { font-size:.78rem; color:var(--muted); }
.pd-prev-rating { margin:0 0 .6rem; font-size:.83rem; color:var(--text-2);
  background:var(--panel-2); border:1px solid var(--line); border-radius:.5rem; padding:.45rem .7rem; }

/* Los numeros del sprint como chips. En una frase («2 tareas, 0 terminadas») hay
   que leerla entera para separar dos numeros que uno queria comparar de un
   vistazo. */
.sp-resumen { display: flex; align-items: center; gap: .35rem; flex-wrap: wrap;
  margin: .5rem 0 .35rem; }
.sp-chip { display: inline-flex; align-items: center; gap: .3rem;
  border: 1px solid var(--line); border-radius: .5rem; background: var(--panel);
  padding: .22rem .5rem; font-size: .78rem; font-weight: 600; color: var(--muted); }
.sp-chip svg { color: var(--muted-2); flex-shrink: 0; }
.sp-chip--ok { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 35%, var(--line)); }
.sp-chip--ok svg { color: var(--ok); }
.sp-chip--flojo { color: var(--muted-2); font-weight: 500; border-style: dashed; }

/* El titulo del sprint, mas grande: es de lo que habla el modal. */
.sp-tit-ver, .sp-tit-input { font-size: 1.15rem; }
.sp-nro { font-size: .76rem; color: var(--muted-2); margin: 0 0 .1rem; }

/* La fecha tambien como chip, para que no quede como texto suelto al lado de un
   boton con contorno. */
.sp-cal-wrap { border: 1px solid var(--line); border-radius: .5rem;
  padding: .2rem .5rem; background: var(--panel); }

/* «Eliminar» con contorno: de solo texto, en el mismo pie que «Guardar», se lee
   como un enlace y no como el boton que borra el sprint. */
.sp-borrar { display: inline-flex; align-items: center; gap: .35rem;
  border: 1px solid color-mix(in srgb, var(--danger) 40%, var(--line));
  background: var(--panel); color: var(--danger); }
.sp-borrar:hover { background: color-mix(in srgb, var(--danger) 8%, var(--panel));
  border-color: var(--danger); }

/* La tarjeta recorta por sus esquinas redondeadas, y con eso se comia el
   desplegable que cae mas abajo del borde. Solo en este modal. */
#modalSprint .modal-card { overflow: visible; }
#modalSprint .modal-head { border-top-left-radius: var(--radius-lg);
  border-top-right-radius: var(--radius-lg); }
#modalSprint .modal-actions { border-bottom-left-radius: var(--radius-lg);
  border-bottom-right-radius: var(--radius-lg); }

/* ── Editar un comentario: texto y adjuntos ──────────────────────────────
   Era un textarea pelado: quien se olvidaba la captura tenia que borrar el
   comentario y escribirlo de nuevo. */
.tm-ed { display: flex; flex-direction: column; gap: .3rem; }
.tm-ed-ta { font-size: .86rem; width: 100%; box-sizing: border-box; resize: vertical; }
.tm-ed-pie { display: flex; align-items: center; gap: .4rem; }
.tm-ed-clip { display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border: 1px solid var(--line); border-radius: .4rem;
  background: var(--panel); color: var(--muted); cursor: pointer; padding: 0; }
.tm-ed-clip:hover { color: var(--brand); border-color: var(--muted-2); }
.tm-ed-tip { font-size: .7rem; color: var(--muted-2); }
.tm-ed-chips { display: flex; flex-wrap: wrap; gap: .3rem; }
.tm-ed-chips[hidden] { display: none; }
.tm-ed-chip { display: inline-flex; align-items: center; gap: .25rem;
  border: 1px solid var(--line); border-radius: 999px; background: var(--panel-2);
  padding: .1rem .2rem .1rem .5rem; font-size: .72rem; color: var(--text); }
.tm-ed-chip button { border: none; background: none; color: var(--muted-2);
  cursor: pointer; font-size: .95rem; line-height: 1; padding: 0 .2rem; }
.tm-ed-chip button:hover { color: var(--danger); }

/* De qué tablero es la tarea, abajo del título del modal: abierta desde un
   aviso o un link, el título solo no lo dice. */
.tm-proy { display: flex; align-items: center; gap: .3rem; margin: .15rem 0 0;
  font-size: .76rem; color: var(--muted); }
.tm-proy a { color: var(--muted); text-decoration: none; }
.tm-proy a:hover { color: var(--brand); text-decoration: underline; }

/* ── El zumbido de «vení acá» ──
   La tarjeta que se vino a buscar después de cerrar el modal de una tarea a la
   que se llegó por link (una novedad, un aviso de escritorio). Se sacude apenas
   y se apaga sola.

   Es `transform` y un marco: nada que ocupe lugar. Con `margin` o `border` la
   tarjeta empujaría a las de abajo y se leería como que la lista se reordenó,
   que es justo lo contrario de lo que se quiere decir. */
@keyframes tk-zumbido {
  0%, 100% { transform: translateX(0); }
  12% { transform: translateX(-5px); }
  26% { transform: translateX(4px); }
  40% { transform: translateX(-3px); }
  54% { transform: translateX(2px); }
  68% { transform: translateX(-1px); }
}
.tk-zumbido {
  animation: tk-zumbido .55s ease both;
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: .6rem;
  /* El marco se queda un rato después de que la sacudida terminó: el movimiento
     te trae los ojos, el marco te los deja ahí mientras leés cuál era. */
  transition: outline-color .5s ease .7s;
}
@media (prefers-reduced-motion: reduce) {
  .tk-zumbido { animation: none; }
}

.pdk-card > .pd-task-tipo { margin-top:.45rem; margin-right:.55rem; }
/* Y centrado con ellos: por defecto estas cajitas se alinean por la LÍNEA DE
   BASE, y la del globito la pone su texto («3») mientras que el sol no tiene
   texto, así que la suya es el borde de abajo — quedaba 6px más abajo. Alineados
   por el medio, los tres comparten centro sin depender de que midan lo mismo. */
.pdk-card > .pdk-coment,
.pdk-card > .pdk-checks,
.pdk-card > .pd-task-tipo { vertical-align:middle; }

/* ── Los globitos: los proyectos abiertos, pegados a un borde ────────────────
   Como las burbujas de chat: chicos y al costado, para volver de un toque desde
   cualquier pantalla. Cada uno con SU lugar: se arrastra de a uno y el resto se
   queda donde está. El JS está en /static/globos.js. */
/* Pegado a la derecha va al revés —primero el nombre, después el redondel—, y
   pegado a la izquierda al derecho. Suena raro escrito, pero es lo único que deja
   el redondel QUIETO al abrirse: el borde que no se mueve es el que está contra
   el margen, así que el nombre tiene que crecer hacia adentro de la pantalla. Al
   revés, abrir el globito le corría el redondel doce centímetros de donde estaba
   el dedo. */
.glb { position:fixed; right:10px; z-index:60; display:flex; align-items:center; gap:.5rem;
  flex-direction:row-reverse;
  /* Cerrado mide exactamente el redondel + su aire + los dos bordes. Puesto a ojo
     le faltaban los bordes —el `max-width` los incluye— y el globo quedaba dos
     pixels más angosto que alto: una pastillita en vez de un redondel, con el
     ícono corrido hacia el lado por donde sale el nombre. */
  --glb-chico:calc(1.7rem + .9rem + 2px);
  max-width:var(--glb-chico); overflow:hidden; padding:.45rem; border-radius:999px;
  border:1px solid var(--line); background:var(--panel); color:var(--text);
  text-decoration:none; cursor:grab; box-shadow:0 6px 18px rgba(0,0,0,.14);
  touch-action:none; transition:max-width .22s var(--ease-out), box-shadow .18s,
  border-color .18s, top .26s cubic-bezier(.22,1,.36,1); }
.glb--izq { right:auto; left:10px; flex-direction:row; }
/* En el celular cada pixel del costado es contenido: el globo se achica y se
   arrima al borde. Tapa menos y se sigue agarrando bien con el dedo (40px). */
@media (max-width: 560px) {
  .glb { right:4px; padding:.3rem; --glb-chico:calc(1.7rem + .6rem + 2px);
    box-shadow:0 3px 10px rgba(0,0,0,.14); }
  .glb--izq { left:4px; }
}
/* Al pasar por encima se abre y muestra el nombre: chico ocupa nada, y hace falta
   saber cuál es cuál sin abrirlos. */
.glb:hover, .glb:focus-visible { max-width:14rem; border-color:var(--brand);
  box-shadow:0 10px 24px rgba(0,0,0,.2); }
/* Volando no se despliega —ni arrastrándolo ni mientras vuelve—: el nombre es
   para cuando está apoyado en un borde, y agarrar un cartel tapa justo lo que
   estás mirando para decidir dónde soltarlo. */
.glb--agarrado, .glb--agarrado:hover, .glb--volviendo, .glb--volviendo:hover {
  max-width:var(--glb-chico); cursor:grabbing; }
/* Y tampoco mientras la mano está en el globo o todavía no se movió de donde lo
   soltó: el nombre es para mirarlo quieto. Soltarlo contra el margen deja el
   puntero justo encima, y el globo se abría de golpe como parte del gesto. */
.glb--quieto, .glb--quieto:hover { max-width:var(--glb-chico); }
/* Salvo cuando lo tocaste para ir: ahí se abre y el nombre queda a la vista
   cruzando la carga de la pantalla nueva. Es la respuesta a «¿adónde me lleva
   esto?», y llega justo cuando la pregunta importa. Va después de todo lo demás
   porque le tiene que ganar a «agarrado» y a «quieto». */
.glb--abierto, .glb--abierto:hover { max-width:14rem; }
/* El que agarrás va por encima de los demás y sin transición: la posición la
   escribe el JS cuadro por cuadro. */
.glb--agarrado { z-index:63; transition:none; will-change:transform; }
.glb--volviendo { transition:transform .28s cubic-bezier(.22,1,.36,1),
  top .28s cubic-bezier(.22,1,.36,1); }
/* Imantado al tacho, un poco más chico, como los íconos de Android al entrar a
   la papelera. */
.glb--en-tacho .glb-ini { transform:scale(.88); }
/* El redondel: del color del proyecto (lo pone el JS), con su ícono. Sin letras
   encima: apiladas sobre el dibujo a este tamaño no se leía ni una cosa ni la
   otra, y el nombre completo ya aparece al pasarle por encima. Las letras quedan
   sólo para el proyecto SIN ícono, que si no sería un punto de color y nada más. */
.glb-ini { position:relative; flex-shrink:0; width:1.7rem; height:1.7rem; border-radius:999px;
  display:inline-flex; align-items:center; justify-content:center; overflow:hidden;
  background:var(--brand); color:var(--on-brand); font-size:.72rem; font-weight:800;
  transition:transform .18s var(--ease-out); }
.glb-ico { position:absolute; inset:0; display:flex; align-items:center; justify-content:center; }
.glb-ico svg { width:1.05rem; height:1.05rem; }
.glb-let { position:relative; line-height:1; font-size:.76rem; }
/* El número de una tarea: tres o cuatro cifras no entran al tamaño de dos, y
   cortado sería otra tarea. */
.glb-let--largo { font-size:.6rem; letter-spacing:-.02em; }
.glb-let--muylargo { font-size:.5rem; }
.glb--con-ico .glb-let { display:none; }
.glb-nom { display:flex; align-items:center; gap:.3rem; white-space:nowrap;
  overflow:hidden; font-size:.78rem; font-weight:600; padding-left:.35rem; }
.glb-nom-txt { overflow:hidden; text-overflow:ellipsis; }
/* Qué es: un proyecto, un sprint, una tarea. Adentro del redondel está el número,
   que dice cuál es pero no qué es. Apagado, porque es el acompañante del nombre
   y no el nombre. */
.glb-tipo { display:flex; flex-shrink:0; align-items:center; opacity:.6; }
.glb-tipo:empty { display:none; }
.glb--izq .glb-nom { padding-left:0; padding-right:.35rem; }
/* Al abrirlo: crece un instante antes de que cambie la pantalla. Es lo que hace
   que se entienda que el globo te llevó, y no que la página se recargó sola. */
.glb--abriendo { animation:glb-abrir .18s var(--ease-out) forwards; }
/* Al cargar una pantalla: entran chiquitos y se pasan un pelito antes de
   asentarse. Aparecer de golpe en un borde no se lee como «acá están tus cosas»,
   se lee como que algo se rompió. */
.glb--poof { animation:glb-poof .34s cubic-bezier(.22,1.4,.4,1) both; }
@keyframes glb-poof {
  from { transform:scale(.2); opacity:0; }
  70%  { transform:scale(1.08); opacity:1; }
  to   { transform:scale(1); opacity:1; }
}
@keyframes glb-abrir {
  from { transform:scale(1); }
  60%  { transform:scale(1.22); box-shadow:0 14px 30px rgba(0,0,0,.26); }
  to   { transform:scale(1.1); opacity:.85; }
}
/* El tacho: abajo al medio y sólo mientras arrastrás. Hay que ir hasta él, así
   que no se llega por accidente. Con el globo encima se vuelve un redondel con el
   ícono solo: el cartel ya cumplió —te trajo hasta acá— y deja de tapar media
   pantalla justo cuando el globo está ahí. */
.glb-tacho { position:fixed; left:50%; bottom:calc(1.2rem + var(--tabbar-h, 0px)); transform:translateX(-50%);
  z-index:59; display:flex; align-items:center; justify-content:center; gap:.5rem;
  padding:.6rem 1rem; border-radius:999px; border:1px dashed var(--line-2);
  background:var(--panel); color:var(--muted); font-size:.8rem; font-weight:600;
  box-shadow:0 10px 30px rgba(0,0,0,.18);
  transition:width .18s var(--ease-out), height .18s var(--ease-out),
  padding .18s var(--ease-out), background .18s, border-color .18s, color .18s; }
.glb-tacho[hidden] { display:none; }
.glb-tacho--cerca { border-color:var(--danger); color:var(--danger); border-style:solid;
  background:color-mix(in srgb, var(--danger) 12%, var(--panel));
  width:3.4rem; height:3.4rem; padding:0; }
.glb-tacho--cerca span { display:none; }
@media (prefers-reduced-motion: reduce) {
  .glb, .glb--volviendo { transition:none; }
  .glb--abriendo, .glb--poof { animation:none; }
}

/* «Acá no hay acciones»: el aviso cuando se aprieta el botón derecho sobre algo
   que no tiene menú. Sale donde apretaste y se va solo. No intercepta el mouse
   (pointer-events: none) para no tapar lo que hay abajo mientras está. */
.sin-menu { position: fixed; z-index: 3000; pointer-events: none;
  padding: .3rem .55rem; border-radius: .4rem; font-size: .78rem;
  font-weight: 600;
  /* El fondo sale del color del texto (oscuro en claro, claro en oscuro), así
     que la letra va con el del fondo de la página: siempre contrasta. Con
     --on-brand, en un proyecto (amarillo) salía casi negro sobre casi negro. */
  color: var(--bg);
  background: color-mix(in srgb, var(--text) 82%, transparent);
  opacity: 0; transform: translateY(-2px);
  transition: opacity .12s ease, transform .12s ease; }
.sin-menu--on { opacity: 1; transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
  .sin-menu { transition: none; }
}

/* ── El tema escondido ─────────────────────────────────────────────────────
   No está a la vista: se abre con la nota privada «temas», igual que Aero.

   Es un TEMA, no un tono del oscuro: tiene su paleta entera y no hay versión
   nocturna. Por eso va en `[data-theme]` y en la misma lista que Claro, Oscuro y
   Aero — como tono del oscuro habría que elegir el oscuro primero para llegar a
   un tema que justamente es claro.

   El rosa va en el FONDO y en los acentos, no en la barra ni en las tarjetas:
   pintando la barra entera el portal dejaba de parecer el portal. Las tarjetas
   blancas sobre el fondo rosa son las que dan el aire, y el color fuerte queda
   para lo que se toca. */
[data-theme="barbie"] {
  --bg:      #fdeef7;
  --panel:   #ffffff;
  --panel-2: #fdf5fa;
  --line:    #f7d9e9;
  --line-2:  #f0b8d5;
  --text:    #1f1020;
  --text-2:  #3a1c30;
  --muted:   #7b5a6b;
  --muted-2: #9b7689;

  --brand:         #e0007e;
  --brand-hover:   #b80068;
  --brand-mid:     #ff4fa3;
  --brand-light:   #fdeaf4;
  --brand-light-2: #f9cfe4;
  --on-brand: #fff;

  --accent: #ff69b4;
  --accent-light: #fff2f9;
}
/* El logo, en rosa: las mismas caras con otros colores. Como el logo va en
   línea, alcanza con cambiar sus variables. */
[data-theme="barbie"] .rt-logo {
  --logo-hex: #500724;
  --logo-espacio: #9d174d;
  --logo-proyecto: #f9a8d4;
  --logo-tarea: #db2777;
}

/* El confeti que cae al cambiar de tema. El contenedor toma la pantalla entera y
   cada pieza arranca arriba, en una columna al azar, con su propia animación: así
   no hay que coordinar nada entre ellas. No intercepta el mouse ni lo lee el
   lector de pantalla. */
.confeti { position: fixed; inset: 0; z-index: 2147483000; pointer-events: none;
  overflow: hidden; }
/* Nacen ARRIBA de la pantalla y transparentes. Con `top: 0` se veia el cuadro en
   que la pieza ya esta en el DOM pero la animacion todavia no aplico: aparecian
   todas juntas en el borde de arriba y recien despues saltaban a su lugar. El
   estado inicial tiene que estar en el CSS, que es lo unico que corre antes. */
/* Sin `will-change`: eran 40 capas de composicion vivas a la vez, y eso se paga
   en memoria de GPU justo en el momento en que la pantalla tiene que ir fluida.
   Una animacion de `transform`/`opacity` hecha con la API de animaciones ya se
   compone sola; avisarlo de mas no la mejora, la encarece. */
.confeti i { position: absolute; top: -15vh; display: block; line-height: 1;
  font-style: normal; opacity: 0; }

/* Botón de instalar el portal como app. Ver `instalarApp` en portal.js: nace
   escondido y lo muestra el JS sólo cuando instalar de verdad se puede.

   Sólo el ícono y pegado al nombre del portal: no es un lugar adonde ir, así que
   entre los links competía con la navegación por un lugar que no le corresponde.
   Lo que hace lo dice el globo. */
.brand-instalar { display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; margin-left: .4rem; padding: 0; flex-shrink: 0;
  border: none; background: transparent; color: var(--muted-2); cursor: pointer;
  transition: color .15s; }
.brand-instalar:hover { color: var(--brand); }
/* Sube y baja despacio para que el ojo lo encuentre. Se mueve el ÍCONO y no el
   botón, que además de ser lo mismo ahora que no hay recuadro, deja el área
   clickeable quieta: un blanco que se mueve es un blanco que se falla.

   Y es infinita a propósito, que normalmente sería molesto: este botón existe
   sólo mientras el portal NO está instalado, así que la animación se termina
   sola en cuanto alguien le hace caso. */
.brand-instalar svg { animation: instalarFlota 2.6s ease-in-out infinite; }
/* Quieto al pasarle por encima: apuntarle a algo que se mueve es incómodo, y
   para ese momento ya cumplió su trabajo. */
.brand-instalar:hover svg { animation-play-state: paused; }
@keyframes instalarFlota {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-2.5px); }
}
@media (prefers-reduced-motion: reduce) {
  .brand-instalar svg { animation: none; }
}
.inst-intro { margin: 0 0 .5rem; font-size: .88rem; color: var(--text-2); }
.inst-pasos { margin: 0 0 .75rem; padding-left: 1.2rem; font-size: .88rem;
  line-height: 1.7; }
.inst-nota { margin: 0 0 .4rem; font-size: .8rem; color: var(--muted); line-height: 1.5; }

/* El zumbido del logo: cada tanto se sacude apenas, como si algo lo hubiera
   despertado. Sólo con el tema escondido puesto — en los demás el portal no
   tiene por qué moverse solo mientras trabajás.

   Va con `animation-iteration-count: infinite` y la sacudida ocupando el 4% del
   ciclo: así el resto del tiempo está quieto y no hace falta un temporizador en
   JS que se acumule con cada pantalla que abrís. */
[data-theme="barbie"] .brand-logo-btn:not(.is-pop-a):not(.is-pop-b):not(.is-premio) .brand-logo {
  animation: logoZumbido 14s ease-in-out infinite;
  transform-origin: 50% 60%;
}
@keyframes logoZumbido {
  0%, 96%, 100% { transform: rotate(0deg) scale(1); }
  96.4% { transform: rotate(-9deg) scale(1.08); }
  97.0% { transform: rotate(8deg)  scale(1.06); }
  97.6% { transform: rotate(-6deg) scale(1.05); }
  98.2% { transform: rotate(4deg)  scale(1.03); }
  98.8% { transform: rotate(-2deg) scale(1.01); }
}
/* Y nada de esto para quien pidió menos movimiento: un logo que se sacude solo
   es justo lo que esa preferencia está pidiendo que no pase. */
@media (prefers-reduced-motion: reduce) {
  [data-theme="barbie"] .brand-logo { animation: none; }
}

/* El botón de instalar, con su ✕ para sacarlo. La ✕ va pegada arriba a la
   izquierda del botón y fuera del flujo, así no le corre el ancho ni empuja al
   nombre del portal; y es chiquita a propósito: lo que se ofrece es instalar, no
   cerrar. */
.brand-instalar-caja { position: relative; display: inline-flex; }
.brand-instalar-x {
  position: absolute; top: -5px; left: -7px; z-index: 2;
  width: 15px; height: 15px; padding: 0; display: flex;
  align-items: center; justify-content: center;
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--panel); color: var(--muted-2);
  font-size: 12px; line-height: 1; cursor: pointer;
  /* Aparece al acercarse al botón: siempre visible, una ✕ al lado de un ícono de
     15px es un amontonamiento. Con el teclado se ve igual, o no habría forma de
     llegar. */
  opacity: 0; transition: opacity .12s, color .12s, border-color .12s;
}
.brand-instalar-caja:hover .brand-instalar-x,
.brand-instalar-x:focus-visible { opacity: 1; }
.brand-instalar-x:hover { color: var(--brand); border-color: var(--brand); }
/* El disparador del menú no se dibuja: lo abre el clic derecho o mantener. */
.brand-instalar-menu { display: none; }
/* Con el dedo la ✕ no sirve (15px, y sólo aparecía con hover): se quita
   manteniéndolo apretado. Sin el globito del sistema al mantener. */
@media (pointer: coarse) {
  .brand-instalar-x { display: none; }
  .brand-instalar { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }
}


/* ── Acento por sección ──────────────────────────────────────────────────────
   <html data-seccion> sale de la dirección (base.html) y el panel de una tarea
   lo pasa a "tarea" mientras está abierto (portal.js). El lila de espacio es el
   de :root. Los temas con acento propio (Aero, Barbie, Arcoíris) no se tocan.
   El amarillo (tareas) es el mismo del logo (#ffb627); encima el texto va
   oscuro, porque blanco sobre ese amarillo no se lee. Las exclusiones van en
   :where() para no sumar especificidad: si no, en oscuro ganaba el tono claro. */
:root[data-seccion="proyecto"]:where(:not([data-theme="aero"], [data-theme="barbie"], [data-theme="dark"][data-dark="arcoiris"])) {
  --brand: #1f6fe5;
  --brand-hover: #185cc2;
  --brand-mid: #2b7fff;
  --brand-light: #eaf2ff;
  --brand-light-2: #cfe1ff;
  --brand-solid: #1f6fe5;
  --brand-solid-hover: #185cc2;
  --on-brand: #fff;
}
:root[data-seccion="tarea"]:where(:not([data-theme="aero"], [data-theme="barbie"], [data-theme="dark"][data-dark="arcoiris"])) {
  --brand: #ffb627;
  --brand-hover: #f0a310;
  --brand-mid: #ffb627;
  --brand-light: #fff5dc;
  --brand-light-2: #ffe3a3;
  --brand-solid: #ffb627;
  --brand-solid-hover: #f0a310;
  --on-brand: #231800;
}
:root[data-theme="dark"][data-seccion="proyecto"]:not([data-dark="arcoiris"]) {
  --brand: #6aa5ff;
  --brand-hover: #8cb9ff;
  --brand-mid: #2b7fff;
  --brand-light: #152236;
  --brand-light-2: #1d3252;
  --brand-solid: #1f6fe5;
  --brand-solid-hover: #185cc2;
  --on-brand: #fff;
}
:root[data-theme="dark"][data-seccion="tarea"]:not([data-dark="arcoiris"]) {
  --brand: #ffb627;
  --brand-hover: #ffc452;
  --brand-mid: #ffb627;
  --brand-light: #2a2210;
  --brand-light-2: #3d3115;
  --brand-solid: #ffb627;
  --brand-solid-hover: #ffc452;
  --on-brand: #231800;
}

/* El cambio de acento se anima, como el color en las caras del logo. Registrar
   las variables como <color> es lo que deja interpolarlas; la primera pintada
   no transiciona, así que al cargar una página no hay parpadeo. */
@property --brand { syntax: '<color>'; inherits: true; initial-value: #6a58d8; }
@property --brand-solid { syntax: '<color>'; inherits: true; initial-value: #6a58d8; }
@property --brand-light { syntax: '<color>'; inherits: true; initial-value: #f1eefd; }
:root { transition: --brand 1s ease, --brand-solid 1s ease, --brand-light 1s ease; }
@media (prefers-reduced-motion: reduce) { :root { transition: none; } }

/* Con una tarea abierta el acento pasa a amarillo, pero casi todo lo que se pinta
   con él queda detrás del panel: el panel mismo tiene que decirlo. Filete arriba
   y encabezado tenido con el color de la tarea. */
.tm-card { border-top: 4px solid var(--brand); }
.tm-card .modal-head { background: var(--brand-light); border-bottom-color: var(--brand-light-2); }
.tm-card .modal-head h3 { color: var(--brand); }
.tm-card .tm-id { color: var(--brand); opacity: .75; }
/* En claro, el amarillo de las tareas como TEXTO no se lee (1.6:1 sobre su
   tinte): el título y el número del panel van en mostaza. El filete y el
   tinte del encabezado siguen amarillos. */
:root[data-seccion="tarea"]:not([data-theme="dark"]):where(:not([data-theme="aero"], [data-theme="barbie"])) .tm-card .modal-head h3,
:root[data-seccion="tarea"]:not([data-theme="dark"]):where(:not([data-theme="aero"], [data-theme="barbie"])) .tm-card .tm-id {
  color: #8f6a0f; }

/* ── Con el dedo ─────────────────────────────────────────────────────────
   Los controles de una fila de tarea son chicos para un dedo (el ⋮ medía
   17×21px). Padding + margen negativo agranda la zona que recibe el toque sin
   mover nada de lugar; sólo en los que no tienen fondo, así no se ven más
   grandes. La pastilla de estado sí tiene fondo: crece un poco de alto. Va al
   final para ganarle a las reglas de cada control. */
@media (pointer: coarse) {
  .pd-task .pd-check, .pd-task .pd-cbtn, .pd-task .action-menu-trigger { padding:9px; margin:-9px; }
  .pd-task .pd-status-pill { padding:.4rem .7rem; }
}

/* ── Barra de abajo (celular) ───────────────────────────────────────────
   En el celular el navbar baja al pie, como en una app: los botones quedan al
   alcance del pulgar y arriba no hay nada fijo, así cada pantalla usa todo el
   alto. Es EL MISMO navbar, no una copia: el tema, la campanita y el menú de la
   persona son los de siempre, y lo que se agregue al navbar aparece en los dos.
   Sin el logo ni el nombre (el logo pasa al encabezado del inicio). Se esconde
   con el teclado abierto: pegada arriba del teclado tapaba el campo. */
@media (max-width: 640px) {
  :root:has(.topbar) { --tabbar-h: calc(58px + env(safe-area-inset-bottom)); }
  body:has(> .topbar) { padding-bottom: var(--tabbar-h); }
  .topbar {
    position: fixed; top: auto; bottom: 0; left: 0; right: 0;
    height: var(--tabbar-h); padding-bottom: env(safe-area-inset-bottom);
    border-bottom: none; border-top: 1px solid var(--line);
  }
  .con-teclado .topbar { display: none; }
  .con-teclado body:has(> .topbar) { padding-bottom: 0; }
  .topbar-inner { padding: 0 .4rem; justify-content: space-around; gap: 0; height: 100%; }
  .topbar .brand-logo-btn, .topbar .brand-text { display: none; }
  .topbar .brand:has(#cajaInstalar.hidden) { display: none; }
  .topbar-nav { display: contents; }
  .topbar .nav-link, .topbar .nav-notes-btn, .topbar .theme-toggle, .topbar .nav-user-trigger {
    min-width: 48px; height: 48px; padding: 0; margin: 0;
    display: inline-flex; align-items: center; justify-content: center; border-radius: var(--radius);
  }
  .topbar .nav-link-ico { display: block; }
  .topbar .nav-link:active, .topbar .nav-notes-btn:active, .topbar .nav-user-trigger:active {
    background: var(--panel-2); }
  .topbar .nav-link-txt { display: none; }
  .topbar .nav-notes-btn svg, .topbar .theme-toggle svg { width: 20px; height: 20px; }
  .nav-user { border-left: none; padding-left: 0; margin-left: 0; }
  .nav-avatar { width: 1.85rem; height: 1.85rem; font-size: .7rem; }
  .nav-user-trigger:hover { transform: none; }
  /* Los menús abren para arriba. */
  .ap-pop { top: auto; bottom: calc(100% + 10px); }
  .nav-user-dropdown {
    top: auto; bottom: calc(100% + .6rem); right: -.2rem;
    min-width: min(260px, calc(100vw - 1.5rem));
    transform: translateY(4px); transition-delay: 0s;
  }
  .nav-user-dropdown::before { top: auto; bottom: -14px; }
  /* Con el dedo no hay hover: abre y cierra con un toque (portal.js). */
  .nav-user:hover .nav-user-dropdown { opacity: 0; visibility: hidden; pointer-events: none; transform: translateY(4px); }
  .nav-user--abierto .nav-user-dropdown, .nav-user--abierto:hover .nav-user-dropdown {
    opacity: 1; visibility: visible; pointer-events: auto; transform: translateY(0);
  }
  .nav-user-item, .nav-user-logout { min-height: 44px; }
  /* Los tooltips del navbar salían para abajo, fuera de la pantalla. */
  .topbar .tip::after, .topbar .tip::before { display: none; }
  .nav-campana-n { top: 6px; right: 6px; }
  .brand-logo-btn--inicio { display: inline-flex; }
  .brand-logo-btn--inicio .brand-logo { width: 1.6rem; height: 1.6rem; }
}

/* En el celular (con el dedo) el tema sale de la barra y pasa al menú de la
   persona, como un submenú que FLOTA encima del menú: no lo agranda ni corre
   los ítems. portal.js lo ubica a la altura de «Apariencia». En una ventana
   angosta de la compu el tema sigue en su botón. */
@media (max-width: 640px) and (pointer: coarse) {
  .topbar .ap-wrap { display: none; }
  .nav-user-dropdown .nav-apariencia { display: flex; }
  .nav-apariencia-flecha { margin-left: auto; transition: transform .18s var(--ease-out, ease-out); }
  .nav-apariencia[aria-expanded="true"] { background: var(--panel-2); }
  .nav-apariencia[aria-expanded="true"] .nav-apariencia-flecha { transform: rotate(-90deg); }
  .nav-user-dropdown .nav-sub:not(.hidden) {
    display: block; position: absolute; left: 1.4rem; right: .5rem; z-index: 3;
    background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
    box-shadow: var(--shadow-lg); padding: .3rem;
  }
  .nav-sub .ap-pop { position: static; min-width: 0; box-shadow: none; border: none; padding: 0; }
}

/* ── Fila de tarea en el celular (Lista y Por estado) ────────────────────
   En un renglón no entraba: nombre, íconos, responsable, comentarios, estado
   y ⋮ se peleaban 340px y el nombre quedaba aplastado debajo de los íconos. Se
   parte en dos: arriba el tilde, el número y el nombre entero; abajo lo demás,
   alineado con el nombre, y el estado y el ⋮ a la derecha. El nodo de
   dependencias es para arrastrar con mouse: en el celular no se muestra. */
@media (max-width: 640px) {
  .pd-task-row { flex-wrap: wrap; row-gap: .35rem; }
  .pd-task-row > .dep-nodo { display: none; }
  .pd-task-row > .pd-task-name { flex: 1 1 calc(100% - 5rem); }
  .pd-task-row > .pd-task-name + * { margin-left: calc(16px + .6rem); }
  .pd-task-row > .pd-task-controls { margin-left: auto; }
}

/* ── Esqueleto al navegar (ver cargando.js) ───────────────────────────────
   Tapa el contenido con la forma de la pantalla que viene mientras llega. Mismo
   lenguaje que el esqueleto del panel de una tarea (.tm-esq): bloques en
   --panel-2 con el mismo latido suave. Deja a la vista el navbar (arriba en la
   compu, abajo en el celular). */
.esq-capa { position: fixed; left: 0; right: 0; top: var(--topbar-h); bottom: 0; z-index: 90;
  background: var(--bg); overflow: hidden; opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .12s ease, visibility 0s linear .12s; }
.esq-capa--on { opacity: 1; visibility: visible; pointer-events: auto; transition: opacity .12s ease; }
@media (max-width: 640px) { .esq-capa { top: 0; bottom: var(--tabbar-h, 0px); } }
.esq-pagina { max-width: var(--page-max); margin: 0 auto; padding: 1.3rem var(--page-pad) 2rem;
  display: flex; flex-direction: column; gap: 1.1rem; }
.esq-pagina--media { max-width: 1000px; padding-left: 1rem; padding-right: 1rem; }
.esq-pagina--angosta { max-width: 620px; padding-left: 1.5rem; padding-right: 1.5rem; }
.esq-card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius-xl);
  padding: 1.1rem 1.2rem; display: flex; flex-direction: column; gap: .9rem; }
.esq-fila { display: flex; align-items: center; gap: .8rem; }
.esq-col { display: flex; flex-direction: column; gap: .5rem; min-width: 0; }
.esq-flex { flex: 1; }
.esq-cab { margin-bottom: .1rem; }
.esq-grilla { display: grid; grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); gap: .7rem; }
.esq-tarea { padding: .55rem 0; border-top: 1px solid var(--line); }
/* --line y no --panel-2: sobre la tarjeta blanca --panel-2 casi no se distingue
   (1.04:1) y el esqueleto parecía una pantalla vacía. */
.esq-b { display: block; flex-shrink: 0; max-width: 100%; border-radius: .4rem; background: var(--line);
  animation: tm-esq-late 1.2s ease-in-out infinite; }
.esq-b--cuadro { border-radius: var(--radius); }
.esq-b--caja { border-radius: var(--radius); }
.esq-b--redondo { border-radius: 999px; }
.esq-b--pastilla { border-radius: 999px; }
/* La línea que se achica para que la pastilla de al lado no se salga. */
.esq-b--estira { flex-shrink: 1; min-width: 3rem; }
@media (prefers-reduced-motion: reduce) {
  .esq-b { animation: none; }
  .esq-capa, .esq-capa--on { transition: none; }
}

/* ── Cartel de carga («Guardando…») ───────────────────────────────────────
   Baja desde el borde de arriba, al centro: una pastilla oscura con su
   ruedita. En el celular también va arriba (abajo está el navbar). La entrada
   frena al final con una curva que se pasa apenas: se nota que llegó sin rebotar. */
.toast-carga { position: fixed; top: 0; left: 50%; z-index: 3100; pointer-events: none;
  transform: translate(-50%, -120%); opacity: 0;
  transition: transform 420ms cubic-bezier(.16, 1, .3, 1), opacity 240ms ease; }
.toast-carga--on { transform: translate(-50%, 0); opacity: 1; }
.toast-carga-chip { display: inline-flex; align-items: center; gap: .6rem; height: 2.6rem;
  padding: 0 1.1rem; padding-top: env(safe-area-inset-top); box-sizing: content-box;
  border-radius: 0 0 1.1rem 1.1rem;
  background: var(--text); color: var(--bg); box-shadow: 0 8px 24px rgba(15, 23, 42, .28);
  font-size: .86rem; font-weight: 600; letter-spacing: .01em; white-space: nowrap; }
.toast-carga-giro { width: 1rem; height: 1rem; flex-shrink: 0; border-radius: 999px;
  border: 2px solid color-mix(in srgb, var(--bg) 35%, transparent); border-top-color: var(--bg);
  animation: toast-carga-giro 650ms linear infinite; }
@keyframes toast-carga-giro { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .toast-carga { transition: opacity 120ms ease; }
  .toast-carga-giro { animation: none; }
}

/* ── La ventanita de la campanita ─────────────────────────────────────────
   Las últimas notificaciones sin salir de la pantalla. Cuelga del botón en la
   compu; en el celular (navbar abajo) sale hacia arriba, a lo ancho. */
.notif-wrap { position: relative; display: inline-flex; }
.nav-campana.is-abierto { color: var(--brand); background: var(--panel-2); }
.nav-campana.is-abierto.tip::after, .nav-campana.is-abierto.tip::before { display: none; }
.notif-pop { position: absolute; top: calc(100% + 8px); right: -2.4rem; z-index: 1150;
  width: 22rem; max-width: calc(100vw - 1.5rem); display: flex; flex-direction: column;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); overflow: hidden; }
.notif-pop.hidden { display: none; }
.notif-pop-cab { display: flex; align-items: center; gap: .5rem; padding: .7rem .85rem .55rem;
  border-bottom: 1px solid var(--line); }
.notif-pop-t { font-size: .88rem; font-weight: 700; color: var(--text); }
.notif-pop-leidas { margin-left: auto; border: none; background: none; padding: .2rem .3rem;
  border-radius: .35rem; font: inherit; font-size: .75rem; color: var(--brand); cursor: pointer; }
.notif-pop-leidas:hover { background: var(--panel-2); }
.notif-pop-lista { max-height: min(24rem, 60vh); overflow-y: auto; overscroll-behavior: contain; }
.notif-pop-item { display: flex; gap: .6rem; padding: .65rem .85rem; text-decoration: none; color: inherit; }
.notif-pop-item + .notif-pop-item { border-top: 1px solid var(--line); }
.notif-pop-item:hover { background: var(--panel-2); }
.notif-pop-item:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.notif-pop-punto { flex-shrink: 0; width: .45rem; height: .45rem; margin-top: .4rem; border-radius: 50%; }
.notif-pop-item--nueva .notif-pop-punto { background: var(--brand); }
.notif-pop-txt { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.notif-pop-tit { font-size: .84rem; color: var(--text); }
.notif-pop-item--nueva .notif-pop-tit { font-weight: 700; }
.notif-pop-cuerpo { font-size: .8rem; color: var(--muted); overflow: hidden;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.notif-pop-cuando { font-size: .72rem; color: var(--muted); }
.notif-pop-vacio { margin: 0; padding: 1.4rem .85rem; text-align: center; font-size: .84rem; color: var(--muted); }
.notif-pop-pie { display: block; padding: .6rem .85rem; border-top: 1px solid var(--line); text-align: center;
  font-size: .8rem; font-weight: 600; color: var(--brand); text-decoration: none; }
.notif-pop-pie:hover { background: var(--panel-2); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
@media (max-width: 640px) {
  .notif-pop { position: fixed; top: auto; left: .6rem; right: .6rem; width: auto; max-width: none;
    bottom: calc(var(--tabbar-h, 0px) + .5rem); }
  .notif-pop-item, .notif-pop-pie { min-height: 44px; }
}
