/* ============================================
   ODINOTE — visual system v3
   Light: white/grey + olive + wine
   Dark: charcoal + same accents
   ============================================ */

:root, [data-theme="light"] {
  --bg:        #ECEBEB;
  --bg-2:      #E2E1E1;
  --bg-3:      #D5D4D4;
  --paper:     #FAF9F6;
  --paper-2:   #F3F2EE;
  --ink:       #1A1A1A;
  --ink-2:     #595459;
  --ink-3:     #8E8A8E;
  /* Bordes en lila (antes gris casi negro). */
  --lila:      #A48FD0;
  --line:      var(--lila);
  --line-soft: color-mix(in srgb, var(--lila) 35%, transparent);
  --line-softer: color-mix(in srgb, var(--lila) 16%, transparent);

  --bg-card:   #FAF9F6;
  --bg-main:   #F4F3EF;
  --text:      #1A1A1A;
  --text-soft: #595459;

  /* Brand palette (user-defined) */
  --pal-grey:   #E1DFE3;
  --pal-dark:   #595459;
  --pal-red:    #E6544F;
  --pal-green:  #90B968;
  --pal-yellow: #F7DA84;

  /* semantic */
  /* Acentos de la interfaz (selección, activo, avisos): el mismo lila que los
     bordes. Los nombres vienen del verde oliva y el rojo vino de antes.
     -l / -2: el acento rebajado con el papel, para fondos suaves.
     -ink: tinta encima de un fondo de acento (es claro: tinta oscura).
     -texto: el acento como color de letra o icono, más hondo para que se lea
     sobre fondo claro.
     El tema va en <body data-theme>: lo que se calcula a partir de --lila se
     repite en el bloque del tema oscuro, si no se quedaría con el lila claro. */
  --acento:  var(--lila);
  --olive:   var(--acento);
  --olive-l: color-mix(in srgb, var(--acento) 22%, var(--paper));
  --olive-2: color-mix(in srgb, var(--acento) 45%, var(--paper));
  --olive-ink:   #1A1A1A;
  /* Los menús: la barra de nodos de arriba, el panel del nodo a la izquierda
     (y el de formato de texto) y la barra lateral de Inicio. */
  --menu-fondo: #F9F6F0;   /* blanco hueso */
  --menu-hover: #D7FFC1;   /* verde lima claro */
  /* Fondo de las columnas (la tarjeta y la zona donde caen los nodos). */
  --columna-fondo: #FFFFFF;
  --olive-texto: #6E54B0;
  --wine:    var(--acento);
  --wine-l:  color-mix(in srgb, var(--acento) 22%, var(--paper));
  --wine-2:  color-mix(in srgb, var(--acento) 45%, var(--paper));
  --wine-ink:    #1A1A1A;
  --wine-texto:  #6E54B0;

  /* sticky tints */
  --c-white:  #FAF9F6;
  --c-cream:  #FEF7E0;
  --c-sage:   #E8F0DA;
  --c-rose:   #FBDFDD;
  --c-stone:  #F5F4F6;
  --c-mist:   #E1DFE3;
  --c-olive:  #90B968;
  --c-wine:   #E6544F;

  /* categorization */
  --cat-red:    #E6544F;
  --cat-orange: #E6544F;
  --cat-yellow: #F7DA84;
  --cat-green:  #90B968;
  --cat-teal:   #90B968;
  --cat-blue:   #595459;
  --cat-purple: #595459;
  --cat-pink:   #E6544F;

  --pop:        2px 2px 0 0 var(--line);
  --pop-sm:     1.5px 1.5px 0 0 var(--line);
  --pop-hover:  3px 4px 0 0 var(--line);
  --pop-deep:   5px 5px 0 0 var(--line);

  --e-out: cubic-bezier(0.22, 1, 0.36, 1);
  --e-std: cubic-bezier(0.4, 0, 0.2, 1);
  --e-in:  cubic-bezier(0.55, 0.06, 0.68, 0.19);

  --font-display: 'Aileron', system-ui, sans-serif;
  --font-body:    'Vegur', system-ui, sans-serif;
  --font-mono:    'JetBrains Mono', ui-monospace, monospace;

  --tool-bg: var(--paper);
  /* Iconos de la barra de nodos, por grupo (Topbar.jsx, .tool-icon--<grupo>).
     Todos blancos: los colores no hacen falta para distinguirlos. */
  --tool-fg:            #1A1A1A;
  --tool-escribir-bg:   #FFFFFF;
  --tool-medios-bg:     #FFFFFF;
  --tool-estructura-bg: #FFFFFF;
  --tool-trazos-bg:     #FFFFFF;
}

[data-theme="dark"] {
  --bg:        #232123;
  --bg-2:      #2A282A;
  --bg-3:      #333133;
  --paper:     #3A383A;
  --paper-2:   #2E2C2E;
  --ink:       #F0EEF0;
  --ink-2:     #A5A1A5;
  --ink-3:     #7A767A;
  --lila:      #A994DA;
  --line:      var(--lila);
  --line-soft: color-mix(in srgb, var(--lila) 35%, transparent);
  --line-softer: color-mix(in srgb, var(--lila) 16%, transparent);

  --acento:  var(--lila);
  --olive:   var(--acento);
  --olive-l: color-mix(in srgb, var(--acento) 22%, var(--paper));
  --olive-2: color-mix(in srgb, var(--acento) 45%, var(--paper));
  --wine:    var(--acento);
  --wine-l:  color-mix(in srgb, var(--acento) 22%, var(--paper));
  --wine-2:  color-mix(in srgb, var(--acento) 45%, var(--paper));
  --olive-texto: var(--acento);
  --wine-texto:  var(--acento);
  --menu-hover: #4A4D3C;
  --columna-fondo: var(--bg-2);

  --frame-title-color: #F0EEF0;
  --bg-card:           #3A383A;
  --bg-main:           #2A282A;
  --text:              #F0EEF0;
  --text-soft:         #A5A1A5;
}
[data-theme="dark"] .frame-card {
  --line: var(--lila);
}
body[data-theme="dark"] { background: #2A282A; }
[data-theme="dark"] .canvas-wrap {
  background-color: #2A282A;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='22' height='22'%3E%3Cpath d='M11 9.5L12.6 12.3H9.4Z' fill='%23F0EEF0' fill-opacity='0.18'/%3E%3C/svg%3E");
  background-size: 22px 22px;
}
[data-theme="dark"] .topbar { background: #3A383A; border-color: var(--line); }
[data-theme="dark"] .tools { background: #2A282A; }
[data-theme="dark"] .tool .tool-label { color: #F0EEF0; }
[data-theme="dark"] .ctx-side { background: #3A383A; border-color: var(--line); }
[data-theme="dark"] .ctx-btn { color: #F0EEF0; }
[data-theme="dark"] .ctx-btn:hover { background: var(--menu-hover); }
[data-theme="dark"] .ctx-close { color: #F0EEF0; }
[data-theme="dark"] .ctx-close:hover { background: #2A282A; }
[data-theme="dark"] .ctx-popout { background: #3A383A; border-color: var(--line); color: #F0EEF0; }
[data-theme="dark"] .ctx-pop-title { color: #F0EEF0; }
[data-theme="dark"] .icon-btn { background: #3A383A; }
[data-theme="dark"] .icon-btn .material-symbols-rounded { color: #F0EEF0; }
[data-theme="dark"] .avatar { color: white; }
[data-theme="dark"] .lang-switch { background: #3A383A; }
[data-theme="dark"] .lang-switch span { color: #F0EEF0 !important; }
[data-theme="dark"] .lang-switch button { color: #F0EEF0; }
[data-theme="dark"] .lang-switch button.active { background: #F0EEF0; color: #1A1A1A; }
[data-theme="dark"] .zoom-ctrls { background: #3A383A; }
[data-theme="dark"] .zoom-ctrls button { color: #F0EEF0; }
[data-theme="dark"] .zoom-ctrls button:hover { background: #2A282A; }
[data-theme="dark"] .mini-search { background: #3A383A; border-color: var(--line); }
[data-theme="dark"] .mini-search input { color: #F0EEF0; }
[data-theme="dark"] .mini-search input::placeholder { color: #A5A1A5; }
[data-theme="dark"] .mini-search kbd { background: #2A282A; color: #A5A1A5; }
[data-theme="dark"] .status-pill { background: #3A383A; border-color: var(--line); color: #F0EEF0; }

/* ── Dark theme — Home / project menu ── */
[data-theme="dark"] .miro-home { background: #232123; }
[data-theme="dark"] .ms-side { background: #2A282A; border-color: var(--line); }
[data-theme="dark"] .ms-brand,
[data-theme="dark"] .ms-nav-item,
[data-theme="dark"] .ms-user-name,
[data-theme="dark"] .ms-section h2,
[data-theme="dark"] .ms-hero-title { color: #F0EEF0; }
[data-theme="dark"] .ms-nav-label,
[data-theme="dark"] .ms-user-sub,
[data-theme="dark"] .ms-nav-item .material-symbols-rounded,
[data-theme="dark"] .ms-nav-item .ms-nav-count,
[data-theme="dark"] .ms-section-link,
[data-theme="dark"] .ms-view-toggle button { color: #A5A1A5; }
[data-theme="dark"] .ms-nav-item:hover { background: var(--menu-hover); color: #fff; }
[data-theme="dark"] .ms-nav-item.active { color: #1A1A1A !important; }
[data-theme="dark"] .ms-nav-item.active .material-symbols-rounded { color: var(--olive-texto) !important; }
[data-theme="dark"] .ms-nav-item.active .ms-nav-count { color: #595459 !important; }
[data-theme="dark"] .ms-side-foot { border-color: var(--line); }
[data-theme="dark"] .ms-search { background: #3A383A; border-color: var(--line); }
[data-theme="dark"] .ms-search input { color: #F0EEF0; }
[data-theme="dark"] .ms-search input::placeholder { color: #A5A1A5; }
[data-theme="dark"] .ms-search kbd { background: #2A282A; border-color: var(--line); color: #A5A1A5; }
[data-theme="dark"] .ms-hero { background: #2F2D2F; border-color: var(--line); }
[data-theme="dark"] .ms-hero-sub { color: #C9C5C9; }
[data-theme="dark"] .ms-hero-eyebrow { color: #C9C5C9; }
[data-theme="dark"] .ms-recent-card,
[data-theme="dark"] .ms-project-card,
[data-theme="dark"] .ms-recent-body,
[data-theme="dark"] .ms-project-body { background: #2F2D2F; border-color: var(--line); }
[data-theme="dark"] .ms-recent-title,
[data-theme="dark"] .ms-project-title { color: #F0EEF0; }
[data-theme="dark"] .ms-recent-meta,
[data-theme="dark"] .ms-project-meta { color: #A5A1A5; }
[data-theme="dark"] .ms-new-cover { background: #232123; }

* { box-sizing: border-box; }
html, body, #root { height: 100%; margin: 0; }

/* ── Las barras de desplazamiento de toda la aplicación ──
   Finas, redondeadas, sin flechas y del color de la tinta con transparencia,
   así que valen igual en claro y en oscuro. Hasta ahora solo las tenían
   algunos sitios (el calendario, las tareas, la barra del nodo) y todo lo
   demás salía con la barra gris de Windows, con sus flechas: el panel de
   fotos de la galería, la pantalla de inicio, los paneles de al lado... (lo
   vio el usuario: "no es el de la app"). Las que ya tenían la suya la
   conservan: sus reglas son más concretas que estas. */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track, ::-webkit-scrollbar-corner { background: transparent; }
::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--ink) 24%, transparent);
  border-radius: 4px;
  border: 2px solid transparent; background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background-color: color-mix(in srgb, var(--ink) 40%, transparent); }
body {
  font-family: var(--font-body);
  color: var(--ink);
  background: var(--bg);
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
  transition: background 200ms var(--e-out), color 200ms var(--e-out);
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='M4.5 4.5L12.5 20.5L15.5 13.5L22.5 10.5L4.5 4.5Z' fill='%231A1A1A' stroke='%2390B968' stroke-width='1.5' stroke-linejoin='round'/%3E%3C/svg%3E") 4 4, auto;
}

button { font-family: inherit; font-size: inherit; color: inherit; background: none; border: none; padding: 0; }
input, textarea { font-family: inherit; color: inherit; background: none; border: none; outline: none; resize: none; overflow-wrap: break-word; word-break: break-word; }

/* Custom Brand Clickable Cursor — en el lila de --lila (#A48FD0). Va escrito
   a mano: un SVG dentro de url() no puede leer variables CSS. */
a, button, select, input[type="submit"], input[type="button"], [role="button"], 
.todo-check, .todo-add, .cal-mb-pick-btn, .btn, .ctx-btn, .project-card, 
.sidebar-link, .icon-btn, .theme-btn, .lang-switch select, .lang-select, .avatar, .todo-row, .board-preview-item {
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='M4.5 4.5L12.5 20.5L15.5 13.5L22.5 10.5L4.5 4.5Z' fill='%23A48FD0' stroke='white' stroke-width='1.5' stroke-linejoin='round'/%3E%3C/svg%3E") 4 4, pointer;
}

/* ─── Cosméticos de patrocinador ───
   Quién los lleva se decide en `patrocinio.js`; el atributo del <body> lo pone
   `app.jsx`. Colgar el cursor de un atributo y no de una clase por elemento
   evita tener que repetir la regla en los treinta sitios de abajo. */

/* El boton dorado de la barra. Solo lo ve quien tiene la corona.

   Mismo tratamiento que el boton de Apoyar —relleno, degradado en movimiento y
   halo de color— pero en dorado. Antes era un boton palido con un brillo suave
   y al lado del rojo de Apoyar parecia apagado; lo que se compra aqui es que se
   vea, asi que tiene que competir de tu a tu con el boton mas llamativo de la
   barra. */
/* .icon-btn.corona-btn y no .corona-btn a secas: este bloque esta al
   principio del archivo y .icon-btn setecientas lineas mas abajo. A igualdad
   de especificidad gana la que va despues, asi que la sombra generica del
   boton se comia el halo dorado y la corona encendida salia apagada. */
.icon-btn.corona-btn {
  position: relative;
  border: 1.5px solid rgba(255, 255, 255, 0.3) !important;
  background: linear-gradient(135deg, #E0A82E, #F6D65C, #C1841B, #E0A82E) !important;
  background-size: 300% 100%;
  animation: corona-brillo 6s ease infinite;
  box-shadow: 0 4px 16px rgba(224, 168, 46, 0.45), 0 0 8px rgba(246, 214, 92, 0.2);
}

[data-theme="dark"] .icon-btn.corona-btn {
  border-color: rgba(255, 255, 255, 0.22) !important;
  box-shadow: 0 4px 18px rgba(224, 168, 46, 0.5), 0 0 10px rgba(246, 214, 92, 0.25);
}

.icon-btn.corona-btn:hover {
  box-shadow: 0 6px 22px rgba(224, 168, 46, 0.65), 0 0 14px rgba(246, 214, 92, 0.35);
}

/* Sobre el relleno dorado, una corona dorada desaparece. Pasa a blanca, igual
   que el texto del boton de Apoyar sobre su rojo, y las piedras se quedan en
   oro claro para que la silueta siga leyendose. */
.corona-btn:not(.apagada) .corona-dibujo svg path {
  fill: #FFFFFF;
  stroke: rgba(108, 72, 12, 0.5);
}
.corona-btn:not(.apagada) .corona-dibujo svg circle {
  fill: #F0C64B;
}
.corona-btn:not(.apagada) .corona-dibujo {
  filter: drop-shadow(0 1px 2px rgba(90, 60, 8, 0.45));
}

/* El degradado se mueve despacio, como el de Apoyar. Seis segundos: se percibe
   sin llamar la atencion cada dos por tres. */
@keyframes corona-brillo {
  0%   { background-position: 0% 50%; }
  50%  { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}

@media (prefers-reduced-motion: reduce) {
  .corona-btn { animation: none; }
}

/* Apagada: la corona en gris, pero con un halo dorado muy tenue alrededor.
   Se ve siempre, también para quien no ha pagado, y a propósito: una corona
   que solo existe cuando ya la tienes no le cuenta a nadie que exista. Así se
   entiende de un vistazo que hay algo que conseguir, sin un cartel pidiendo
   dinero. */
.icon-btn.corona-btn.apagada {
  border-color: var(--line-soft, #E5E1DD) !important;
  background: var(--paper, #FFF) !important;
  background-image: none !important;
  box-shadow: 2px 2px 0 var(--line-soft, #E5E1DD), 0 0 7px rgba(224, 168, 46, 0.28);
  animation: none;
  opacity: 0.92;
}

[data-theme="dark"] .icon-btn.corona-btn.apagada {
  border-color: #4A474A !important;
  background: #232123 !important;
  box-shadow: 2px 2px 0 #4A474A, 0 0 8px rgba(224, 168, 46, 0.3);
}

/* Al pasar por encima se insinúa lo que se gana. */
.icon-btn.corona-btn.apagada:hover,
[data-theme="dark"] .icon-btn.corona-btn.apagada:hover {
  box-shadow: 2px 2px 0 rgba(201, 150, 42, 0.6), 0 0 15px rgba(224, 168, 46, 0.6);
  opacity: 1;
}

.corona-btn.apagada .corona-dibujo {
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.25));
}


.corona-dibujo {
  display: grid;
  place-items: center;
  pointer-events: none;
  filter: drop-shadow(0 1px 1.5px rgba(0, 0, 0, 0.4));
}

.corona-patrocinador {
  position: absolute;
  top: -3px;
  right: -4px;
  display: grid;
  place-items: center;
  pointer-events: none;
  /* Sin sombra, el dorado se pierde encima de un botón claro. */
  filter: drop-shadow(0 1px 1.5px rgba(0, 0, 0, 0.4));
  animation: corona-aparece 420ms var(--e-out) both;
}

/* Aparece creciendo un poco de más y volviendo. Es la única señal de que algo
   se acaba de desbloquear: sin ella, la corona simplemente está ahí y nadie
   se entera de que ha cambiado nada. */
@keyframes corona-aparece {
  0%   { opacity: 0; transform: scale(0.2) rotate(-18deg); }
  65%  { opacity: 1; transform: scale(1.22) rotate(4deg); }
  100% { opacity: 1; transform: scale(1) rotate(0deg); }
}

@media (prefers-reduced-motion: reduce) {
  .corona-patrocinador { animation: none; }
}

/* El aro que gira mientras se comprueba una donación. La espera puede irse a
   veinte segundos cuando la función del servidor lleva rato apagada, y una
   pantalla quieta durante veinte segundos parece una pantalla rota. */
.corona-girando {
  animation: spin 900ms linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .corona-girando { animation: none; }
}

/* ══════════════════════════════════════════════════════════════════
   EL TALLER DE LA CORONA
   ══════════════════════════════════════════════════════════════════
   Lo que se compra con una donación no es una función: es que se note. Así
   que esta ventana no puede estar hecha del mismo gris que el resto de la
   aplicación — si se pareciera a Ajustes, no habría nada que enseñar.
   El dorado va en el borde, en el halo y en el botón que guarda; el resto se
   queda en su sitio para que el color elegido siga siendo el protagonista.

   Y todo lo que se puede pulsar responde al pulsarlo. Antes estos botones
   llevaban su estilo escrito en el propio elemento, y un estilo escrito ahí
   gana a cualquier regla de :hover o :active que se escriba aquí: se veían
   tiesos y no era una impresión, es que literalmente no tenían respuesta. */

.corona-taller {
  width: min(380px, 100%);
  max-height: 86vh;
  overflow-y: auto;
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 15px;
  border-radius: 16px;
  color: var(--ink, #1A1A1A);
  border: 1.5px solid rgba(224, 168, 46, 0.55);
  /* El degradado se apaga a los 160 px: es un reflejo en la parte de arriba,
     no un fondo amarillo. Un panel entero en dorado no se puede leer. */
  background:
    linear-gradient(180deg, rgba(224, 168, 46, 0.14), rgba(224, 168, 46, 0) 160px),
    var(--bg-card, #FFFFFF);
  box-shadow:
    0 24px 70px rgba(0, 0, 0, 0.38),
    0 0 30px rgba(224, 168, 46, 0.13);
}
[data-theme="dark"] .corona-taller {
  border-color: rgba(224, 168, 46, 0.45);
  background:
    linear-gradient(180deg, rgba(224, 168, 46, 0.16), rgba(224, 168, 46, 0) 160px),
    var(--bg-card, #201F24);
  box-shadow:
    0 24px 70px rgba(0, 0, 0, 0.6),
    0 0 34px rgba(224, 168, 46, 0.16);
}

/* La raya de debajo de la cabecera: dorada en el centro y transparente en las
   puntas, para que no parezca un borde de tabla. */
.corona-hilo {
  height: 1px;
  border: 0;
  margin: 0;
  background: linear-gradient(90deg,
    rgba(224, 168, 46, 0) 0%,
    rgba(224, 168, 46, 0.55) 50%,
    rgba(224, 168, 46, 0) 100%);
}

.corona-rotulo {
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #A8791A;
}
[data-theme="dark"] .corona-rotulo { color: #E0A82E; }

/* ── Las dos pestañas ── */
.corona-pestana {
  flex: 1;
  padding: 9px 10px;
  border-radius: 9px;
  font-size: 12.5px;
  font-weight: 700;
  cursor: pointer;
  color: var(--ink-3, #595459);
  border: 1.5px solid var(--line-soft, #E5E1DD);
  background: transparent;
  transition: transform 120ms var(--e-out), border-color 140ms, background 140ms, color 140ms;
}
.corona-pestana:hover { color: var(--ink, #1A1A1A); border-color: rgba(224, 168, 46, 0.55); }
.corona-pestana:active { transform: scale(0.975); }
.corona-pestana.activa {
  color: #6B4E0A;
  border-color: rgba(224, 168, 46, 0.9);
  background: linear-gradient(180deg, rgba(246, 214, 92, 0.38), rgba(224, 168, 46, 0.18));
}
[data-theme="dark"] .corona-pestana.activa {
  color: #F6D65C;
  background: linear-gradient(180deg, rgba(224, 168, 46, 0.30), rgba(224, 168, 46, 0.10));
}

/* ── Guardar: el único botón dorado de toda la aplicación ── */
.corona-guardar {
  flex: 1;
  padding: 11px;
  border-radius: 10px;
  cursor: pointer;
  font-weight: 800;
  font-size: 13px;
  color: #3E2C05;
  border: 1.5px solid rgba(122, 83, 16, 0.45);
  background: linear-gradient(180deg, #F6D65C 0%, #E0A82E 55%, #C1841B 100%);
  box-shadow: 0 6px 16px rgba(224, 168, 46, 0.32), inset 0 1px 0 rgba(255, 255, 255, 0.55);
  transition: transform 130ms var(--e-out), box-shadow 130ms var(--e-out), filter 130ms;
}
.corona-guardar:hover {
  transform: translateY(-2px);
  filter: brightness(1.05);
  box-shadow: 0 11px 24px rgba(224, 168, 46, 0.42), inset 0 1px 0 rgba(255, 255, 255, 0.6);
}
/* Se hunde de verdad: baja, encoge y la sombra pasa de estar debajo a estar
   dentro. Es la diferencia entre un botón que responde y uno que parece un
   dibujo. */
.corona-guardar:active {
  transform: translateY(2px) scale(0.985);
  box-shadow: 0 1px 3px rgba(224, 168, 46, 0.25), inset 0 2px 6px rgba(122, 83, 16, 0.4);
}
.corona-guardar.hecho {
  color: #22431C;
  border-color: rgba(58, 92, 41, 0.5);
  background: linear-gradient(180deg, #C7E3A6 0%, #90B968 55%, #6A8546 100%);
  box-shadow: 0 6px 16px rgba(144, 185, 104, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.5);
}

/* ── "El de siempre": secundario, pero no muerto ── */
.corona-normal {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 11px 14px;
  border-radius: 10px;
  cursor: pointer;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--ink-3, #595459);
  border: 1.5px solid var(--line-soft, #E5E1DD);
  background: transparent;
  transition: transform 130ms var(--e-out), border-color 140ms, background 140ms, color 140ms, box-shadow 140ms;
}
.corona-normal:hover {
  color: var(--ink, #1A1A1A);
  border-color: rgba(224, 168, 46, 0.6);
  background: rgba(224, 168, 46, 0.10);
}
.corona-normal:active {
  transform: scale(0.96);
  background: rgba(224, 168, 46, 0.2);
  border-color: rgba(224, 168, 46, 0.8);
}
/* Sin nada que restablecer no hay nada que pulsar, y decirlo apagándolo es más
   honesto que dejar un botón que no hace nada. */
.corona-normal:disabled {
  opacity: 0.45;
  cursor: default;
  transform: none;
  background: transparent;
  border-color: var(--line-soft, #E5E1DD);
}

/* ── El botón de subir una imagen ── */
.corona-imagen {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 11px;
  border-radius: 10px;
  cursor: pointer;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--ink, #1A1A1A);
  border: 1.5px dashed rgba(224, 168, 46, 0.55);
  background: rgba(224, 168, 46, 0.06);
  transition: transform 130ms var(--e-out), background 140ms, border-color 140ms;
}
.corona-imagen:hover { background: rgba(224, 168, 46, 0.14); border-color: rgba(224, 168, 46, 0.85); }
.corona-imagen:active { transform: scale(0.98); }

@media (prefers-reduced-motion: reduce) {
  .corona-guardar, .corona-normal, .corona-pestana, .corona-imagen { transition: none; }
}

/* ── El historial del selector de color, cuando va todo en una fila ── */
.selector-color-raya {
  width: 1.5px;
  border-radius: 1px;
  margin: 0 4px;
  background: linear-gradient(180deg,
    rgba(142, 138, 142, 0) 0%,
    var(--line, #8E8A8E) 25%,
    var(--line, #8E8A8E) 75%,
    rgba(142, 138, 142, 0) 100%);
}
/* El reloj dice qué son las casillas que vienen detrás sin gastar una línea de
   texto. Con el rótulo escrito no cabían en una fila, y sin nada delante once
   círculos seguidos parecen una única paleta. */
.selector-color-reloj {
  font-size: 15px;
  color: var(--ink-3, #8E8A8E);
  cursor: default;
  user-select: none;
}


/* El cursor, en dorado en vez de en verde. Mismo dibujo que el normal: la
   gracia es que se note el color, no que cambie la forma y desoriente. */
body[data-patrocinador="1"] {
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='M4.5 4.5L12.5 20.5L15.5 13.5L22.5 10.5L4.5 4.5Z' fill='%231A1A1A' stroke='%23E0A82E' stroke-width='1.5' stroke-linejoin='round'/%3E%3C/svg%3E") 4 4, auto;
}

body[data-patrocinador="1"] a,
body[data-patrocinador="1"] button,
body[data-patrocinador="1"] select,
body[data-patrocinador="1"] input[type="submit"],
body[data-patrocinador="1"] input[type="button"],
body[data-patrocinador="1"] [role="button"],
body[data-patrocinador="1"] .todo-check,
body[data-patrocinador="1"] .todo-add,
body[data-patrocinador="1"] .cal-mb-pick-btn,
body[data-patrocinador="1"] .btn,
body[data-patrocinador="1"] .ctx-btn,
body[data-patrocinador="1"] .project-card,
body[data-patrocinador="1"] .sidebar-link,
body[data-patrocinador="1"] .icon-btn,
body[data-patrocinador="1"] .theme-btn,
body[data-patrocinador="1"] .lang-switch select,
body[data-patrocinador="1"] .lang-select,
body[data-patrocinador="1"] .avatar,
body[data-patrocinador="1"] .todo-row,
body[data-patrocinador="1"] .board-preview-item {
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='M4.5 4.5L12.5 20.5L15.5 13.5L22.5 10.5L4.5 4.5Z' fill='%23E0A82E' stroke='white' stroke-width='1.5' stroke-linejoin='round'/%3E%3C/svg%3E") 4 4, pointer;
}


.material-symbols-rounded { font-variation-settings: 'FILL' 0, 'wght' 500, 'GRAD' 0, 'opsz' 24; user-select: none; }
/* Los iconos propios (src/iconos/iconos.js): un dibujo en vez de la letra de
   Material. Mide 1em, como la letra a la que sustituye, y el trazo crece con
   el tamaño igual que crecía el grosor de la letra. No se toca el display del
   icono: hay reglas que lo esconden con display:none y tienen que seguir
   ganando. */
.odi-icono > svg { width: 1em; height: 1em; display: block; margin: 0 auto; overflow: visible; stroke-width: 1.5px; }
/* El nombre escondido del icono: hay reglas como «.barra span { display: flex }»
   que le ganarían al hidden del navegador. */
.odi-icono > span[hidden] { display: none !important; }
/* De derecha a izquierda (árabe), las flechas que dicen «atrás», «adelante» o
   «siguiente» miran al otro lado; las demás (deshacer, girar…) se quedan. */
[dir="rtl"] .odi-icono:is([data-icono="arrow_back"], [data-icono="chevron_left"], [data-icono="chevron_right"], [data-icono="arrow_outward"], [data-icono="near_me"]) > svg { transform: scaleX(-1); }
/* El lienzo no se pone en espejo: los nodos van donde los dejas. */
[dir="rtl"] .canvas-wrap { direction: ltr; }
/* La barra del nodo y sus paneles, a la derecha (con la barra de nodos a un
   lado se quedan donde estaban, para no montarse con ella). */
html[dir="rtl"]:not([data-mobile="1"]):not([data-barra="left"]):not([data-barra="right"]) .ctx-side { left: auto; right: 14px; }
html[dir="rtl"]:not([data-mobile="1"]):not([data-barra="left"]):not([data-barra="right"]) .ctx-popout { left: auto; right: 100px; transform-origin: right top; }
[dir="rtl"] .ctx-side, [dir="rtl"] .ctx-popout { direction: rtl; }
/* Los códigos (colores, atajos, rutas, código) se leen siempre de izquierda a
   derecha: en espejo salía «FFFFFF#» y «255 ,255 ,255». */
[dir="rtl"] .panel-color input, [dir="rtl"] kbd, [dir="rtl"] code, [dir="rtl"] .code-area, [dir="rtl"] .ms-vault-path { direction: ltr; unicode-bidi: isolate; }
/* El texto que escribe la gente sigue SU dirección, en cualquier idioma de la
   interfaz: una nota en árabe se alinea a la derecha y una en español a la
   izquierda, cada párrafo según lo que lleve. Antes todo iba a la izquierda. */
.canvas-surface [contenteditable], .canvas-surface textarea, .canvas-surface input[type="text"],
.canvas-surface .rich, .canvas-surface .rich > *, .canvas-surface .rich li,
.doc-modal-window [contenteditable] { unicode-bidi: plaintext; text-align: start; }
/* «Lleno»: lo que Material pintaba con FILL 1. Solo se rellena lo marcado con r. */
.odi-icono.icono-lleno > svg .r,
.boton-fijar.fijada .odi-icono > svg .r,
.ms-folder-card.con-color .ms-folder-icono > svg .r,
.nodo-candado .odi-icono > svg .r { fill: currentColor; }

/* ─── motion ─── */
.lift { transition: transform 140ms var(--e-out), box-shadow 140ms var(--e-out); }
.lift:hover { transform: translate(-1px, -2px); box-shadow: var(--pop-hover); }
.press { transition: transform 80ms var(--e-out); }
.press:active { transform: scale(0.97); }

/* ============================================
   HOME — Miro-style (sidebar + main)
   ============================================ */
.miro-home {
  height: 100%; width: 100%;
  display: flex;
  background: var(--bg);
  overflow: hidden;
}

/* Sidebar */
.ms-side {
  width: 320px; flex-shrink: 0;
  background: var(--menu-fondo);
  border-right: 1.5px solid var(--line);
  display: flex; flex-direction: column;
  padding: 16px 12px;
  overflow-y: auto;
}
.ms-brand {
  display: flex; align-items: center; gap: 9px;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 18px;
  letter-spacing: -0.02em;
  padding: 4px 8px 14px;
  color: var(--ink);
}
.ms-brand .brand-mark {
  position: relative;
  width: 28px; height: 28px;
  border-radius: 50%;
  background: white;
  display: grid; place-items: center;
  box-shadow: 0 0 10px rgba(255, 255, 255, 0.4);
}

/* ── La chincheta: siempre encima y sin bordes ──
   En reposo, la chincheta inclinada; fijada, en verde, rellena y derecha,
   con un pequeño rebote al clavarse. */
.boton-fijar {
  width: 30px; height: 30px; flex-shrink: 0;
  display: grid; place-items: center;
  border: 1.5px solid var(--line); border-radius: 8px;
  background: var(--paper); color: var(--ink-2);
  box-shadow: var(--pop-sm);
  cursor: pointer;
  transition: transform 160ms var(--e-out), box-shadow 160ms, background-color 200ms, color 200ms;
}
.boton-fijar:hover { transform: translate(-1px, -1px); box-shadow: var(--pop); color: var(--ink); }
.boton-fijar .material-symbols-rounded { font-size: 17px; transform: rotate(40deg); transition: transform 460ms var(--muelle); }
.boton-fijar.fijada { background: var(--olive); color: var(--olive-ink); }
.boton-fijar.fijada .material-symbols-rounded { transform: rotate(0deg); font-variation-settings: 'FILL' 1; }
/* En la cabecera de inicio, del tamaño de los botones de al lado y empujada
   al extremo derecho. */
.ms-top > .fijar-caja { margin-left: auto; }
.ms-top .boton-fijar { width: 38px; height: 38px; }
.ms-top .boton-fijar .material-symbols-rounded { font-size: 20px; }
/* En el lienzo, a la derecha del todo y a la altura del buscador
   (.mini-search: top 14px, 37 de alto). */
.fijar-lienzo { position: absolute; top: 14px; right: 16px; z-index: 40; height: 37px; display: flex; align-items: center; }
.fijar-lienzo .boton-fijar { width: 34px; height: 34px; }

/* La transparencia de la ventana fijada: sale al pasar el ratón por la
   chincheta, debajo y pegada a su borde derecho (está arriba a la derecha del
   todo). El hueco de 8 px va DENTRO del contenedor (padding), para que al bajar
   el ratón hasta la barrita no se cierre por el camino. */
.fijar-caja { position: relative; display: inline-flex; }
.fijar-opacidad {
  position: absolute; top: 100%; right: 0; z-index: 60;
  padding-top: 8px;
}
.fijar-opacidad-panel {
  width: 200px; padding: 9px 11px 10px;
  background: var(--paper); color: var(--ink);
  border: 1.5px solid var(--line); border-radius: 8px;
  box-shadow: var(--pop);
  animation: fijar-opacidad-entra 220ms var(--muelle) both;
}
@keyframes fijar-opacidad-entra { from { opacity: 0; transform: translateY(-4px) scale(0.97); } to { opacity: 1; transform: none; } }
.fijar-opacidad-fila { display: flex; align-items: baseline; justify-content: space-between; font-size: 11.5px; font-weight: 700; margin-bottom: 6px; }
.fijar-opacidad-fila span:last-child { font-family: var(--font-mono); color: var(--ink-2); }
.fijar-opacidad input[type=range] { width: 100%; accent-color: var(--olive); cursor: pointer; }
/* Con la ventana fijada, lo que la mueve lo dice el cursor. */
html[data-ventana-fijada] [data-mueve-ventana] { cursor: grab; }
html[data-ventana-fijada] [data-mueve-ventana]:active { cursor: grabbing; }

.ms-new-btn {
  display: flex; align-items: center; gap: 8px;
  background: var(--olive); color: var(--olive-ink);
  padding: 9px 12px;
  border-radius: 2px;
  font-weight: 700;
  font-size: 13.5px;
  border: 1.5px solid var(--line);
  box-shadow: var(--pop-sm);
  margin-bottom: 16px;
  transition: transform 140ms var(--e-out), box-shadow 140ms var(--e-out);
}
.ms-new-btn:hover { transform: translate(-1px, -2px); box-shadow: var(--pop-hover); }
.ms-new-btn:active { transform: translate(1px, 1px); box-shadow: 0 0 0 0 var(--line); }
.ms-new-btn .material-symbols-rounded { font-size: 18px; }

.ms-join-btn:hover {
  background: rgba(106, 133, 70, 0.05) !important;
  transform: translate(-1px, -2px);
  box-shadow: var(--pop-hover);
}
.ms-join-btn:active {
  transform: translate(1px, 1px);
  box-shadow: 0 0 0 0 var(--line);
}

.ms-nav { display: flex; flex-direction: column; gap: 1px; }
.ms-nav-label {
  font-size: 10.5px;
  font-weight: 700;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 6px 10px 4px;
  font-family: var(--font-mono);
}
.ms-nav-item {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 10px;
  border-radius: 2px;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-2);
  width: 100%;
  text-align: left;
  transition: background 100ms, color 100ms;
}
.ms-nav-item:hover { background: var(--menu-hover); color: var(--ink); }
.ms-nav-item.active { background: var(--olive-l); color: var(--ink); font-weight: 700; }
.ms-nav-item.active .material-symbols-rounded { color: var(--olive-texto); }
.ms-nav-item .material-symbols-rounded { font-size: 17px; color: var(--ink-3); }
.ms-nav-item .ms-nav-count { margin-left: auto; font-family: var(--font-mono); font-size: 10px; color: var(--ink-3); }
.ms-nav-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; margin-left: 4px; margin-right: 4px; }

.ms-side-foot { margin-top: auto; padding-top: 14px; border-top: 1.5px solid var(--line-softer); }
.ms-user { display: flex; align-items: center; gap: 9px; padding: 6px 8px; border-radius: 2px; }
.ms-user:hover { background: var(--menu-hover); }
.ms-user .avatar { width: 30px; height: 30px; font-size: 12px; }
.ms-user-meta { display: flex; flex-direction: column; gap: 1px; }
.ms-user-name { font-size: 12.5px; font-weight: 700; }
.ms-user-sub { font-size: 10.5px; color: var(--ink-3); }

/* Main */
.ms-main { flex: 1; overflow-y: auto; padding: 18px 32px 40px; }
.ms-top {
  display: flex; align-items: center; gap: 12px;
  margin-bottom: 24px;
}
.ms-search {
  flex: 1;
  display: flex; align-items: center; gap: 10px;
  background: var(--paper);
  border: 1.5px solid var(--line);
  border-radius: 2px;
  box-shadow: var(--pop-sm);
  padding: 9px 14px;
  max-width: 560px;
}
.ms-search input { flex: 1; font-size: 14px; }
.ms-search .material-symbols-rounded { color: var(--ink-3); font-size: 18px; }
.ms-search kbd { font-family: var(--font-mono); font-size: 11px; padding: 1px 5px; background: var(--bg); border: 1px solid var(--line-soft); border-radius: 2px; color: var(--ink-3); }
.ms-top-actions { display: flex; align-items: center; gap: 8px; }
/* El buscador cede sitio antes que los botones: con la chincheta al final de
   la fila, en una ventana de 1280 px la fila se salía por la derecha (el
   campo de texto no bajaba de su ancho natural). */
.ms-search { min-width: 160px; }
.ms-search input { min-width: 0; }

/* Hero */
.ms-hero {
  background: var(--paper);
  border: 1.5px solid var(--line);
  border-radius: 2px;
  box-shadow: var(--pop);
  padding: 36px 40px;
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 32px;
  margin-bottom: 36px;
  overflow: hidden;
  position: relative;
}
.ms-hero-eyebrow {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 11px;
  background: var(--bg);
  border: 1.5px solid var(--line);
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 600;
  margin-bottom: 18px;
}
.ms-hero-eyebrow .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--olive); }
.ms-hero-title {
  font-family: var(--font-display);
  font-size: clamp(28px, 3.6vw, 44px);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.05;
  margin: 0 0 14px;
  color: var(--ink);
}
.ms-hero-title .hero-mark {
  background: linear-gradient(180deg, transparent 60%, var(--olive-2) 60%);
  padding: 0 4px;
}
.ms-hero-sub { font-size: 15px; color: var(--ink-2); margin: 0 0 22px; line-height: 1.55; max-width: 520px; }
.ms-hero-cta { display: flex; gap: 10px; }

/* Hero art */
.ms-hero-art {
  position: relative;
  height: 200px;
}
.ms-art-card {
  position: absolute;
  background: var(--paper);
  border: 1.5px solid var(--line);
  border-radius: 2px;
  box-shadow: var(--pop-sm);
  width: 130px;
  overflow: hidden;
}
.ms-art-card.a { top: 10px;  left: 20px;  transform: rotate(-3deg); }
.ms-art-card.b { top: 70px;  left: 130px; transform: rotate(2deg); width: 140px; z-index: 2; }
.ms-art-card.c { top: 130px; left: 30px;  transform: rotate(-1deg); }
.ms-art-card-bar { height: 6px; border-bottom: 1.5px solid var(--line); }
.ms-art-card-body { padding: 10px 11px; display: flex; flex-direction: column; gap: 6px; }
.ms-art-line { height: 6px; background: var(--bg-2); border-radius: 2px; }
.ms-art-line.w40 { width: 40%; }
.ms-art-line.w50 { width: 50%; }
.ms-art-line.w60 { width: 60%; }
.ms-art-line.w70 { width: 70%; }
.ms-art-line.w80 { width: 80%; }
.ms-art-line-svg {
  position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none;
  z-index: 3;
}

/* Sections */
.ms-section { margin-bottom: 32px; }
.ms-section-head {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: 14px;
}
.ms-section-head h2 {
  font-family: var(--font-display);
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0;
}
.ms-section-link { font-size: 13px; color: var(--ink-2); font-weight: 600; }
.ms-section-link:hover { color: var(--olive-texto); }
.ms-view-toggle { display: flex; background: var(--paper); border: 1.5px solid var(--line); border-radius: 2px; overflow: hidden; }
.ms-view-toggle button { width: 30px; height: 28px; display: grid; place-items: center; border-right: 1.5px solid var(--line); transition: background 100ms; }
.ms-view-toggle button:last-child { border-right: none; }
.ms-view-toggle button.active { background: var(--ink); color: var(--bg); }
.ms-view-toggle button:hover:not(.active) { background: var(--bg); }
.ms-view-toggle .material-symbols-rounded { font-size: 15px; }

/* Recent row — horizontal scroll */
.ms-recent-row { display: flex; gap: 14px; }
.ms-recent-card {
  flex: 1; min-width: 0; max-width: 280px;
  background: var(--paper);
  border: 1.5px solid var(--line);
  border-radius: 2px;
  box-shadow: var(--pop-sm);
  overflow: hidden;
  cursor: pointer;
  transition: transform 140ms var(--e-out), box-shadow 140ms var(--e-out);
}
.ms-recent-card:hover { transform: translate(-1px, -2px); box-shadow: var(--pop-hover); }
.ms-recent-cover { position: relative; height: 90px; border-bottom: 1.5px solid var(--line); display: grid; place-items: center; overflow: hidden; }
.ms-recent-cover::before {
  content: '';
  position: absolute; inset: 0;
  background-image: radial-gradient(circle at 1px 1px, rgba(0,0,0,0.08) 1px, transparent 0);
  background-size: 12px 12px;
}
.ms-recent-emoji { font-size: 32px; z-index: 1; }
.ms-recent-cover-overlay {
  position: absolute; top: 6px; right: 6px;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--paper);
  border: 1.5px solid var(--line);
  display: grid; place-items: center;
  opacity: 0;
  transform: translateY(-2px);
  transition: opacity 140ms, transform 140ms;
}
.ms-recent-cover-overlay .material-symbols-rounded { font-size: 13px; }
.ms-recent-card:hover .ms-recent-cover-overlay { opacity: 1; transform: translateY(0); }
.ms-recent-body { padding: 10px 12px; }
.ms-recent-title { font-family: var(--font-display); font-size: 14px; font-weight: 700; letter-spacing: -0.01em; margin-bottom: 3px; }
.ms-recent-meta { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--ink-3); }
.ms-recent-meta .dot { width: 3px; height: 3px; border-radius: 50%; background: var(--ink-3); }

/* Project grid */
.ms-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px;
}
.ms-project-card {
  background: var(--paper);
  border: 1.5px solid var(--line);
  border-radius: 2px;
  box-shadow: var(--pop-sm);
  overflow: hidden;
  cursor: pointer;
  transition: transform 140ms var(--e-out), box-shadow 140ms var(--e-out);
}
.ms-project-card:hover { transform: translate(-1px, -2px); box-shadow: var(--pop-hover); }
.ms-project-card:active { transform: translate(1px, 1px); box-shadow: 0 0 0 0 var(--line); }
.ms-project-cover {
  height: 110px;
  position: relative;
  border-bottom: 1.5px solid var(--line);
  display: grid; place-items: center;
  overflow: hidden;
}
.ms-project-cover::before {
  content: '';
  position: absolute; inset: 0;
  background-image: radial-gradient(circle at 1px 1px, rgba(0,0,0,0.08) 1px, transparent 0);
  background-size: 12px 12px;
  opacity: 0.6;
  /* Esto es una textura, no un botón, y por no decirlo se comió media pantalla.
     En modo lista la portada pasa a `position: static` (ver más abajo, para que
     los botones de la fila se anclen a la fila y no a la miniatura), así que
     este `inset: 0` deja de medirse contra la portada y se mide contra el primer
     antepasado colocado, que puede ser el área entera de proyectos. Invisible,
     pero recibiendo TODOS los clics: pulsar el botón de cambiar de vista abría
     "Nuevo proyecto", y la tarjeta se quedaba con el aspecto de estar siempre
     bajo el ratón. Un adorno nunca debe poder recibir un clic. */
  pointer-events: none;
}
.ms-project-emoji { font-size: 38px; z-index: 1; filter: drop-shadow(1px 2px 0 rgba(0,0,0,0.1)); }

/* Hover action buttons on cards (favourite / delete / restore) */
/* `pointer-events: none` mientras estan invisibles, y no es un detalle.
   Un elemento con `opacity: 0` sigue recibiendo clics: en cuadricula quedaban
   en una esquina de la portada y no molestaban, pero en lista se colocan en
   medio de la fila, asi que el clic para abrir el proyecto se lo llevaba un
   boton que no se veia. Y el cursor cambiaba a mano sobre un sitio donde,
   aparentemente, no habia nada. */
.ms-card-actions { position: absolute; top: 6px; right: 6px; display: flex; gap: 5px; z-index: 3; opacity: 0; pointer-events: none; transition: opacity 130ms; }
.ms-project-card:hover .ms-card-actions,
.ms-recent-card:hover .ms-card-actions { opacity: 1; pointer-events: auto; }
.ms-card-btn {
  width: 26px; height: 26px; display: grid; place-items: center;
  background: rgba(255,255,255,0.94); border: 1.5px solid var(--line);
  border-radius: 4px; box-shadow: 1px 1px 0 var(--line); cursor: pointer;
  /* El botón es blanco en ambos temas, así que el icono siempre debe ser oscuro
     (var(--ink) se vuelve blanco en modo oscuro y el icono desaparecía) */
  color: #1A1A1A;
}
.ms-card-btn:hover { background: #fff; transform: translate(-1px,-1px); box-shadow: 2px 2px 0 var(--line); }
/* En lista, ese pellizco de un pixel apartaba el boton del raton justo cuando
   lo tocabas, se perdia el hover, volvia a su sitio y otra vez: parpadeo. En
   cuadricula no pasa porque hay mas aire alrededor. */
.ms-grid-list .ms-card-btn:hover { transform: none; }

/* Y la fila entera tampoco salta. Ese `translate(-1px, -2px)` del hover mueve
   la tarjeta fuera de debajo del raton cuando el cursor esta cerca de un borde:
   se pierde el hover, vuelve a su sitio, y otra vez. En cuadricula casi no se
   nota porque hay aire entre tarjetas; en lista, con filas de lado a lado y
   pegadas, el raton pasa la mayor parte del tiempo cerca de un borde y el
   parpadeo es constante. La sombra se queda: es la que dice donde estas. */
.ms-grid-list .ms-project-card:hover { transform: none; }
.ms-grid-list .ms-project-card:active { transform: none; }

/* La nube al final del todo y los botones a su izquierda. Es el orden que se
   espera: primero lo que se puede hacer, y el estado al borde. */
.ms-grid-list .odi-nube {
  position: absolute;
  top: 50%;
  right: 14px;
  transform: translateY(-50%);
}
.ms-card-btn.danger:hover { color: var(--wine-texto); }
.ms-card-btn.on { color: #E0A82E; }
.ms-card-btn.star-btn:hover, .ms-card-btn.star-btn.on { color: #E0A82E !important; }
.ms-card-btn .material-symbols-rounded { font-size: 16px; }
.ms-empty-hint { grid-column: 1 / -1; padding: 30px; text-align: center; color: var(--ink-3); font-size: 13px; }

/* List view */
.ms-grid.ms-grid-list { grid-template-columns: 1fr; }
.ms-grid-list .ms-project-card { display: flex; align-items: center; }
.ms-grid-list .ms-project-cover { width: 84px; height: 60px; flex-shrink: 0; border-bottom: none; border-right: 1.5px solid var(--line); }
.ms-grid-list .ms-project-emoji { font-size: 26px; }
/* Hueco al final de la fila para los tres botones y para el icono de la nube,
   que antes se pisaban entre ellos. */
.ms-grid-list .ms-project-body { flex: 1; min-width: 0; padding-right: 108px; }
.ms-grid-list .ms-new-cover { width: 84px; height: 60px; }

.ms-project-body { padding: 11px 14px; }
.ms-project-title { font-family: var(--font-display); font-size: 14px; font-weight: 700; letter-spacing: -0.01em; margin-bottom: 3px; }
.ms-project-meta { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--ink-3); }
.ms-project-meta .dot { width: 3px; height: 3px; border-radius: 50%; background: var(--ink-3); }
.ms-new-project-card .ms-new-cover {
  background: var(--paper-2);
  background-image: repeating-linear-gradient(45deg, transparent, transparent 8px, var(--line-softer) 8px, var(--line-softer) 16px);
}
.ms-new-plus {
  width: 42px; height: 42px;
  border-radius: 2px;
  background: var(--ink);
  color: var(--bg);
  border: 1.5px solid var(--line);
  box-shadow: var(--pop-sm);
  display: grid; place-items: center;
  z-index: 1;
}
.ms-new-plus .material-symbols-rounded { font-size: 22px; }

/* Responsive */
@media (max-width: 980px) {
  .ms-hero { grid-template-columns: 1fr; }
  .ms-hero-art { display: none; }
}
@media (max-width: 700px) {
  .ms-side { display: none; }
  .ms-main { padding: 14px 18px 30px; }
}
.home {
  height: 100%; width: 100%;
  background: var(--bg);
  overflow-y: auto;
  position: relative;
}
.home-nav {
  position: sticky; top: 0;
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 30px;
  background: color-mix(in srgb, var(--bg) 90%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1.5px solid var(--line);
  z-index: 10;
}
.brand { display: flex; align-items: center; gap: 10px; font-family: var(--font-display); font-weight: 800; font-size: 20px; letter-spacing: -0.02em; cursor: pointer; }
.brand-mark {
  position: relative;
  width: 32px; height: 32px;
  border-radius: 50%;
  background: white;
  display: grid; place-items: center;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
.brand-mark img {
  position: relative;
  border-radius: 50%;
  width: 100%; height: 100%;
  z-index: 2;
}
.brand-mark::before {
  content: '';
  position: absolute;
  top: -8px; left: -8px; right: -8px; bottom: -8px;
  border-radius: 50%;
  background: conic-gradient(from 0deg, #FFFFFF, #90B968, #595459, #E6544F, #FFFFFF);
  filter: blur(8px);
  animation: lava-sway 18s ease-in-out infinite;
  z-index: 1;
  pointer-events: none;
}
.brand-mark::after {
  content: '';
  position: absolute;
  top: -6px; left: -6px; right: -6px; bottom: -6px;
  border-radius: 50%;
  background: radial-gradient(circle at 15% 40%, #FFFFFF 0%, rgba(255, 255, 255, 0.75) 30%, rgba(144, 185, 104, 0.25) 55%, transparent 75%);
  filter: blur(2.5px);
  animation: crescent-glow 14s ease-in-out infinite;
  z-index: 1;
  pointer-events: none;
}

[data-theme="dark"] .brand-mark {
  box-shadow: 0 0 12px rgba(255, 255, 255, 0.12);
}
[data-theme="dark"] .brand-mark::before {
  background: conic-gradient(from 0deg, #FFFFFF, #90B968, #595459, #E6544F, #FFFFFF);
  filter: blur(10px);
  opacity: 0.55;
}
[data-theme="dark"] .brand-mark::after {
  background: radial-gradient(circle at 15% 40%, #FFFFFF 0%, rgba(255, 255, 255, 0.8) 25%, rgba(230, 84, 79, 0.2) 50%, transparent 75%);
  filter: blur(3px);
  opacity: 0.85;
}

@keyframes lava-sway {
  0% {
    transform: scale(0.93) translate(-3px, -2px) rotate(-8deg);
    border-radius: 42% 58% 62% 38% / 45% 45% 55% 55%;
    opacity: 0.6;
  }
  50% {
    transform: scale(1.15) translate(2px, 3px) rotate(12deg);
    border-radius: 58% 42% 38% 62% / 55% 55% 45% 45%;
    opacity: 0.85;
  }
  100% {
    transform: scale(0.93) translate(-3px, -2px) rotate(-8deg);
    border-radius: 42% 58% 62% 38% / 45% 45% 55% 55%;
    opacity: 0.6;
  }
}
@keyframes crescent-glow {
  0% {
    transform: scale(0.94) translate(-1px, -1px);
    opacity: 0.7;
  }
  50% {
    transform: scale(1.08) translate(1px, 2px);
    opacity: 0.95;
  }
  100% {
    transform: scale(0.94) translate(-1px, -1px);
    opacity: 0.7;
  }
}

.home-hero { max-width: 1200px; margin: 0 auto; padding: 48px 36px 16px; }
.eyebrow { display: inline-flex; align-items: center; gap: 6px; padding: 5px 12px; background: var(--paper); border: 1.5px solid var(--line); border-radius: 999px; font-size: 12px; font-weight: 600; box-shadow: var(--pop-sm); margin-bottom: 20px; }
.eyebrow .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--olive); }
.home-title { font-family: var(--font-display); font-size: clamp(38px, 5.5vw, 56px); font-weight: 800; letter-spacing: -0.03em; line-height: 1; margin: 0 0 16px; color: var(--ink); }
.home-title .accent { background: linear-gradient(180deg, transparent 62%, var(--olive-2) 62%); padding: 0 4px; }
.home-title .accent.wine { background: linear-gradient(180deg, transparent 62%, var(--wine-2) 62%); }
.home-sub { font-size: 17px; color: var(--ink-2); max-width: 560px; margin: 0 0 28px; line-height: 1.5; }

.home-toolbar { display: flex; align-items: center; gap: 10px; max-width: 1200px; margin: 0 auto; padding: 0 36px 24px; }
.search-input { flex: 1; display: flex; align-items: center; gap: 10px; padding: 10px 14px; background: var(--paper); border: 1.5px solid var(--line); border-radius: 2px; box-shadow: var(--pop-sm); }
.search-input input { flex: 1; font-size: 15px; }

.btn { display: inline-flex; align-items: center; gap: 8px; padding: 10px 16px; background: var(--paper); border: 1.5px solid var(--line); border-radius: 2px; box-shadow: var(--pop-sm); font-weight: 600; font-size: 14px; transition: transform 140ms var(--e-out), box-shadow 140ms var(--e-out); }
.btn:hover { transform: translate(-1px, -2px); box-shadow: var(--pop-hover); }
.btn:active { transform: translate(1px, 1px); box-shadow: 0 0 0 0 var(--line); }
.btn-primary { background: var(--olive); color: var(--olive-ink); border-color: var(--line); }
.btn-wine    { background: var(--wine);  color: var(--wine-ink); }
.btn-ghost   { background: transparent; box-shadow: none; border-color: transparent; }
.btn-ghost:hover { box-shadow: var(--pop-sm); background: var(--paper); border-color: var(--line); }

.section-header { display: flex; align-items: baseline; gap: 12px; max-width: 1200px; margin: 24px auto 14px; padding: 0 36px; }
.section-title { font-family: var(--font-display); font-size: 22px; font-weight: 700; letter-spacing: -0.01em; }
.section-count { font-size: 13px; color: var(--ink-3); font-family: var(--font-mono); }

.project-grid { max-width: 1200px; margin: 0 auto; padding: 0 36px 80px; display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 18px; }
.project-card { position: relative; background: var(--paper); border: 1.5px solid var(--line); border-radius: 2px; box-shadow: var(--pop); overflow: hidden; cursor: pointer; transition: transform 140ms var(--e-out), box-shadow 140ms var(--e-out); }
.project-card:hover { transform: translate(-1px, -3px); box-shadow: var(--pop-hover); }
.project-card:active { transform: translate(1px, 1px); box-shadow: var(--pop-sm); }
.project-cover { height: 120px; position: relative; border-bottom: 1.5px solid var(--line); display: grid; place-items: center; overflow: hidden; }
.project-cover::before { content: ''; position: absolute; inset: 0; background-image: radial-gradient(circle at 1px 1px, rgba(0,0,0,0.10) 1px, transparent 0); background-size: 14px 14px; opacity: 0.5; }
.project-emoji { font-size: 44px; filter: drop-shadow(2px 2px 0 rgba(0,0,0,0.12)); z-index: 1; }
.project-body { padding: 12px 15px; }
.project-title { font-family: var(--font-display); font-size: 16px; font-weight: 700; letter-spacing: -0.01em; margin-bottom: 3px; }
.project-meta { display: flex; align-items: center; gap: 7px; font-size: 12px; color: var(--ink-3); }
.project-meta .dot { width: 3px; height: 3px; border-radius: 50%; background: var(--ink-3); }

.project-card.new-card { display: grid; place-items: center; min-height: 200px; background: var(--paper-2); background-image: repeating-linear-gradient(45deg, transparent, transparent 8px, var(--line-softer) 8px, var(--line-softer) 16px); color: var(--ink-2); }
.project-card.new-card .new-inner { display: flex; flex-direction: column; align-items: center; gap: 10px; font-weight: 700; font-family: var(--font-display); }
.new-plus { width: 48px; height: 48px; border-radius: 2px; background: var(--ink); color: var(--bg); border: 1.5px solid var(--line); box-shadow: var(--pop-sm); display: grid; place-items: center; }

/* ============================================
   CANVAS — top bar
   ============================================ */
.app { height: 100%; display: flex; flex-direction: column; }
.topbar { display: flex; align-items: center; gap: 12px; padding: 8px 14px; background: var(--paper); border-bottom: 1.5px solid var(--line); z-index: 50; position: relative; }
/* ── Ruta: una pastilla con el sitio actual y el camino en un desplegable ──
   La cadena separada por "/" crecia con cada tablero anidado hasta comerse la
   barra de nodos y acabar cortada. Esto ocupa lo mismo con dos niveles que con
   diez, y el camino completo sigue a un clic. */
/* Flecha de subir un nivel: en escritorio es un boton discreto junto a la
   pastilla; en movil, el bloque de mas abajo la agranda para el dedo. */
.crumb-back {
  display: grid; place-items: center; flex: 0 0 auto;
  width: 30px; height: 30px; border-radius: 8px;
  color: var(--ink-2); transition: background 120ms, color 120ms;
}
.crumb-back:hover { background: var(--bg); color: var(--ink); }
.crumb-back .material-symbols-rounded { font-size: 19px; }
/* ── Migas de pan (Topbar.jsx, bloque .migas) ──
   Cada tablero del camino es un botón. Cada miga se encoge con puntos
   suspensivos antes de quitarle sitio a la barra de nodos; la actual se encoge
   la última. Con más de 4 niveles, los del medio se pliegan en un "…" que abre
   .migas__menu con el camino completo. */
.migas {
  --migas-ancho-miga: 180px;
  position: relative; display: flex; align-items: center; gap: 2px;
  /* No se encogen: la barra de nodos, que sí, tiene su deslizador. Encogiendo
     las dos, las migas se quedaban en "H… › Pru…". Su tope es max-width. */
  flex: 0 0 auto; min-width: 0; max-width: min(560px, 42vw);
}
.migas__miga {
  display: inline-flex; align-items: center; gap: 6px;
  min-width: 0; max-width: var(--migas-ancho-miga); flex: 0 1 auto;
  padding: 5px 8px; border-radius: 8px;
  font-weight: 600; font-size: 13px; color: var(--ink-2);
  transition: background 120ms, color 120ms;
}
button.migas__miga:hover { background: var(--bg); color: var(--ink); }
.migas__miga--actual { color: var(--ink); flex-shrink: 0.3; cursor: default; }
.migas__miga--plegadas { flex: 0 0 auto; padding: 5px 7px; letter-spacing: 1px; }
.migas__miga--abierta { background: var(--bg); color: var(--ink); }
.migas__sep { font-size: 16px; color: var(--ink-3); flex: 0 0 auto; }
.migas__texto { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.migas__casa { font-size: 16px; color: var(--ink-2); flex-shrink: 0; }
.migas__chip {
  width: 13px; height: 13px; border-radius: 3px; flex-shrink: 0;
  border: 1.5px solid var(--line); background: var(--chip-color, var(--paper));
}
.migas__fondo { position: fixed; inset: 0; z-index: 300; }
.migas__menu {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 301;
  min-width: 240px; max-width: 340px;
  background: var(--paper); border: 1.5px solid var(--line);
  border-radius: 10px; box-shadow: var(--pop-deep); padding: 6px;
  animation: fade-in 120ms var(--e-out);
}
.migas__menu-titulo {
  font-size: 10px; font-weight: 800; letter-spacing: 0.5px; text-transform: uppercase;
  color: var(--ink-3); padding: 4px 8px 6px;
}
.migas__menu-item {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 7px 8px 7px calc(10px + var(--nivel, 0) * 13px);
  border-radius: 6px; font-size: 13px; font-weight: 600;
  color: var(--ink-2); text-align: left; min-width: 0;
}
.migas__menu-item .migas__texto { flex: 1; }
.migas__menu-item:hover { background: var(--bg); color: var(--ink); }
.migas__menu-item--actual { color: var(--ink); background: color-mix(in srgb, var(--olive) 12%, transparent); }
.migas__aqui { font-size: 15px; color: var(--olive-texto); flex-shrink: 0; }

.topbar-spacer { flex: 1; }

/* Tamaños base COMPACTOS: se aplican en todas las resoluciones (incluidas >2K),
   para que la barra no se agrande ni se solape en pantallas grandes. Los
   breakpoints de abajo reducen aún más en pantallas pequeñas, pero NO son lo
   que evita el solape: eso lo hacen min-width:0 + overflow-x:auto de aquí
   abajo, así que no hay una anchura de ventana capaz de romperlo. Sin
   min-width:0 un elemento flex nunca se encoge por debajo de su contenido —
   por eso, en cualquier hueco entre el modo móvil (860px) y el primer
   breakpoint de escritorio, esta barra se salía de su sitio y tapaba las
   migas de pan de la izquierda, sin que importara la resolución del monitor. */
/* El contenedor es quien se encoge; la barra de dentro solo se desplaza. El
   deslizador cuelga debajo y solo existe cuando hay algo que desplazar. */
.tools-wrap {
  display: flex; flex-direction: column; align-items: stretch;
  flex: 0 1 auto; min-width: 0; gap: 3px;
}
.tools-slider {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 4px; margin: 0;
  background: var(--line-soft); border-radius: 999px; cursor: pointer;
}
.tools-slider::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 46px; height: 8px; margin-top: -2px;
  border-radius: 999px; background: var(--ink-3); border: none; cursor: grab;
}
.tools-slider::-webkit-slider-thumb:active { background: var(--olive); cursor: grabbing; }
.tools-slider::-moz-range-thumb {
  width: 46px; height: 8px; border-radius: 999px;
  background: var(--ink-3); border: none; cursor: grab;
}
.tools-slider:hover::-webkit-slider-thumb { background: var(--ink-2); }

.tools {
  display: flex; align-items: center; gap: 3px; background: var(--menu-fondo);
  border: 1.5px solid var(--line); border-radius: 8px; padding: 4px; box-shadow: var(--pop-sm);
  min-width: 0; max-width: 100%; overflow-x: auto; overflow-y: hidden; scrollbar-width: none;
}
.tools::-webkit-scrollbar { display: none; }
.tool { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 4px 7px; border-radius: 6px; transition: transform 120ms var(--e-out), background 100ms; }
.tool:hover { transform: translateY(-1px); background: var(--menu-hover); }
.tool .tool-icon { width: 31px; height: 31px; border-radius: 8px; display: grid; place-items: center; border: 1.5px solid var(--line); box-shadow: var(--pop-sm); color: var(--icono-fg, var(--ink)); background: var(--icono-bg, var(--tool-bg)); transition: transform 100ms var(--e-out); }
/* nowrap: en japonés o chino no hay espacios, y sin esto «ドキュメント» se partía
   letra a letra en tres líneas y la barra crecía de 65 a 102 px. La tira ya se
   desplaza de lado si no cabe. */
.tool .tool-label { font-size: 11px; font-weight: 600; letter-spacing: -0.01em; color: var(--ink-2); white-space: nowrap; }
/* El grupo elige el fondo; la tinta es fija porque los fondos son claros en
   los dos temas. .tool.active (abajo) gana y pinta el verde de seleccion. */
.tool-icon--escribir,   .hoja-nodo-icono--escribir   { --icono-bg: var(--tool-escribir-bg);   --icono-fg: var(--tool-fg); }
.tool-icon--medios,     .hoja-nodo-icono--medios     { --icono-bg: var(--tool-medios-bg);     --icono-fg: var(--tool-fg); }
.tool-icon--estructura, .hoja-nodo-icono--estructura { --icono-bg: var(--tool-estructura-bg); --icono-fg: var(--tool-fg); }
.tool-icon--trazos,     .hoja-nodo-icono--trazos     { --icono-bg: var(--tool-trazos-bg);     --icono-fg: var(--tool-fg); }
.tool.active .tool-icon { background: var(--olive); color: var(--olive-ink); transform: scale(1.05); border-color: var(--line); }
.tool.active { background: color-mix(in srgb, var(--olive) 14%, transparent); }
.tool.active .tool-label { color: var(--ink); }
.tool .material-symbols-rounded { font-size: 19px; }
.tool-divider { width: 1.5px; height: 32px; background: var(--line-soft); margin: 0 3px; }

.topbar-actions { display: flex; align-items: center; gap: 5px; flex-shrink: 0; }
.icon-btn { width: 38px; height: 38px; border-radius: 8px; display: grid; place-items: center; border: 1.5px solid var(--line); background: var(--paper); box-shadow: var(--pop-sm); transition: transform 140ms var(--e-out), box-shadow 140ms var(--e-out); }
.icon-btn:hover { transform: translate(-1px, -1px); box-shadow: var(--pop-hover); }
.icon-btn .material-symbols-rounded { font-size: 22px; }
.avatar { width: 32px; height: 32px; border-radius: 50%; border: 1.5px solid var(--line); background: var(--olive); color: var(--olive-ink); display: grid; place-items: center; font-weight: 700; font-family: var(--font-display); font-size: 12px; box-shadow: var(--pop-sm); }
.lang-switch {
  display: inline-flex;
  height: 42px;
  width: 58px;
  border: 1.5px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
  background: var(--paper);
  box-shadow: var(--pop-sm);
  font-size: 12px;
  font-weight: 700;
  position: relative;
  align-items: center;
  justify-content: center;
  transition: transform 140ms var(--e-out), box-shadow 140ms var(--e-out);
}
.lang-switch:hover {
  transform: translate(-1px, -1px);
  box-shadow: var(--pop-hover);
}
.lang-select {
  padding: 0 16px 0 6px;
  width: 100%;
  height: 100%;
  font-family: inherit;
  font-size: inherit;
  font-weight: inherit;
  color: var(--ink);
  background: transparent;
  border: none;
  outline: none;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  text-align: center;
  text-align-last: center;
}
.lang-select option {
  background: var(--paper);
  color: var(--ink);
}
.lang-switch::after {
  content: '▼';
  font-size: 7px;
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  pointer-events: none;
  color: var(--ink-3);
}
.theme-btn .material-symbols-rounded { transition: transform 200ms var(--e-out); }

/* ── Volumen: un cuadrado, no un rectangulo ──

   Era el unico control de la barra con otra forma, porque llevaba el
   deslizador pegado al lado y eso lo hacia el doble de ancho que sus vecinos.
   Ahora ocupa un cuadrado igual que los demas y el deslizador aparece flotando
   debajo al acercar el raton.

   Y de paso arregla algo peor que la forma: por debajo de 1200 px el
   deslizador se escondia ENTERO porque no cabia a lo ancho, o sea que en una
   ventana estrecha no habia manera de bajar el volumen, solo de silenciarlo.
   Flotando no ocupa ancho, asi que ya no hay que esconderlo nunca. */
.volume-ctrl {
  position: relative;
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  padding: 0;
  gap: 0;
  background: var(--paper);
  border: 1.5px solid var(--line);
  border-radius: 8px;
  box-shadow: var(--pop-sm);
  transition: transform 140ms var(--e-out), box-shadow 140ms var(--e-out);
}

/* El puente invisible entre el boton y el deslizador. Sin el, al bajar el raton
   se pierde el hover en el hueco de 10 px y el panel se cierra en las narices
   justo cuando ibas a tocarlo. */
.volume-ctrl::after {
  content: "";
  position: absolute;
  top: 100%;
  left: -8px;
  right: -8px;
  height: 14px;
}
.volume-ctrl:hover {
  transform: translate(-1px, -1px);
  box-shadow: var(--pop-hover);
}
.volume-ctrl .icon-btn-mute {
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  cursor: pointer;
  color: var(--ink);
  transition: transform 100ms;
}
.volume-ctrl .icon-btn-mute:active {
  transform: scale(0.95);
}
.volume-ctrl .volume-slider {
  -webkit-appearance: none;
  appearance: none;
  position: absolute;
  top: calc(100% + 10px);
  left: 50%;
  width: 124px;
  height: 34px;
  margin: 0;
  padding: 0 12px;
  background: var(--paper);
  border: 1.5px solid var(--line);
  border-radius: 8px;
  box-shadow: var(--pop);
  outline: none;
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transform: translateX(-50%) translateY(-4px);
  transition: opacity 130ms var(--e-out), transform 130ms var(--e-out), visibility 130ms;
  z-index: 70;
}

/* Con el foco tambien, no solo con el raton: quien llega con el teclado tiene
   que poder ver lo que esta moviendo. */
.volume-ctrl:hover .volume-slider,
.volume-ctrl:focus-within .volume-slider {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
}

/* Al pasar a panel, el fondo del control ya no es la barra: hay que pintar la
   barra aparte dentro de el. */
.volume-ctrl .volume-slider::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 99px;
  background: var(--line-soft);
}
.volume-ctrl .volume-slider::-moz-range-track {
  height: 4px;
  border-radius: 99px;
  background: var(--line-soft);
}
.volume-ctrl .volume-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  margin-top: -4px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--wine, #7B2D26);
  border: 1.5px solid white;
  box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}

/* ============================================
   CANVAS surface
   ============================================ */
.canvas-wrap {
  flex: 1; position: relative;
  /* clip, no hidden. Con overflow:hidden el contenedor SIGUE siendo
     desplazable por dentro: el navegador lo desplaza por su cuenta cuando algo
     de dentro recibe el foco, para traerlo a la vista, y no lo devuelve. Como
     todo lo colocado dentro se mueve con el, la barra de busqueda y la paleta
     se salian de la pantalla por la izquierda mientras el rail (fixed) se
     quedaba en su sitio. Habia una red de seguridad que lo devolvia a cero,
     pero el navegador volvia a desplazarlo y ganaba el.
     Con clip el contenedor deja de ser desplazable y no hay pelea. Medido en un
     telefono: con hidden, scrollLeft=200 se quedaba y la barra iba a x=-192;
     con clip, scrollLeft se queda en 0 y la barra en x=8.
     El hidden de delante es para los WebView viejos que no entienden clip. */
  overflow: hidden;
  overflow: clip;
  background-color: var(--bg);
  /* Tiny triangle grid (distinct from Milanote's dot grid) */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='22' height='22'%3E%3Cpath d='M11 9.5L12.6 12.3H9.4Z' fill='%231A1A1A' fill-opacity='0.13'/%3E%3C/svg%3E");
  background-size: 22px 22px;
}
.canvas-wrap.canvas-bg-default { background-color: var(--bg); }
.canvas-wrap.canvas-bg-gray { background-color: #ECEAE6; }
.canvas-wrap.canvas-bg-sand { background-color: #F4EFE6; }
.canvas-wrap.canvas-bg-mint { background-color: #EAF2EB; }
.canvas-wrap.canvas-bg-sky { background-color: #E6F0FA; }
.canvas-wrap.canvas-bg-pink { background-color: #FAEBEF; }

[data-theme="dark"] .canvas-wrap.canvas-bg-default { background-color: #2A282A; }
[data-theme="dark"] .canvas-wrap.canvas-bg-gray { background-color: #1E1C1E; }
[data-theme="dark"] .canvas-wrap.canvas-bg-sand { background-color: #38322B; }
[data-theme="dark"] .canvas-wrap.canvas-bg-mint { background-color: #25332A; }
[data-theme="dark"] .canvas-wrap.canvas-bg-sky { background-color: #232F3D; }
[data-theme="dark"] .canvas-wrap.canvas-bg-pink { background-color: #3A232F; }
/* Sin cuadrícula (Canvas.jsx, por tablero desde el clic derecho). */
.canvas-wrap.canvas-wrap--sin-cuadricula { background-image: none; }

.canvas-surface { position: absolute; transform-origin: 0 0; }
.canvas-surface, .item-card {
  -webkit-font-smoothing: antialiased;
  text-rendering: geometricPrecision;
}
.canvas-content { position: absolute; top: 0; left: 0; width: 1px; height: 1px; transform-origin: 0 0; }
.canvas-wrap.placing { cursor: crosshair; }

/* Con una herramienta armada, los tiradores de tamano y los enganches de los
   nodos dejan de recibir clics.

   Sin esto basta con que uno quede debajo del cursor para que se trague el clic
   y el nodo nuevo no se coloque nunca. Y no es raro: los tiradores de un dibujo
   grande estan repartidos por media pantalla y son invisibles, asi que el
   lienzo parece muerto sin que nada explique por que.

   Los enganches se quedan vivos al tirar una linea, que es justo cuando hacen
   falta. */
.canvas-wrap.placing .handle,
.canvas-wrap.placing .anchor,
/* Espacio pulsado: mano abierta, y cerrada mientras se arrastra. El cursor va
   con !important porque cada nodo trae el suyo (texto, mover, redimensionar) y
   si no, la mano solo se vería sobre el hueco vacío del lienzo. */
.canvas-wrap.con-espacio, .canvas-wrap.con-espacio * { cursor: grab !important; }
.canvas-wrap.paneando, .canvas-wrap.paneando * { cursor: grabbing !important; }

.canvas-wrap.linking .handle {
  pointer-events: none;
}
.canvas-wrap.placing .item { pointer-events: none; }
.canvas-wrap.linking { cursor: crosshair; }

/* Zoom controls */
/* ── La cámara del lienzo ── */
/* Con .icon-btn delante a propósito: las reglas que encogen los botones de
   arriba en pantallas de menos de 1920 (36-39 px) son de .icon-btn y van más
   abajo en este archivo, así que le ganaban a esta y la cámara salía más
   grande que sus vecinos de 32 px en cuanto la ventana no era enorme (lo vio
   el usuario con la ventana pequeña). */
.icon-btn.canvas-shot {
  position: absolute;
  bottom: 16px;
  right: 205px;
  width: 32px;
  height: 32px;
  border-radius: 2px;
  z-index: 40;
}

/* ── El fogonazo ──

   Al disparar, el lienzo se apaga un instante y los bordes se encienden en
   blanco, hacia dentro. Es el mismo velo oscuro que usa el modo dibujo, y a
   proposito: ya se sabe lo que significa —"esto de aqui es lo que importa
   ahora"— y no hace falta aprenderlo dos veces.

   Entre pulsar y ver la ventana de guardar pasa casi un segundo, y sin nada en
   medio parece que el boton no ha hecho nada y se vuelve a pulsar.

   No recibe clics, para no comerse el que venga detras. Y se apaga ANTES de
   disparar, o saldria en la foto. */
.canvas-fogonazo {
  position: absolute;
  inset: 0;
  z-index: 45;
  pointer-events: none;
  border-radius: inherit;
  animation: canvas-fogonazo 420ms ease-out forwards;
}

@keyframes canvas-fogonazo {
  0% {
    background: rgba(10, 10, 12, 0);
    box-shadow: inset 0 0 0 0 rgba(255, 255, 255, 0);
  }
  30% {
    /* El velo y el borde llegan juntos. El halo entra 150px hacia el centro:
       lo bastante para que se lea como un marco y no como una linea. */
    background: rgba(10, 10, 12, 0.42);
    box-shadow: inset 0 0 150px 26px rgba(255, 255, 255, 0.92);
  }
  55% {
    background: rgba(10, 10, 12, 0.34);
    box-shadow: inset 0 0 120px 18px rgba(255, 255, 255, 0.6);
  }
  100% {
    background: rgba(10, 10, 12, 0);
    box-shadow: inset 0 0 0 0 rgba(255, 255, 255, 0);
  }
}
@media (prefers-reduced-motion: reduce) {
  .canvas-fogonazo { animation-duration: 1ms; }
}


.zoom-ctrls { position: absolute; bottom: 16px; right: 16px; display: flex; background: var(--paper); border: 1.5px solid var(--line); border-radius: 2px; box-shadow: var(--pop-sm); overflow: hidden; z-index: 40; }
.zoom-ctrls button { padding: 6px 10px; font-size: 12.5px; font-weight: 600; border-right: 1.5px solid var(--line); display: grid; place-items: center; transition: background 100ms; }
.zoom-ctrls button:last-child { border-right: none; }
.zoom-ctrls button:hover { background: var(--bg); }
.zoom-level { min-width: 48px; font-family: var(--font-mono); font-size: 11.5px; }

/* Mini search */
.mini-search { position: absolute; top: 14px; left: 50%; transform: translateX(-50%); display: flex; align-items: center; gap: 8px; background: var(--paper); border: 1.5px solid var(--line); border-radius: 2px; box-shadow: var(--pop-sm); padding: 6px 11px; width: 280px; z-index: 40; }
.mini-search input { flex: 1; font-size: 13px; }
.mini-search kbd { font-family: var(--font-mono); font-size: 11px; padding: 1px 5px; background: var(--bg); border: 1px solid var(--line-soft); border-radius: 2px; }

/* Place hint */
.place-hint { position: absolute; top: 56px; left: 50%; transform: translateX(-50%); background: var(--ink); color: var(--bg); padding: 7px 13px; font-size: 12.5px; font-weight: 600; border-radius: 2px; box-shadow: var(--pop-sm); z-index: 41; display: flex; align-items: center; gap: 8px; border: 1.5px solid var(--line); }
.place-hint .esc { font-family: var(--font-mono); font-size: 10px; padding: 1px 5px; background: rgba(255,255,255,0.15); border-radius: 2px; }
/* La misma pastilla, pero pulsable: con el dedo no hay tecla esc que valga y
   la única salida era acertarle a la X del raíl. */
.place-hint .esc.como-boton {
  font-family: inherit; font-weight: 700; font-size: 11px;
  padding: 4px 10px; border: 0; border-radius: 999px;
  background: rgba(255,255,255,0.22); color: inherit;
  cursor: pointer; margin-left: 2px;
}
.place-hint .esc.como-boton:active { background: rgba(255,255,255,0.35); }

/* Drag-create preview rectangle */
.drag-preview { position: absolute; border: 1.5px dashed var(--olive); background: color-mix(in srgb, var(--olive) 8%, transparent); border-radius: 2px; pointer-events: none; z-index: 50; }

/* Marquee selection rectangle */
.marquee-rect {
  position: absolute;
  border: 1px solid var(--olive);
  background: color-mix(in srgb, var(--olive) 12%, transparent);
  pointer-events: none;
  z-index: 55;
}

/* Pending line preview */
.connector-preview { position: absolute; pointer-events: none; z-index: 50; }

/* ============================================
   ITEMS
   ============================================ */
.item { position: absolute; user-select: none; }
.item.dragging { z-index: 999 !important; cursor: grabbing; }
.item.dragging .item-card { transform: rotate(0.8deg) scale(1.015); box-shadow: var(--pop-deep); transition: none; }
.item-card { border: 1.5px solid var(--line); border-radius: 2px; box-shadow: var(--pop); background: var(--paper); overflow: hidden; cursor: grab; transition: transform 130ms var(--e-out), box-shadow 130ms var(--e-out); position: relative; height: 100%; }
.item:hover .item-card { transform: translate(-1px, -2px); box-shadow: var(--pop-hover); }
.item.selected .item-card { outline: 2px solid var(--olive); outline-offset: 2px; }
.item.drop-target .item-card { outline: 2px dashed var(--wine); outline-offset: 4px; }
.item.editing .item-card { cursor: text; }

/* Node-first editing: until a node is selected (or already in edit mode), its entire card is inert
   so a first click selects/drags the whole node, and subsequent clicks allow editing or interaction. */
.item:not(.selected):not(.editing) .item-card { pointer-events: none; }
/* Allow pointer events for drop targets when dragging a task row */
body.dragging-task .item-card { pointer-events: auto !important; }
/* …but columns and their nested children must keep their own drag & click interactions.
   (The nested children each render their OWN .item-card, which the rule above would also
   make inert — so we explicitly re-enable pointer events for everything inside a column body.) */
.item:not(.selected):not(.editing) .column-body,
.item:not(.selected):not(.editing) .column-body .item-card,
.item:not(.selected):not(.editing) .column-body * { pointer-events: auto; }

/* Anchor points (appear on hover) */
.anchors { position: absolute; inset: -1px; pointer-events: none; }
.anchor { position: absolute; width: 12px; height: 12px; border-radius: 50%; background: var(--olive); border: 2px solid var(--paper); box-shadow: 0 0 0 1.5px var(--line); pointer-events: auto; cursor: crosshair; opacity: 0; transform: scale(0.6); transition: opacity 140ms var(--e-out), transform 140ms var(--e-out); }
.item:hover .anchor, .item.selected .anchor { opacity: 1; transform: scale(1); }
.anchor:hover { background: var(--wine); transform: scale(1.25); }
.anchor.top    { top: -6px;    left: 50%;  margin-left: -6px; }
.anchor.right  { right: -6px;  top: 50%;   margin-top: -6px; }
.anchor.bottom { bottom: -6px; left: 50%;  margin-left: -6px; }
.anchor.left   { left: -6px;   top: 50%;   margin-top: -6px; }

/* Single Milanote-style connection handle (one point, connects to the node center).
   Placed at the right-center edge so it never collides with the corner resize handles. */
.connect-handle {
  position: absolute; right: -11px; top: 50%; margin-top: -11px;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--paper); border: 1.5px solid var(--olive);
  box-shadow: var(--pop-sm);
  display: grid; place-items: center;
  pointer-events: auto; cursor: crosshair;
  /* Escondido NO lee el zoom: cada paso del zoom cambia --handle-scale, y con
     la transición de transform arrancaba 2.000 animaciones invisibles en un
     lienzo de 500 nodos (el 90 % del coste del zoom, medido). Lo lee al verse. */
  opacity: 0; transform: scale(0.7);
  transition: opacity 130ms var(--e-out), transform 130ms var(--e-out), background 100ms;
  z-index: 6;
  transform-origin: center;
}
/* Solo el handle PROPIO del elemento sobre el que está el cursor: con el selector
   descendiente anterior, pasar sobre una columna encendía a la vez su handle y el
   de TODAS sus tarjetas hijas (anillos superpuestos) */
.item:hover > .anchors > .connect-handle,
.col-child-wrap:hover > .anchors > .connect-handle { opacity: 1; transform: scale(calc(1 * var(--handle-scale, 1))); }
/* Dentro de una columna: al pasar sobre una tarjeta hija se esconde el conector
   de la columna y solo queda el de la tarjeta hija */
.item:has(.col-child-wrap:hover) > .anchors > .connect-handle { opacity: 0 !important; pointer-events: none !important; }

/* Cuatro puntos de conexión estilo Miro: arriba, derecha, abajo e izquierda
   (la base .connect-handle ya posiciona el derecho) */
.connect-handle.pos-top    { right: auto; left: 50%; top: -11px; margin-top: 0; margin-left: -11px; }
.connect-handle.pos-bottom { right: auto; left: 50%; top: auto; bottom: -11px; margin-top: 0; margin-left: -11px; }
.connect-handle.pos-left   { right: auto; left: -11px; }
.connect-handle:hover { background: var(--olive); transform: scale(calc(1.15 * var(--handle-scale, 1))); }
.connect-handle .material-symbols-rounded { font-size: 16px; color: var(--olive-texto); }
.connect-handle:hover .material-symbols-rounded { color: #fff; }

/* Note */
.note { padding: 0; font-size: calc(13.5px * var(--node-scale, 1) * var(--vista-escala, var(--text-scale, 1))); line-height: 1.45; }
.note-inner { width: 100%; height: 100%; padding: calc(10px * var(--node-scale, 1)) calc(12px * var(--node-scale, 1)); font-family: var(--fuente-nodo, var(--font-body)); color: var(--ink); overflow: hidden; white-space: pre-wrap; word-break: break-word; }
.note-edit { width: 100%; height: 100%; padding: calc(10px * var(--node-scale, 1)) calc(12px * var(--node-scale, 1)); font-size: calc(13.5px * var(--node-scale, 1) * var(--vista-escala, var(--text-scale, 1))); line-height: 1.45; background: transparent; overflow-wrap: break-word; word-break: break-word; }
.note.c-white .item-card  { background: var(--c-white); }
.note.c-cream .item-card  { background: var(--c-cream); }
.note.c-sage  .item-card  { background: var(--c-sage); }
.note.c-rose  .item-card  { background: var(--c-rose); }
.note.c-stone .item-card  { background: var(--c-stone); }
.note.c-mist  .item-card  { background: var(--c-mist); }
.note.c-olive .item-card  { background: var(--c-olive); color: white; }
.note.c-wine  .item-card  { background: var(--c-wine);  color: white; }
/* Nota sin fondo (.note--sin-fondo): texto flotando, como los títulos. Sin
   fondo, borde ni sombra; al pasar por encima o seleccionada, un discontinuo
   suave para saber dónde está. */
.note--sin-fondo .item-card,
.item:hover .note--sin-fondo .item-card {
  background: transparent; color: var(--ink);
  border: 1px dashed transparent; box-shadow: none; transform: none;
}
.item:hover .note--sin-fondo .item-card,
.item.selected .note--sin-fondo .item-card { border-color: var(--line-soft); }

/* Image */
.image-card .item-card {
  padding: 0 !important;
  background-color: transparent !important;
  border: none !important;
  box-shadow: none !important;
  border-radius: 0 !important;
}
.image-card.empty .item-card {
  background-color: var(--paper) !important;
  border: 1.5px dashed var(--line-soft) !important;
  border-radius: 2px !important;
}
.image-card .image-frame {
  height: 100%; width: 100%;
  background-color: transparent !important;
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  position: relative;
  overflow: hidden;
  border-radius: 0;
}
/* Disable pointer events on iframes during active resize/drag so mouseup reaches the canvas */
body.odi-busy iframe { pointer-events: none !important; }
.image-card .image-caption { position: absolute; bottom: 5px; left: 5px; right: 5px; padding: 4px 8px; background: color-mix(in srgb, var(--paper) 92%, transparent); border-radius: 2px; font-size: 11px; font-weight: 600; backdrop-filter: blur(4px); }
.image-empty { display: grid; place-items: center; height: 100%; color: var(--ink-3); flex-direction: column; gap: 6px; cursor: pointer; }
.image-empty .material-symbols-rounded { font-size: 30px; }
.image-empty:hover { color: var(--olive-texto); background: var(--olive-l); }
/* Node-first: until the image node is selected, the empty dropzone is inert so a first
   click selects/drags the node; once selected, clicking it opens the file picker. */
.item:not(.selected) .image-empty { pointer-events: none; }

/* Link */
.link-card .item-card { display: flex; flex-direction: column; padding: 0; }
.link-card.empty .item-card { padding: 12px; display: flex; flex-direction: column; align-items: stretch; justify-content: flex-start; gap: 6px; }
.link-edit-row {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 9px 11px;
  border: 1.5px solid var(--line-soft);
  border-radius: 4px;
  background: var(--paper);
}
.link-edit-row:focus-within { border-color: var(--olive); box-shadow: 0 0 0 2px var(--olive-l); }
.link-card.empty .link-input { flex: 1; font-size: calc(13px * var(--node-scale, 1)); padding: 0; min-width: 0; }
.link-edit-hint { font-size: calc(10px * var(--node-scale, 1)); color: var(--ink-3); font-style: italic; padding-left: 2px; }
.link-card .link-prefix { color: var(--ink-3); display: flex; align-items: center; flex-shrink: 0; }
.link-thumb { flex: 1 1 auto; min-height: 50%; background: var(--olive-l); display: grid; place-items: center; border-bottom: 1.5px solid var(--line); position: relative; background-size: cover; background-position: center; cursor: pointer; }
.link-thumb .material-symbols-rounded { font-size: 36px; color: var(--ink); }
.link-thumb-placeholder { display: grid; place-items: center; gap: 8px; position: relative; }
.link-thumb-favicon { width: calc(40px * var(--node-scale, 1)); height: calc(40px * var(--node-scale, 1)); opacity: 0.85; border-radius: 4px; }
.link-thumb-spinner {
  width: 22px; height: 22px;
  border: 2.5px solid var(--line-soft);
  border-top-color: var(--olive);
  border-radius: 50%;
  animation: link-spin 700ms linear infinite;
}
@keyframes link-spin { to { transform: rotate(360deg); } }
.link-thumb .play-icon { position: absolute; inset: 0; display: grid; place-items: center; background: rgba(0,0,0,0.25); }
.link-thumb .play-icon .material-symbols-rounded { color: white; font-size: 44px; filter: drop-shadow(0 2px 4px rgba(0,0,0,0.5)); }
.link-play-btn {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 56px; height: 56px; border-radius: 50%;
  background: rgba(0,0,0,0.65); border: none;
  display: grid; place-items: center;
  cursor: pointer; transition: transform 120ms, background 120ms;
  z-index: 2;
}
.link-play-btn:hover { background: rgba(0,0,0,0.85); transform: translate(-50%, -50%) scale(1.08); }
.link-play-btn .material-symbols-rounded { color: white; font-size: 32px; }
.link-play-btn { z-index: 2; }
.link-body { padding: 8px 11px; flex: 0 0 auto; display: flex; flex-direction: column; gap: 3px; justify-content: center; }
.link-host { display: flex; align-items: center; gap: 5px; font-family: var(--font-mono); font-size: calc(10px * var(--node-scale, 1)); color: var(--ink-3); }
.link-host img { width: calc(12px * var(--node-scale, 1)); height: calc(12px * var(--node-scale, 1)); }
.link-host span { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.link-open-btn { flex-shrink: 0; width: 22px; height: 22px; display: grid; place-items: center; background: transparent; border: none; cursor: pointer; color: var(--ink-3); border-radius: 2px; padding: 0; }
.link-open-btn:hover { background: var(--olive-l); color: var(--olive-texto); }
.link-open-btn .material-symbols-rounded { font-size: calc(15px * var(--node-scale, 1)); }
.link-title-input { font-weight: 700; font-size: calc(13px * var(--node-scale, 1)); line-height: 1.3; background: transparent; border: none; width: 100%; color: inherit; padding: 0; overflow-wrap: break-word; word-break: break-word; }
.link-title-input::placeholder { color: var(--ink-3); font-weight: 600; }
.link-caption-input { margin-top: 2px; color: var(--wine-texto); font-weight: 600; font-size: calc(12px * var(--node-scale, 1)); line-height: 1.3; background: transparent; border: none; width: 100%; resize: none; font-family: var(--font-body); padding: 0; }
.link-caption-input::placeholder { color: var(--ink-3); font-weight: 400; font-style: italic; }
.link-desc { font-size: calc(11px * var(--node-scale, 1)); color: var(--ink-3); line-height: 1.25; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

/* ── Captions / "leyendas" (shared rich contentEditable) ──
   Always styled like a heading (H1). Font size is FIXED (not node-scaled) so that
   auto-growing the node height can't feed back into the caption height. */
/* ── Muelle, al estilo del iPhone ──
   La curva de las animaciones nuevas: se pasa un poco de largo y vuelve, que es
   lo que hace que un movimiento parezca físico y no mecánico. Los nodos nuevos
   la estrenan; la 1.2 la llevará al resto de la aplicación. */
:root {
  --muelle: cubic-bezier(0.34, 1.56, 0.64, 1);
  --muelle-suave: cubic-bezier(0.22, 1.25, 0.36, 1);
}

/* ── Carpeta ──
   Dibujada con las reglas del resto de la aplicación, no con las de otro
   sistema: colores planos, el borde de 1,5 px en el color de las líneas, la
   sombra dura desplazada (sin difuminar) y esquinas casi rectas. La primera
   versión llevaba degradados, sombras suaves y cristal esmerilado, y el
   usuario vio enseguida que parecía "algo aparte" (lo era: era la estética de
   macOS).

   En reposo es una carpeta cerrada: opaca y sin nada asomando. Al pasar el
   ratón la delantera se vuelve medio transparente —más en el medio— y las
   hojas salen en abanico con rebote. Lo pidió así el usuario: la transparencia
   y las hojas son el EFECTO del ratón; tenerlas siempre puestas las gastaba. */
.carpeta {
  /* La letra del nombre: 15 px por el tamaño elegido en la barra (o por el que
     se está previsualizando). La cuenta y el hueco que el dibujo deja debajo
     salen de ella, para que un nombre grande no se salga del nodo. */
  --carpeta-letra: calc(15px * var(--vista-escala, var(--text-scale, 1)));
  width: 100%; height: 100%;
  container-type: size;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 7px; padding: 12px 8px 8px;
  cursor: pointer; user-select: none;
}
.carpeta-dibujo {
  position: relative;
  /* Lo más grande que quepa, dejando sitio debajo para el nombre y la cuenta. */
  width: min(86cqw, calc((100cqh - 46px - var(--carpeta-letra) * 1.6) * 1.3));
  aspect-ratio: 1.3 / 1;
  flex: 0 0 auto;
  font-size: min(4.2cqw, 16px);
  perspective: 700px;
  /* Las hojas son papel y la carpeta es amarilla en los dos temas: en el
     oscuro, las hojas salían gris oscuro sobre el amarillo. Se clavan aquí los
     valores del tema claro, como en las tarjetas de comentario. */
  --paper: #FAF9F6; --paper-2: #F3F2EE; --ink-2: #595459; --ink-3: #8E8A8E;
}
.carpeta-trasera {
  position: absolute; left: 0; right: 0; top: 10%; bottom: 0;
  border: 1.5px solid var(--line); border-radius: 4px;
  background: color-mix(in srgb, var(--carpeta) 78%, var(--line));
  box-shadow: var(--pop);
}
/* La pestaña, del mismo trazo. */
.carpeta-trasera::before {
  content: ''; position: absolute; left: -1.5px; top: -12%;
  width: 38%; height: 13%;
  border: 1.5px solid var(--line); border-bottom: 0;
  border-radius: 4px 4px 0 0;
  background: inherit;
}
.carpeta-hojas { position: absolute; left: 9%; right: 9%; top: 0; bottom: 28%; }
/* Cada hoja, una tarjetita como las del lienzo: papel, borde y sombra dura.
   En reposo están metidas del todo detrás de la delantera. */
.carpeta-hoja {
  position: absolute; top: 5%;
  width: 36%; aspect-ratio: 3 / 3.7;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  overflow: hidden;
  padding: 5%;
  border: 1.5px solid var(--line); border-radius: 2px;
  background: var(--paper);
  box-shadow: var(--pop-sm);
  transition: transform 520ms var(--muelle);
}
.carpeta-hoja img {
  width: 100%; height: 100%; object-fit: cover; pointer-events: none;
  border-radius: 1px;
}
.carpeta-hoja .material-symbols-rounded { font-size: 2em; color: var(--ink-2); }
.carpeta-hoja-ext {
  font-family: var(--font-mono); font-size: 0.62em; font-weight: 700;
  letter-spacing: 0.04em; color: var(--ink-3);
}
.carpeta-hoja.tipo-carpeta .material-symbols-rounded { color: color-mix(in srgb, var(--carpeta) 70%, var(--line)); }
.carpeta-hoja.tipo-pdf .material-symbols-rounded { color: var(--wine-texto); }
.carpeta-hoja.hueca { background: var(--paper-2); box-shadow: none; }
.carpeta-hoja.h0 { left: 0%;  transform: translateY(64%) rotate(-3deg); }
.carpeta-hoja.h1 { left: 32%; transform: translateY(62%); z-index: 1; }
.carpeta-hoja.h2 { left: 64%; transform: translateY(64%) rotate(3deg); }
.carpeta-delantera {
  position: absolute; left: 0; right: 0; top: 30%; bottom: 0;
  display: grid; place-items: center;
  border: 1.5px solid var(--line); border-radius: 4px;
  /* El color de fondo es el que cambia: entero en reposo, y al pasar el ratón
     casi transparente. El degradado de encima tiñe más los bordes que el
     medio, así que lo de dentro se ve sobre todo por el centro, borroso. */
  background-color: var(--carpeta);
  background-image: radial-gradient(ellipse 62% 58% at 50% 45%,
    transparent,
    color-mix(in srgb, var(--carpeta) 80%, transparent) 78%);
  -webkit-backdrop-filter: blur(0px) saturate(1);
  backdrop-filter: blur(0px) saturate(1);
  box-shadow: var(--pop);
  transform-origin: 50% 100%;
  transition: transform 520ms var(--muelle), box-shadow 200ms,
    background-color 380ms ease, backdrop-filter 380ms ease, -webkit-backdrop-filter 380ms ease;
  z-index: 2;
}
/* Las dos rayas de abajo, como las de una carpeta de cartón. */
.carpeta-delantera::before, .carpeta-delantera::after {
  content: ''; position: absolute; left: 14%; right: 14%; height: 1.5px;
  background: var(--line); opacity: 0.35;
}
.carpeta-delantera::before { bottom: 15%; }
.carpeta-delantera::after { bottom: 9%; }
.item:hover .carpeta-hoja.h0 { transform: translate(-14%, -30%) rotate(-14deg); }
.item:hover .carpeta-hoja.h1 { transform: translateY(-42%); transition-delay: 40ms; }
.item:hover .carpeta-hoja.h2 { transform: translate(14%, -30%) rotate(14deg); transition-delay: 80ms; }
.item:hover .carpeta-delantera {
  transform: rotateX(-14deg) translateY(1.5%);
  box-shadow: var(--pop-hover);
  background-color: color-mix(in srgb, var(--carpeta) 42%, transparent);
  -webkit-backdrop-filter: blur(8px) saturate(1.25);
  backdrop-filter: blur(8px) saturate(1.25);
}
.carpeta-nombre {
  max-width: 100%;
  font-family: var(--font-display); font-weight: 800; font-size: var(--carpeta-letra);
  letter-spacing: -0.01em; line-height: 1.2;
  color: var(--carpeta-tinta, var(--ink));
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  cursor: text;
}
/* Escribiendo el nombre: el mismo tamaño y la misma letra, en su campo. */
.carpeta-nombre-campo {
  width: 100%; max-width: 100%;
  padding: 0.07em 0.4em;
  border: 1.5px solid var(--olive); border-radius: 2px;
  background: var(--paper);
  font-family: var(--font-display); font-weight: 800; font-size: var(--carpeta-letra);
  letter-spacing: -0.01em; line-height: 1.2;
  color: var(--carpeta-tinta, var(--ink));
  text-align: center;
}
/* La cuenta, con la letra de los datos de la aplicación (la de ancho fijo). Crece
   con el nombre pero más despacio: a la par, con el nombre a 36 la cuenta
   pasaba a 24 y le quitaba el protagonismo. */
.carpeta-cuenta {
  padding: 0.2em 0.8em;
  border: 1.5px solid var(--line-soft); border-radius: 2px;
  color: var(--ink-3);
  font-family: var(--font-mono); font-size: calc(6px + var(--carpeta-letra) * 0.27); font-weight: 700;
  letter-spacing: 0.03em; text-transform: uppercase;
  white-space: nowrap;
}
.carpeta.vacia .carpeta-trasera, .carpeta.perdida .carpeta-trasera { opacity: 0.6; }
.carpeta-elegir {
  position: relative; z-index: 1;
  display: inline-flex; align-items: center; gap: 5px;
  padding: 6px 11px;
  border: 1.5px solid var(--line); border-radius: 2px;
  background: var(--olive); color: #1A1A1A;
  box-shadow: var(--pop-sm);
  font-size: 12px; font-weight: 700; cursor: pointer;
  transition: transform 220ms var(--muelle), box-shadow 150ms;
}
.carpeta-elegir:hover { transform: translate(-1px, -1px); box-shadow: var(--pop); }
.carpeta-elegir .material-symbols-rounded { font-size: 16px; }

/* ── Ruleta ──
   Todo lo que va escrito dentro crece con la rueda, como una imagen: las
   medidas van en cqw (centésimas del ancho de la rueda) y sin tope. Antes
   llevaban un máximo de 18-22 px, y en una ruleta grande el "Girar" y los
   avisos se quedaban diminutos en medio del círculo. Aquí no hay botón de
   tamaño de letra a propósito: lo pidió así el usuario. */
.ruleta {
  width: 100%; height: 100%;
  display: grid; place-items: center;
  padding: 8px;
  user-select: none;
  container-type: size;
}
/* Un cuadrado lo más grande que quepa en el nodo, sea como sea el nodo. */
.ruleta-rueda-caja {
  position: relative;
  width: min(100cqw, 100cqh); height: min(100cqw, 100cqh);
  container-type: inline-size;
  /* La letra del sistema, como en las apps de Apple (en Windows, Segoe UI). */
  --ruleta-letra: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI Variable Text', 'Segoe UI', var(--font-body), sans-serif;
  --ruleta-tinta: #1D1D1F;
  --ruleta-gris: #6E6E73;
  --ruleta-plato: #FFFFFF;
  --ruleta-cristal: rgba(255, 255, 255, 0.78);
}
[data-theme="dark"] .ruleta-rueda-caja {
  --ruleta-plato: #2C2C2E;
  --ruleta-cristal: rgba(44, 44, 46, 0.8);
  --ruleta-gris: #A1A1A6;
}
/* Lo que no gira (Ruleta.jsx): debajo el plato con su sombra suave; encima
   un brillo leve y el filo. Entre los dos, la rueda, que es lo único que da
   vueltas. Estilo Apple, como pidió el usuario: nada de tinta gruesa, aros
   ni bombillas (la versión de feria le pareció más fea que la de antes). */
.ruleta-fondo, .ruleta-marco {
  position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none; overflow: visible;
}
.ruleta-fondo { z-index: 0; filter: drop-shadow(0 2.4cqw 5cqw rgba(0, 0, 0, 0.14)) drop-shadow(0 0.5cqw 1.2cqw rgba(0, 0, 0, 0.08)); }
.ruleta-marco { z-index: 2; }
.ruleta-plato { fill: var(--ruleta-plato); }
.ruleta-plato-borde { fill: none; stroke: rgba(0, 0, 0, 0.06); stroke-width: 0.6; }
.ruleta-filo { fill: none; stroke: rgba(0, 0, 0, 0.05); stroke-width: 0.6; }
.ruleta-rueda {
  position: relative; z-index: 1;
  width: 100%; height: 100%;
  display: block;
  border-radius: 50%;
  will-change: transform;
}
.ruleta-porcion { stroke: none; transition: opacity 420ms ease, transform 520ms var(--muelle), filter 420ms ease; }
/* Al salir el premio, las demás se apagan y pierden color; la que sale se
   adelanta un poco. */
.ruleta-porcion.apagada { opacity: 0.4; filter: saturate(0.35); }
/* La porción que se acaba de añadir entra desde el centro con rebote: es la
   respuesta a haber escrito algo. El centro de la rueda es el 0 0 del dibujo. */
.ruleta-porcion.nueva { transform-origin: 0 0; animation: ruleta-porcion-entra 560ms var(--muelle) backwards; }
@keyframes ruleta-porcion-entra { from { transform: scale(0.35); opacity: 0.2; } to { transform: scale(1); opacity: 1; } }
/* El hueco del segundo elemento cuando solo hay uno: sin color, con borde de
   puntos, y con lo que se va escribiendo dentro según se teclea. */
.ruleta-porcion.fantasma { fill: var(--paper-2); stroke: var(--ink-3); stroke-width: 0.8; stroke-dasharray: 3 2.4; }
/* Su transform va en CSS (ver Ruleta.jsx) para que la vuelta de los que quedan
   cabeza abajo al parar se vea girar en su sitio. El origen, el centro de la
   rueda, como el atributo transform de siempre. */
.ruleta-texto { fill: #1D1D1F; font-family: var(--ruleta-letra); font-weight: 600; font-size: 8px; letter-spacing: -0.015em; pointer-events: none; transform-box: view-box; transform-origin: 0 0; transition: opacity 420ms ease, transform 520ms var(--muelle); }
.ruleta-texto.fantasma { fill: var(--ink-3); font-weight: 500; }
/* Sobre una foto, el nombre lleva un halo claro para leerse. */
.ruleta-texto.con-halo { paint-order: stroke; stroke: rgba(255,255,255,0.9); stroke-width: 2.2px; stroke-linejoin: round; }
/* Las líneas blancas entre porciones. */
.ruleta-raya { stroke: var(--ruleta-plato); stroke-width: 1.4; stroke-linecap: round; pointer-events: none; }
.ruleta-fotos { pointer-events: none; }
/* La flecha: un triángulo pequeño de puntas redondeadas, oscuro y con una
   sombra suave. Se mueve un poco cuando pasa cada porción (golpeFlecha en
   Ruleta.jsx), así que al frenar se va quedando quieta. Gira sobre su base. */
.ruleta-flecha {
  position: absolute; left: 50%; top: -1.5%; z-index: 3;
  width: 8.5%; aspect-ratio: 24 / 26;
  transform: translateX(-50%);
  transform-origin: 50% 15%;
  pointer-events: none;
  filter: drop-shadow(0 0.6cqw 1cqw rgba(0, 0, 0, 0.25));
}
.ruleta-flecha svg { width: 100%; height: 100%; display: block; overflow: visible; }
.ruleta-flecha-cuerpo { fill: var(--ruleta-tinta); stroke: var(--ruleta-plato); stroke-width: 1.6; stroke-linejoin: round; }
[data-theme="dark"] .ruleta-flecha-cuerpo { fill: #F5F5F7; stroke: #2C2C2E; }
/* El botón del centro, como uno de iOS: blanco, redondo, con su sombra suave;
   crece un poco al pasar el ratón y se encoge al pulsarlo. */
.ruleta-centro {
  position: absolute; left: 50%; top: 50%; z-index: 3;
  width: 26%; aspect-ratio: 1;
  display: grid; place-items: center;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  border: none;
  background: linear-gradient(180deg, var(--ruleta-plato) 0%, color-mix(in srgb, var(--ruleta-plato) 92%, #000) 100%);
  color: var(--ruleta-tinta);
  box-shadow: 0 1.2cqw 3.4cqw rgba(0, 0, 0, 0.18), 0 0 0 0.3cqw rgba(0, 0, 0, 0.04), inset 0 0.2cqw 0 rgba(255, 255, 255, 0.7);
  font-family: var(--ruleta-letra); font-weight: 600; font-size: 5.2cqw; letter-spacing: -0.01em;
  cursor: pointer;
  transition: transform 320ms var(--muelle), box-shadow 200ms ease, opacity 300ms;
}
[data-theme="dark"] .ruleta-centro { color: #F5F5F7; box-shadow: 0 1.2cqw 3.4cqw rgba(0, 0, 0, 0.4), 0 0 0 0.3cqw rgba(255, 255, 255, 0.06); }
.ruleta-centro:hover:not(:disabled) { transform: translate(-50%, -50%) scale(1.05); box-shadow: 0 1.8cqw 4.6cqw rgba(0, 0, 0, 0.22), 0 0 0 0.3cqw rgba(0, 0, 0, 0.04); }
.ruleta-centro:active:not(:disabled) { transform: translate(-50%, -50%) scale(0.95); }
.ruleta-centro:disabled { cursor: default; }
.ruleta-centro-gira { font-size: 7cqw; display: inline-flex; color: var(--ruleta-gris); animation: ruleta-gira-icono 900ms linear infinite; }
@keyframes ruleta-gira-icono { to { transform: rotate(360deg); } }
/* Con un solo elemento el botón ya está, pero apagado: dice qué viene después. */
.ruleta-centro.espera { color: var(--ruleta-gris); }
/* El que ha salido: una tarjeta de cristal esmerilado, con el color de su
   porción, «Ha salido» en gris pequeño y el nombre debajo. Abajo, lejos de
   la flecha, que es donde está él. */
.ruleta-premio {
  position: absolute; left: 50%; bottom: 4%; z-index: 4;
  max-width: 86%;
  display: flex; align-items: center; gap: 2.4cqw;
  padding: 2.2cqw 2.4cqw 2.2cqw 2.8cqw;
  border-radius: 4.2cqw;
  background: var(--ruleta-cristal);
  -webkit-backdrop-filter: blur(16px) saturate(1.8);
  backdrop-filter: blur(16px) saturate(1.8);
  color: var(--ruleta-tinta);
  box-shadow: 0 2.4cqw 6cqw rgba(0, 0, 0, 0.18), 0 0 0 0.25cqw rgba(0, 0, 0, 0.04);
  font-family: var(--ruleta-letra);
  transform: translateX(-50%);
  animation: ruleta-premio 560ms var(--muelle) backwards;
}
[data-theme="dark"] .ruleta-premio { color: #F5F5F7; box-shadow: 0 2.4cqw 6cqw rgba(0, 0, 0, 0.45), 0 0 0 0.25cqw rgba(255, 255, 255, 0.06); }
.ruleta-premio-color { width: 4.6cqw; height: 4.6cqw; flex-shrink: 0; border-radius: 50%; box-shadow: inset 0 0 0 0.25cqw rgba(0, 0, 0, 0.08); }
.ruleta-premio-texto { display: flex; flex-direction: column; min-width: 0; line-height: 1.15; }
.ruleta-premio-eti { font-size: 2.9cqw; font-weight: 500; color: var(--ruleta-gris); letter-spacing: 0; }
.ruleta-premio-nombre { font-size: 5.6cqw; font-weight: 700; letter-spacing: -0.02em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ruleta-premio-quitar {
  flex-shrink: 0;
  padding: 1cqw 2.2cqw;
  border-radius: 999px;
  border: none;
  background: rgba(120, 120, 128, 0.16); color: inherit;
  font-family: var(--ruleta-letra); font-size: 3cqw; font-weight: 600; cursor: pointer;
  transition: background 150ms, color 150ms;
}
.ruleta-premio-quitar:hover { background: var(--wine); color: var(--wine-ink); }
/* Un premio largo se parte en dos líneas y con la letra más pequeña: en una
   sola, «Elemento con nombre largo 41» se cortaba justo en lo que lo distingue. */
.ruleta-premio.largo .ruleta-premio-nombre {
  font-size: 4.2cqw; white-space: normal;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
}
/* El confeti del final (ruletaConfeti en Ruleta.jsx): el doble de la rueda
   y centrado en ella, para que los triángulos puedan salir fuera. */
.ruleta-confeti {
  position: absolute; left: -50%; top: -50%; width: 200%; height: 200%;
  z-index: 5; pointer-events: none; overflow: visible;
}
@keyframes ruleta-premio {
  from { opacity: 0; transform: translateX(-50%) translateY(3cqw) scale(0.92); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
}
/* El botón de la foto en la lista de elementos: con foto, la enseña. */
.ruleta-fila-foto {
  width: 26px; height: 26px; flex-shrink: 0; display: grid; place-items: center;
  border: 1.5px dashed var(--line-soft); border-radius: 6px;
  color: var(--ink-3); cursor: pointer;
  background-size: cover; background-position: center;
}
.ruleta-fila-foto:hover { border-color: var(--line); color: var(--ink); }
.ruleta-fila-foto.con-foto { border-style: solid; border-color: var(--line); }
.ruleta-fila-foto .material-symbols-rounded { font-size: 16px; }
/* Vacía: un círculo en blanco que dice lo que falta, como el de la captura.
   Deja sitio abajo para el botón o el campo, que van sueltos (ver
   .ruleta-anadir) para no rehacerse al pasar de cero elementos a uno. */
.ruleta-vacia {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 16% 16% 30%;
  border-radius: 50%;
  background: var(--paper); color: var(--ink);
  border: max(1.5px, 0.6cqw) dashed var(--line-soft);
  box-shadow: 0 2.5cqw 7cqw rgba(0,0,0,0.14);
  text-align: center;
}
.ruleta-vacia-texto { font-family: var(--font-display); font-weight: 700; font-size: 5.6cqw; line-height: 1.25; }
/* El botón de añadir o el campo de escribir: con la rueda vacía, bajo el
   texto; con un elemento, abajo, encima de la rueda. */
.ruleta-anadir {
  position: absolute; left: 50%; top: 60%; z-index: 4;
  width: 76%;
  display: flex; justify-content: center;
  transform: translateX(-50%);
}
.ruleta.uno .ruleta-anadir { top: auto; bottom: 7%; }
.ruleta-boton {
  display: inline-flex; align-items: center; gap: 0.4em;
  padding: 0.55em 1.1em; border-radius: 999px;
  background: var(--olive); color: var(--olive-ink);
  font-size: 4.4cqw; font-weight: 700; cursor: pointer;
  box-shadow: 0 0.7cqw 2.5cqw rgba(0,0,0,0.18);
  transition: transform 220ms var(--muelle);
}
.ruleta-boton:hover { transform: scale(1.06); }
.ruleta-boton .material-symbols-rounded { font-size: 1.3em; }
.ruleta-campo {
  width: 100%; padding: 0.55em 0.9em; border-radius: 999px;
  border: max(1.5px, 0.6cqw) solid var(--olive); background: var(--paper-2); color: var(--ink);
  box-shadow: 0 0.7cqw 2.5cqw rgba(0,0,0,0.18);
  font-size: 4.4cqw; font-weight: 600; text-align: center;
}
/* El panel de elementos de la barra. */
/* Con un poco de margen: la lista se desplaza, y lo que sobresale de ella (el
   aro del color al pasar el ratón) se cortaba por el borde. */
.ruleta-lista { display: flex; flex-direction: column; gap: 5px; margin-bottom: 8px; max-height: 50vh; overflow-y: auto; padding: 4px; margin-left: -4px; margin-right: -4px; }
.ruleta-fila { display: flex; align-items: center; gap: 6px; }
.ruleta-fila-color { width: 22px; height: 22px; flex-shrink: 0; border-radius: 50%; border: 1.5px solid var(--line); cursor: pointer; transition: box-shadow 150ms; }
.ruleta-fila-color:hover, .ruleta-fila-color.abierto { box-shadow: 0 0 0 2px var(--paper), 0 0 0 3.5px var(--line); }
.ruleta-fila-selector { padding: 6px 0 8px 30px; }
.ruleta-fila-texto, .ruleta-nuevo {
  flex: 1; min-width: 0; width: 100%;
  padding: 6px 8px; border: 1.5px solid var(--line-soft); border-radius: 2px;
  background: var(--paper-2); color: var(--ink); font-size: 12.5px; font-weight: 600;
}
.ruleta-fila-texto:focus, .ruleta-nuevo:focus { border-color: var(--olive); }
.ruleta-fila-quitar { width: 26px; height: 26px; flex-shrink: 0; display: grid; place-items: center; border-radius: 2px; color: var(--ink-3); cursor: pointer; }
.ruleta-fila-quitar:hover { background: color-mix(in srgb, var(--wine) 14%, transparent); color: var(--wine-texto); }
.ruleta-fila-quitar .material-symbols-rounded { font-size: 16px; }
.ruleta-fila-quitar.volver:hover { background: color-mix(in srgb, var(--olive) 22%, transparent); color: var(--ink); }
/* Un elemento que ya salió (con «Quitar al que sale» o el botón del cartel):
   sigue en la lista, en gris, para poder volver a meterlo. */
.ruleta-fila.fuera .ruleta-fila-texto { opacity: 0.5; text-decoration: line-through; }
.ruleta-fila.fuera .ruleta-fila-color, .ruleta-fila.fuera .ruleta-fila-foto { opacity: 0.4; }
.ruleta-acciones { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.ruleta-accion {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 5px 10px; border-radius: 8px;
  border: 1.5px solid var(--line); background: var(--paper); color: var(--ink);
  font-size: 12px; font-weight: 600; cursor: pointer; box-shadow: var(--pop-sm);
}
.ruleta-accion:hover { background: var(--paper-2); }
.ruleta-accion .material-symbols-rounded { font-size: 15px; }
.ruleta-duraciones { display: flex; gap: 6px; }
.ruleta-duracion {
  flex: 1; padding: 6px 8px; border-radius: 8px;
  border: 1.5px solid var(--line); background: var(--paper); color: var(--ink);
  font-size: 12px; font-weight: 700; cursor: pointer;
}
.ruleta-duracion.activa { background: var(--olive); color: var(--olive-ink); box-shadow: var(--pop-sm); }
.ruleta-interruptor { display: flex; gap: 8px; align-items: flex-start; cursor: pointer; }
.ruleta-interruptor input { margin-top: 3px; accent-color: var(--olive); }
.ruleta-interruptor span { display: flex; flex-direction: column; gap: 2px; font-size: 13px; }
.ruleta-interruptor small { color: var(--ink-3); font-size: 11.5px; line-height: 1.35; }
.ruleta-historial { display: flex; flex-direction: column; gap: 4px; max-height: 200px; overflow-y: auto; margin-bottom: 8px; }
.ruleta-historial-fila { display: flex; align-items: center; gap: 7px; font-size: 13px; }
.ruleta-historial-fila i { width: 12px; height: 12px; flex-shrink: 0; border-radius: 50%; border: 1.5px solid var(--line); }
.ruleta-historial-fila span { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ruleta-historial-fila small { color: var(--ink-3); font-size: 11px; font-variant-numeric: tabular-nums; }
.ruleta-historial-vacio { color: var(--ink-3); font-size: 12.5px; margin-bottom: 4px; }

/* ── Galería ──
   Una tarjeta como las demás (borde, sombra dura, esquinas casi rectas) con
   las fotos dentro. Cada foto va en posición absoluta y con transiciones, así
   que al cambiar de vista, añadir, quitar o estirar el nodo, las fotos se
   deslizan a su sitio nuevo con un poco de rebote en vez de saltar.
   No usa .item-card a propósito: esa clase deja el nodo sin eventos hasta que
   se selecciona, y entonces no se podían soltar fotos encima de una galería
   que no estuviera seleccionada. */
/* ── El nodo de progreso ──
   Crece como una imagen: la letra va en unidades del propio nodo (cqw/cqh),
   así que al estirarlo crece todo junto, sin botón de tamaño (como la ruleta).
   La barra se llena deslizándose con --muelle cuando cambia el número. */
.progreso {
  container-type: size;
  position: relative; width: 100%; height: 100%; box-sizing: border-box;
  display: flex; flex-direction: column; justify-content: center;
  /* En % y no en cqw/cqh: en el propio contenedor esas unidades no miden el
     nodo sino la ventana, y salían 77 px de margen a cada lado. */
  padding: 4% 6%;
  border: 1.5px solid var(--line); border-radius: 2px;
  box-shadow: var(--pop);
  color: var(--ink);
  user-select: none;
}
.progreso-cabeza { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; min-width: 0; }
.progreso-titulo {
  display: flex; align-items: center; gap: 0.35em; min-width: 0;
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(10px, 4.6cqw, 44px);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.progreso-titulo .material-symbols-rounded { font-size: 1.25em; color: var(--olive-texto); flex-shrink: 0; }
.progreso-pct {
  font-family: var(--font-display); font-weight: 800; line-height: 1;
  font-size: clamp(16px, 9.5cqw, 96px);
  font-variant-numeric: tabular-nums;
}
.progreso-pct small { font-size: 0.5em; margin-left: 0.05em; color: var(--ink-2); }
.progreso-barra {
  position: relative; height: clamp(8px, 15cqh, 64px);
  margin: 6cqh 0 5cqh;
  border: 1.5px solid var(--line); border-radius: 999px;
  background: var(--paper-2);
  overflow: hidden;
}
.progreso-relleno {
  position: absolute; inset: 0 auto 0 0;
  background-color: var(--olive);
  background-image: repeating-linear-gradient(-45deg, rgba(255,255,255,0.20) 0 7px, transparent 7px 14px);
  border-right: 1.5px solid var(--line);
  transition: width 700ms var(--muelle);
}
.progreso-barra i {
  position: absolute; top: 28%; bottom: 28%; width: 1.5px;
  background: color-mix(in srgb, var(--ink) 16%, transparent);
}
.progreso-pie { font-size: clamp(9px, 3.5cqw, 30px); font-weight: 600; color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.progreso.vacio .progreso-pie { white-space: normal; }
.progreso.vacio .progreso-relleno { border-right: none; }
/* Lleno: la barra entera y el número dan un saltito. */
.progreso.lleno .progreso-relleno { border-right: none; }
.progreso.lleno .progreso-pct { color: var(--olive-texto); animation: progreso-lleno 620ms var(--muelle); }
@keyframes progreso-lleno { 0% { transform: scale(1); } 40% { transform: scale(1.18); } 100% { transform: scale(1); } }

.galeria {
  --galeria-curva: cubic-bezier(0.3, 1.22, 0.45, 1);
  position: relative; width: 100%; height: 100%;
  border: 1.5px solid var(--line); border-radius: 2px;
  box-shadow: var(--pop);
  user-select: none;
  transition: transform 130ms var(--e-out), box-shadow 130ms var(--e-out),
    background-color 300ms, border-color 300ms;
}
.item:hover .galeria { transform: translate(-1px, -2px); box-shadow: var(--pop-hover); }
.item.selected .galeria { outline: 2px solid var(--olive); outline-offset: 2px; }
/* En pila no hay tarjeta: las fotos quedan sueltas encima del lienzo, como
   un montón de fotos de papel sobre la mesa. */
.galeria.pila:not(.vacia) { background: transparent !important; border-color: transparent; box-shadow: none; }
.item:hover .galeria.pila:not(.vacia) { transform: none; box-shadow: none; }

/* El lienzo cambia --handle-scale y --handle-libre a cada paso del zoom, y
   como se heredan, el navegador recalculaba el estilo de cada foto (cuatro
   elementos por foto: con 500, dos mil) aunque aquí no se usan. Fijándolas
   en el contenedor, lo de dentro no cambia y no se recalcula. */
.galeria-fotos { position: absolute; inset: var(--galeria-borde, 8px); --handle-scale: initial; --handle-libre: initial; }
.galeria-foto {
  position: absolute;
  /* Sin overflow: hidden: la foto ya mide justo su caja, y un recorte por
     foto eran quinientos recortes más al componer cada cuadro. */
  border-radius: 2px;
  background: var(--paper-2);
  box-shadow: 0 0 0 1px var(--line-soft);
  transition: left 460ms var(--galeria-curva), top 460ms var(--galeria-curva),
    width 460ms var(--galeria-curva), height 460ms var(--galeria-curva),
    transform 560ms var(--muelle), box-shadow 160ms, padding 300ms, background-color 300ms;
}
.galeria-foto img { width: 100%; height: 100%; object-fit: cover; display: block; pointer-events: none; border-radius: 1px; }
/* Llegan cuando está su miniatura (ver galeria-miniaturas.js) y aparecen con
   un fundido, en vez de pintarse a trozos. */
.galeria-foto img, .galeria-mini-caja img { opacity: 0; transition: opacity 220ms ease-out; }
.galeria-foto img.lista, .galeria-mini-caja img.lista { opacity: 1; }
.galeria-mini-caja { display: block; width: 100%; height: 100%; }
.galeria-mini-caja img { width: 100%; height: 100%; object-fit: cover; display: block; pointer-events: none; }
.galeria.rejilla .galeria-foto:hover { transform: scale(1.03); z-index: 2; box-shadow: var(--pop); }

/* La pila: fotos de papel, con su marco blanco y más margen abajo, torcidas
   cada una a su manera. Con el ratón encima se abren en abanico. */
.galeria.pila .galeria-foto {
  padding: 4% 4% 13%;
  background: #FFFFFF;
  border-radius: 2px;
  box-shadow: 0 0 0 1.5px var(--line), 2px 2px 0 1.5px var(--line);
  transform: translate(var(--pila-x, 0px), var(--pila-y, 0px)) rotate(var(--pila-giro, 0deg));
}
.item:hover .galeria.pila .galeria-foto {
  transform: translate(var(--abanico-x, 0px), var(--abanico-y, 0px)) rotate(var(--abanico-giro, 0deg));
}
.galeria-contador {
  position: absolute; right: 6%; bottom: 7%; z-index: 999;
  min-width: 24px; padding: 2px 7px;
  border: 1.5px solid var(--line); border-radius: 999px;
  background: var(--paper); color: var(--ink);
  box-shadow: var(--pop-sm);
  font-family: var(--font-mono); font-size: 11px; font-weight: 700; text-align: center;
  transition: opacity 200ms;
}
.item:hover .galeria-contador { opacity: 0; }

/* Entrar y salir. Con las propiedades sueltas (scale, rotate) y no con
   transform, para no pisar la inclinación que cada foto lleva en la pila. */
.galeria-foto.entra { animation: galeria-entra 560ms var(--muelle) both; }
@keyframes galeria-entra {
  from { opacity: 0; scale: 0.35; rotate: -8deg; }
  to   { opacity: 1; scale: 1;    rotate: 0deg; }
}
.galeria-foto.sale { animation: galeria-sale 240ms ease-in forwards; pointer-events: none; }
@keyframes galeria-sale { to { opacity: 0; scale: 0.3; rotate: 6deg; } }

/* Quitar una foto: solo con la galería seleccionada, para no borrar una sin
   querer al pasar por encima. */
.galeria-quitar {
  position: absolute; top: 6px; right: 6px; z-index: 3;
  width: 22px; height: 22px;
  display: grid; place-items: center;
  border: 1.5px solid var(--line); border-radius: 50%;
  background: var(--wine); color: var(--wine-ink);
  box-shadow: var(--pop-sm);
  cursor: pointer;
  opacity: 0; scale: 0.5; pointer-events: none;
  transition: opacity 150ms, scale 240ms var(--muelle);
}
.galeria-quitar .material-symbols-rounded { font-size: 14px; }
.item.selected .galeria-foto:hover .galeria-quitar { opacity: 1; scale: 1; pointer-events: auto; }

/* Vacía: el sitio donde soltar, con un icono que flota. */
.galeria.vacia { border-style: dashed; box-shadow: none; }
.galeria-vacia-caja {
  position: absolute; inset: var(--galeria-borde, 8px);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  border-radius: 2px;
  background: var(--paper-2); color: var(--ink-2);
  text-align: center; padding: 10px;
}
.galeria-vacia-icono { font-size: 42px; color: var(--ink-3); animation: galeria-flota 3.2s ease-in-out infinite; }
@keyframes galeria-flota { 0%, 100% { translate: 0 0; } 50% { translate: 0 -5px; } }
.galeria-vacia-texto { font-family: var(--font-display); font-weight: 700; font-size: 15px; }
.galeria-boton {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px;
  border: 1.5px solid var(--line); border-radius: 2px;
  background: var(--olive); color: #1A1A1A;
  box-shadow: var(--pop-sm);
  font-size: 12.5px; font-weight: 700; cursor: pointer;
  transition: transform 220ms var(--muelle), box-shadow 150ms;
}
.galeria-boton:hover { transform: translate(-1px, -1px); box-shadow: var(--pop); }
.galeria-boton .material-symbols-rounded { font-size: 17px; }

/* Arrastrando fotos por encima: la galería dice que las va a coger. */
.galeria-suelta {
  position: absolute; inset: 0; z-index: 1000;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  border: 2.5px dashed var(--olive); border-radius: 2px;
  background: color-mix(in srgb, var(--olive) 24%, transparent);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  color: var(--ink);
  font-family: var(--font-display); font-weight: 800; font-size: 15px;
  pointer-events: none;
  animation: galeria-suelta 700ms var(--muelle) infinite alternate;
}
.galeria-suelta .material-symbols-rounded { font-size: 34px; }
@keyframes galeria-suelta { from { scale: 0.98; } to { scale: 1.015; } }
/* Encogiendo las fotos antes de guardarlas: una raya que corre arriba. */
.galeria-cargando {
  position: absolute; left: 0; right: 0; top: -1px; height: 3px; z-index: 1001;
  background: linear-gradient(90deg, transparent, var(--olive), transparent);
  background-size: 50% 100%; background-repeat: no-repeat;
  animation: galeria-carga 900ms linear infinite;
}
@keyframes galeria-carga { from { background-position: -50% 0; } to { background-position: 150% 0; } }

/* ── El visor de la galería ──
   A pantalla completa, encima de todo. Los botones en blanco con la sombra
   dura de la aplicación, sobre un fondo oscuro que deja ver el lienzo
   borroso detrás. */
.galeria-visor { position: fixed; inset: 0; z-index: 10050; }
.galeria-visor-fondo {
  position: absolute; inset: 0;
  background: rgba(20, 19, 22, 0.86);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
}
.galeria-visor-escena { position: absolute; inset: 70px 80px 100px; display: flex; align-items: center; justify-content: center; }
/* Con medidas de la ventana y no en porcentaje: dentro de la escena el 100 %
   de alto no se aplicaba y una foto apaisada se salía por abajo. */
.galeria-visor-foto {
  max-width: calc(100vw - 160px); max-height: calc(100vh - 170px);
  object-fit: contain;
  border-radius: 4px;
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.5);
  opacity: 0;
  user-select: none;
  will-change: transform;
}
.galeria-visor-foto.lista { opacity: 1; }
.galeria-visor-arriba {
  position: absolute; top: 18px; left: 20px; right: 20px; z-index: 2;
  display: flex; justify-content: space-between; align-items: center;
  pointer-events: none;
}
.galeria-visor-cuenta {
  padding: 4px 11px;
  border: 1.5px solid rgba(255, 255, 255, 0.28); border-radius: 999px;
  color: #F0EEF0;
  font-family: var(--font-mono); font-size: 13px; font-weight: 700;
}
.galeria-visor-cerrar, .galeria-visor-flecha {
  pointer-events: auto;
  width: 42px; height: 42px;
  display: grid; place-items: center;
  border: 1.5px solid #1A1A1A; border-radius: 50%;
  background: #FFFFFF; color: #1A1A1A;
  box-shadow: 2px 2px 0 0 #1A1A1A;
  cursor: pointer;
  transition: transform 220ms var(--muelle), box-shadow 150ms;
}
.galeria-visor-cerrar:hover, .galeria-visor-flecha:hover { transform: scale(1.1); box-shadow: 3px 4px 0 0 #1A1A1A; }
.galeria-visor-cerrar:active, .galeria-visor-flecha:active { transform: scale(0.94); }
.galeria-visor-flecha { position: absolute; top: 50%; z-index: 2; translate: 0 -50%; }
.galeria-visor-flecha.izq { left: 20px; }
.galeria-visor-flecha.der { right: 20px; }
.galeria-visor-flecha .material-symbols-rounded { font-size: 26px; }
.galeria-visor-tira {
  position: absolute; bottom: 20px; left: 50%; z-index: 2;
  translate: -50% 0;
  display: flex; gap: 7px;
  max-width: calc(100vw - 40px);
  overflow-x: auto; padding: 6px 4px;
  scrollbar-width: none;
}
.galeria-visor-mini {
  flex: 0 0 auto;
  width: 50px; height: 50px; padding: 0;
  border: 2px solid transparent; border-radius: 4px;
  overflow: hidden;
  background: #2A282C;
  opacity: 0.5; cursor: pointer;
  transition: opacity 150ms, transform 260ms var(--muelle), border-color 150ms;
}
.galeria-visor-mini img { width: 100%; height: 100%; object-fit: cover; display: block; pointer-events: none; }
.galeria-visor-mini:hover { opacity: 0.85; }
.galeria-visor-mini.actual { opacity: 1; border-color: var(--olive); transform: translateY(-4px) scale(1.08); }
@media (max-width: 700px) {
  .galeria-visor-escena { inset: 64px 12px 96px; }
  .galeria-visor-foto { max-width: calc(100vw - 24px); }
  .galeria-visor-flecha { display: none; }
}
/* El panel de fotos de la barra: cada una con su miniatura, para cambiarlas
   de orden (la primera es la portada, la de arriba de la pila) o quitarlas. */
.galeria-lista { display: flex; flex-direction: column; gap: 5px; max-height: 50vh; overflow-y: auto; padding: 4px; margin: 0 -4px; }
.galeria-fila { display: flex; align-items: center; gap: 7px; }
.galeria-fila-mini { width: 40px; height: 40px; flex-shrink: 0; overflow: hidden; object-fit: cover; border: 1.5px solid var(--line); border-radius: 2px; background: var(--paper-2); }
.galeria-fila-nombre { flex: 1; min-width: 0; font-size: 12.5px; font-weight: 600; color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.galeria-fila-boton { width: 26px; height: 26px; flex-shrink: 0; display: grid; place-items: center; border-radius: 2px; color: var(--ink-2); cursor: pointer; }
.galeria-fila-boton:hover:not(:disabled) { background: var(--paper-2); color: var(--ink); }
.galeria-fila-boton:disabled { opacity: 0.3; cursor: default; }
.galeria-fila-boton.quitar:hover { background: color-mix(in srgb, var(--wine) 14%, transparent); color: var(--wine-texto); }
.galeria-fila-boton .material-symbols-rounded { font-size: 16px; }

/* ── Un tablero que se va a ser proyecto ──
   El anillo verde que se abre donde estaba (el portal), el brillo de la copia
   que vuela, y el saltito de la flecha de volver al recibirlo. */
.teleporte-anillo {
  position: fixed; z-index: 9998; pointer-events: none;
  border-radius: 50%;
  border: 3px solid var(--olive);
  box-shadow: 0 0 0 6px color-mix(in srgb, var(--olive) 25%, transparent), inset 0 0 18px color-mix(in srgb, var(--olive) 45%, transparent);
  transform: translate(-50%, -50%) scale(0.4);
  animation: teleporte-anillo 760ms var(--e-out) forwards;
}
@keyframes teleporte-anillo {
  0%   { opacity: 0.95; transform: translate(-50%, -50%) scale(0.35); }
  100% { opacity: 0;    transform: translate(-50%, -50%) scale(1.3); }
}
.teleporte-copia { filter: drop-shadow(0 0 12px color-mix(in srgb, var(--olive) 75%, transparent)); }
.crumb-back.recibe { animation: crumb-recibe 620ms var(--muelle); }
@keyframes crumb-recibe {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.4); color: var(--olive-texto); }
  100% { transform: scale(1); }
}

/* ── Separador ──
   La línea ocupa lo que deje el título; a la izquierda o a la derecha el título
   se come una de las dos. Sin título queda una sola línea de lado a lado. */
.separador {
  width: 100%; height: 100%;
  display: flex; align-items: center; gap: 0.7em;
  font-size: calc(18px * var(--vista-escala, var(--text-scale, 1)));
}
.sep-linea { flex: 1 1 0; min-width: 16px; height: 0; }
.sep-left .sep-antes, .sep-right .sep-despues { display: none; }
.separador.sin-titulo .sep-antes { display: block; }
.separador.sin-titulo .sep-titulo, .separador.sin-titulo .sep-despues { display: none; }
.sep-titulo {
  flex: 0 1 auto; min-width: 1ch; max-width: 80%;
  font-family: var(--font-display); font-weight: 800;
  letter-spacing: -0.01em; line-height: 1.2;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  outline: none;
}
.sep-titulo:empty::before { content: attr(data-placeholder); color: var(--ink-3); font-weight: 600; }
.sep-muestra { width: 34px; height: 0; flex-shrink: 0; color: var(--ink-2); }

.node-caption { width: 100%; outline: none; font-family: var(--font-display); font-weight: 800; font-size: 15px; line-height: 1.25; letter-spacing: -0.01em; color: var(--ink); min-height: 1.2em; word-break: break-word; cursor: text; }
.node-caption:empty::before { content: attr(data-placeholder); color: var(--ink-3); font-weight: 600; pointer-events: none; }
.node-caption a { color: var(--wine-texto); text-decoration: underline; }
.node-caption h1, .node-caption h2, .node-caption p { margin: 0; font: inherit; }
/* The node must be selected before its caption becomes editable — a first click
   falls through to select/drag the node, a second click edits the text. */
.item:not(.selected) .node-caption { pointer-events: none; }
.node-caption-row { padding: 6px 12px; border-top: 1px solid var(--line-soft); }
.link-caption-input.node-caption { margin-top: 4px; }
/* La leyenda de imagen se posiciona con left/right, así que su ancho debe ser
   automático — el width:100% heredado de .node-caption la desbordaba por la
   derecha (hueco solo a la izquierda). */
.image-caption.node-caption { min-height: 0; width: auto; box-sizing: border-box; }

/* Todo */
.todo-card .item-card {
  padding: calc(11px * var(--node-scale, 1)) calc(13px * var(--node-scale, 1));
  background: var(--paper);
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  height: 100%;
}
.todo-title { flex: 0 0 auto; font-family: var(--font-display); font-weight: 700; font-size: calc(14px * var(--node-scale, 1)); margin-bottom: 8px; display: flex; align-items: center; gap: 6px; min-width: 0; width: 100%; }
.todo-title span { overflow-wrap: break-word; word-break: break-word; flex: 1; min-width: 0; }
.todo-title .material-symbols-rounded { font-size: calc(16px * var(--node-scale, 1)); color: var(--olive-texto); }
.todo-title-edit { font: inherit; flex: 1; overflow-wrap: break-word; word-break: break-word; }
.todo-list {
  display: flex;
  flex-direction: column;
  gap: 3px;
  flex: 1;
  overflow-x: hidden;
  overflow-y: hidden; /* no vertical scroll inside todo cards */
  min-height: 0;
  padding-right: 4px;
}
.todo-drag-handle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 20px;
  cursor: grab;
  color: var(--ink-3);
  opacity: 0;
  transition: opacity 120ms ease;
  margin-right: -2px;
  margin-left: -4px;
  flex-shrink: 0;
}
.todo-row:hover .todo-drag-handle {
  opacity: 1;
}
.todo-drag-handle:active {
  cursor: grabbing;
}
.todo-drag-handle .material-symbols-rounded {
  font-size: 16px;
}
.todo-row-controls {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  margin-left: 6px;
  flex-shrink: 0;
}
.todo-row-controls button {
  background: transparent;
  border: none;
  color: var(--ink-3);
  padding: 2px;
  border-radius: 3px;
  cursor: pointer;
  display: grid;
  place-items: center;
}
.todo-row-controls button:hover:not(:disabled) {
  background: var(--bg);
  color: var(--olive-texto);
}
.todo-row-controls button.danger:hover:not(:disabled) {
  background: var(--bg);
  color: var(--wine-texto);
}
.todo-row-controls button:disabled {
  opacity: 0.25;
  cursor: not-allowed;
}
.todo-row-controls button .material-symbols-rounded {
  font-size: 14px;
}
.todo-list::-webkit-scrollbar {
  width: 5px;
}
.todo-list::-webkit-scrollbar-track {
  background: transparent;
}
.todo-list::-webkit-scrollbar-thumb {
  background: var(--line-soft);
  border-radius: 99px;
}
.todo-list::-webkit-scrollbar-thumb:hover {
  background: var(--olive);
}
.todo-row { display: flex; align-items: flex-start; gap: 7px; font-size: calc(13px * var(--node-scale, 1) * var(--vista-escala, var(--text-scale, 1))); padding: 4px 6px; border-radius: 4px; transition: background 150ms ease, box-shadow 150ms ease; margin: 0 -6px; max-width: 100%; box-sizing: border-box; flex-shrink: 0; }
.todo-row.indent-1 { padding-left: 22px; margin-left: 0; }
.todo-row.indent-2 { padding-left: 44px; margin-left: 0; }
.todo-row.focused { background: var(--focused-row-bg, rgba(144, 185, 104, 0.08)); box-shadow: inset 3px 0 0 var(--olive); }
.todo-check { width: 15px; height: 15px; border-radius: 2px; border: 1.5px solid var(--line); display: grid; place-items: center; background: var(--paper); flex-shrink: 0; margin-top: 1px; cursor: pointer; }
.todo-check.done { background: var(--olive); border-color: var(--olive); }
.todo-check.partial { background: color-mix(in srgb, var(--olive) 30%, var(--paper)); }
.todo-check .material-symbols-rounded { font-size: 11px; color: white; }
.todo-row.done .todo-label { text-decoration: line-through; color: var(--ink-3); }
.todo-label { flex: 1; }
.todo-input {
  font-size: calc(13px * var(--node-scale, 1));
  line-height: 1.45;
  flex: 1 1 auto;
  display: block;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
  padding: 0;
  background: transparent;
  border: none;
  outline: none;
  resize: none;
  overflow-y: hidden;
  height: auto;
  color: inherit;
  font-family: inherit;
  overflow-wrap: anywhere;
  word-break: normal;
  white-space: pre-wrap;
}
/* La fila del to-do dejo de ser un <textarea> y pasa a ser texto con formato,
   asi que necesita lo que un textarea traia de serie: el aviso de fila vacia y
   que el formato no se salga de la caja. */
.todo-input:empty::before {
  content: attr(data-placeholder);
  color: var(--ink-3);
  pointer-events: none;
}
.todo-input:focus { outline: none; }
/* Una tarea es una linea, no un documento: los bloques que el navegador pueda
   crear al pegar o al partir la linea se aplanan para que no descuadren la fila. */
.todo-input p, .todo-input div { margin: 0; display: inline; }
.todo-input h1, .todo-input h2, .todo-input h3 { font-size: inherit; font-weight: 700; margin: 0; display: inline; }
.todo-input img { display: none; }
.todo-row.done .todo-input { opacity: 0.55; }

.todo-add { display: flex; align-items: center; gap: 6px; margin-top: 4px; padding: 3px 0; color: var(--ink-3); cursor: pointer; font-size: calc(12px * var(--node-scale, 1)); flex-shrink: 0; }
.todo-add:hover { color: var(--ink); }
.todo-add .material-symbols-rounded { font-size: 14px; }
.todo-row-body { display: flex; flex-direction: column; flex: 1; min-width: 0; max-width: 100%; box-sizing: border-box; }
.todo-row-meta { display: flex; flex-wrap: wrap; gap: 3px; margin-top: 2px; margin-bottom: 1px; }
.todo-meta-chip { display: inline-flex; align-items: center; gap: 3px; font-size: calc(10px * var(--node-scale, 1)); font-weight: 600; padding: 1px 5px; border-radius: 2px; cursor: pointer; transition: opacity 100ms; }
.todo-meta-chip:hover { opacity: 0.7; }
.todo-meta-chip .material-symbols-rounded { font-size: 10px; }
.todo-meta-chip.assignee { color: var(--olive-texto); background: var(--olive-l); border: 1px solid var(--olive); }
.todo-meta-chip.due { color: var(--wine-texto); background: var(--wine-l); border: 1px solid var(--wine-2); }

/* Column strip + body */
.column-card .item-card { background: var(--columna-fondo); display: flex; flex-direction: column; border-radius: 8px; overflow: hidden; }
.column-card .column-strip {
  padding: 11px 14px 9px;
  border-bottom: 1.5px solid var(--line);
  /* Franja del título con un leve degradado para dar profundidad (menos plano) */
  background: linear-gradient(180deg, var(--paper) 0%, color-mix(in srgb, var(--paper) 92%, var(--line-soft)) 100%);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 15px;
  letter-spacing: 0;
  text-align: center;
  position: relative;
  color: #111;
}
.column-card .column-strip.dark { color: #fff; }
.column-strip-head { display: flex; align-items: center; justify-content: center; gap: 7px; }
.column-strip-icon { font-size: 19px; flex-shrink: 0; color: inherit; }
.column-strip-title { white-space: pre-wrap; word-break: break-word; }
.column-card .column-strip textarea { font: inherit; width: 100%; text-align: center; color: inherit; background: transparent; border: none; outline: none; resize: none; overflow-wrap: break-word; word-break: break-word; }
.column-strip-meta {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 11px;
  opacity: 0.7;
  margin-top: 2px;
  color: inherit;
}
.column-card .column-body {
  padding: 10px;
  display: flex; flex-direction: column;
  gap: 7px;
  flex: 1;
  min-height: 80px;
  background: var(--columna-fondo);
  /* Sombra interior sutil: da sensación de "contenedor" en vez de área plana */
  box-shadow: inset 0 2px 6px -4px rgba(0,0,0,0.25);
  overflow-y: auto;
  overflow-x: hidden;
}
.column-card.drop-target .item-card { outline: 3px dashed var(--olive); outline-offset: 2px; }
.column-card.drop-target .column-body { background: var(--olive-l); }

/* Estado vacío: zona punteada acogedora con icono y texto (menos plano) */
.column-empty {
  flex: 1;
  min-height: 90px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px;
  margin: 2px;
  border: 1.5px dashed var(--line-soft, #D5D1CD);
  border-radius: 8px;
  color: var(--ink-3);
  font-size: 12px; font-weight: 600;
  text-align: center;
}
.column-empty .material-symbols-rounded { font-size: 26px; opacity: 0.6; }
.column-card.drop-target .column-empty { border-color: var(--olive); color: var(--olive-texto); }

/* Items rendered INSIDE a column */
.col-child-wrap {
  position: relative;
  width: 100%;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
}
.col-child-wrap input,
.col-child-wrap textarea,
.col-child-wrap [contenteditable] {
  user-select: text;
  -webkit-user-select: text;
}
.col-child-wrap.selected > * > .item-card,
.col-child-wrap.selected .item-card {
  outline: 2px solid var(--olive) !important;
  outline-offset: 2px !important;
}
.col-child-wrap.selected .anchor,
.col-child-wrap:hover .anchor {
  opacity: 1;
  transform: scale(1);
}
.col-child-wrap > .note,
.col-child-wrap > .image-card,
.col-child-wrap > .link-card,
.col-child-wrap > .todo-card,
.col-child-wrap > .doc-card,
.col-child-wrap > .board-card,
.col-child-wrap > .comment-card,
.col-child-wrap > .cal-mb,
.col-child-wrap > .table-card,
.col-child-wrap > .audio-card,
.col-child-wrap > .color-card,
.col-child-wrap > .file-card,
.col-child-wrap > .map-card,
.col-child-wrap > .frame-card,
.col-child-wrap > .title-card,
.col-child-wrap > .swatch-card {
  width: 100% !important;
  height: 100% !important;
}
.col-child-wrap > * > .item-card {
  box-shadow: 1.5px 1.5px 0 var(--line);
  transition: transform 130ms var(--e-out);
}
.col-child-wrap:hover > * > .item-card { transform: translate(-1px, -1px); box-shadow: 2.5px 3px 0 var(--line); }

/* Board — better preview */
.board-card .item-card {
  background: var(--paper);
  padding: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.board-card .item-card .board-color-bar { height: 8px; background: var(--olive); border-bottom: 1.5px solid var(--line); }
.board-cover {
  flex: 1;
  position: relative;
  background: var(--paper-2);
  border-bottom: 1.5px solid var(--line);
  overflow: hidden;
}
.board-cover-grid {
  position: absolute; inset: 0;
  background-image: radial-gradient(circle at 1px 1px, var(--line-soft) 1px, transparent 0);
  background-size: 10px 10px;
}
.board-preview-item {
  position: absolute;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--paper);
  box-shadow: 1px 1px 0 var(--line);
  font-size: 8px;
  padding: 3px;
  font-weight: 600;
  line-height: 1.1;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
}
.board-preview-icon { font-size: 22px !important; color: var(--ink-2); flex-shrink: 0; line-height: 1; }
.board-preview-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; text-align: center; color: var(--ink-2); }
.board-preview-item.kind-note { background: var(--c-cream); }
.board-preview-item.kind-note .board-preview-icon { color: #B58B00; }
.board-preview-item.kind-image { background: var(--bg-2); }
.board-preview-item.kind-image .board-preview-icon { color: var(--ink-2); }
.board-preview-item.kind-board { background: var(--olive-l); }
.board-preview-item.kind-board .board-preview-icon { color: var(--olive-texto); }
.board-preview-item.kind-todo .board-preview-icon { color: var(--olive-texto); }
.board-preview-item.kind-doc .board-preview-icon { color: var(--wine-texto); }
.board-preview-item.kind-link .board-preview-icon { color: #3D5A80; }
.board-preview-item.kind-calendar .board-preview-icon { color: var(--wine-texto); }
.board-preview-item.kind-table .board-preview-icon { color: var(--ink-2); }
.board-preview-item.kind-column { background: var(--paper); }
.board-preview-item.kind-column .board-preview-icon { color: #C24A45; }
.board-preview-item.empty-message { position: absolute; inset: 0; display: grid; place-items: center; color: var(--ink-3); font-size: 11px; background: none; border: none; box-shadow: none; }

.board-foot {
  padding: 11px 14px;
  display: flex; align-items: center; gap: 10px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 16px;
  border-top: 1.5px solid var(--line);
  color: #111;
}
/* On dark board colors, switch text/icon to white */
.board-foot.dark { color: #fff; }
/* With the title hidden, center the logo (and drop the count so it sits truly centered) */
.board-foot.no-title { justify-content: center; }
.board-foot.no-title .board-count { display: none; }
.board-foot .board-foot-icon { font-size: 28px; flex-shrink: 0; color: inherit; }
.board-foot .board-foot-title,
.board-foot .board-title-edit {
  flex: 1; min-width: 0; cursor: text;
  color: inherit;
  white-space: pre-wrap;
  overflow-wrap: break-word;
  word-break: break-word;
}
.board-foot .board-title-edit { font: inherit; font-weight: 700; background: transparent; border: none; }
/* El titulo del tablero es ahora el mismo div editable siempre (como el
   titulo grande): sin texto se ve el nombre por defecto en gris, en vez de
   quedarse en blanco. */
.board-foot .board-foot-title:empty::before {
  content: attr(data-placeholder);
  opacity: 0.6;
  pointer-events: none;
}
.board-foot .board-foot-title:focus { outline: none; }

.board-foot .board-count { font-family: var(--font-mono); font-size: 12px; color: inherit; opacity: 0.7; }

/* ── Board inside a column: Milanote-style horizontal card (icon left, name + count right) ── */
.board-in-column { cursor: pointer; }
.board-col-card {
  width: 100%; height: 100%; display: flex; align-items: center; gap: 10px;
  background: var(--paper); border: 1.5px solid var(--line); border-radius: 6px;
  box-shadow: var(--pop-sm); padding: 8px 10px; box-sizing: border-box;
  transition: transform 120ms var(--e-out), box-shadow 120ms var(--e-out);
}
.board-in-column:hover .board-col-card { transform: translateY(-1px); box-shadow: var(--pop-hover); }
.board-col-icon {
  width: 40px; height: 40px; flex-shrink: 0; border-radius: 9px;
  display: grid; place-items: center;
}
.board-col-icon .material-symbols-rounded { font-size: 22px; }
.board-col-meta { flex: 1; min-width: 0; }
.board-col-title { font-family: var(--font-display); font-weight: 700; font-size: 13.5px; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.board-col-title-edit { font-family: var(--font-display); font-weight: 700; font-size: 13.5px; color: var(--ink); width: 100%; background: transparent; border: none; outline: none; padding: 0; }
.board-col-count { font-family: var(--font-mono); font-size: 11px; color: var(--ink-3); margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.board-in-column.editing .board-col-card { outline: 2px solid var(--olive); outline-offset: 1px; }
.board-col-iconpicker {
  position: absolute; top: 44px; left: 0; z-index: 50;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 3px;
  background: var(--paper); border: 1.5px solid var(--line); border-radius: 6px;
  box-shadow: var(--pop); padding: 5px; width: 168px;
}
.board-col-iconopt { width: 36px; height: 36px; display: grid; place-items: center; border-radius: 4px; background: var(--bg-2); cursor: pointer; border: 1.5px solid transparent; }
.board-col-iconopt:hover { background: var(--olive-l); }
.board-col-iconopt.active { border-color: var(--olive); background: var(--olive-l); }
.board-col-iconopt .material-symbols-rounded { font-size: 18px; color: var(--ink); }

/* ── Board compact mode (no preview) — small square: icon + title + count ── */
.board-compact {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px; padding: 14px 12px; text-align: center; color: #111;
}
.board-compact.dark { color: #fff; }
.board-compact-icon { font-size: 38px; flex-shrink: 0; }
.board-compact-title { font-family: var(--font-display); font-weight: 700; font-size: 14px; line-height: 1.2; max-width: 100%; word-break: break-word; }
.board-compact-count { font-family: var(--font-mono); font-size: 10.5px; opacity: 0.7; }

/* Doc — small card on canvas, opens fullscreen modal */
.doc-card .item-card { padding: calc(11px * var(--node-scale, 1)) calc(13px * var(--node-scale, 1)); cursor: pointer; display: flex; flex-direction: column; }
/* Documento sin vista previa: sin caja/rectángulo, solo el logo sobre el lienzo */
.doc-card.doc-compact-mode .item-card { background: transparent !important; border: none !important; box-shadow: none !important; padding: 4px; }
.doc-head { flex-shrink: 0; display: flex; align-items: center; gap: 8px; font-family: var(--font-display); font-weight: 700; font-size: calc(14px * var(--node-scale, 1)); margin-bottom: 7px; }
.doc-head .material-symbols-rounded { font-size: calc(16px * var(--node-scale, 1)); color: var(--wine-texto); }
.doc-body-preview { font-size: calc(12px * var(--node-scale, 1)); color: var(--ink-2); line-height: 1.5; flex: 1; overflow: hidden; }
/* Compact doc (preview off) — just the logo + title, like the file node */
.doc-compact { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: calc(10px * var(--node-scale, 1)); text-align: center; min-height: 0; }
/* Logo del documento: icono + líneas de texto simuladas, sin marco/caja
   (solo el "logo" flotando sobre el fondo del nodo) */
.doc-compact-paper {
  position: relative;
  width: min(52%, 92px);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px;
  overflow: hidden;
}
.doc-compact-icon { font-size: calc(40px * var(--node-scale, 1)); color: var(--wine-texto); }
.doc-compact-lines { width: 78%; display: flex; flex-direction: column; gap: 4px; }
.doc-compact-lines i { display: block; height: 3px; border-radius: 2px; background: color-mix(in srgb, var(--wine) 22%, var(--line-soft, #E5E1DD)); }
.doc-compact-lines i:last-child { width: 60%; }
.doc-compact-title { font-family: var(--font-display); font-weight: 700; font-size: calc(13px * var(--node-scale, 1)); color: var(--ink); line-height: 1.3; word-break: break-word; max-width: 92%; }
.doc-body-preview:empty::before { content: 'Doble clic para escribir…'; color: var(--ink-3); font-style: italic; }
[data-lang="en"] .doc-body-preview:empty::before { content: 'Double-click to write…'; }

/* ── Calendario ──
   Al estilo de los que ya conoce todo el mundo (Notion, Google, Apple): el mes
   como título, rejilla de líneas finas sin cajas, los días de los meses de al
   lado en tenue, hoy en un círculo verde y el día elegido en un aro rojo; y las
   vistas de día, semana, año y agenda de Google.
   Las líneas y los tintes salen de currentColor, la tinta del propio nodo: así
   se ven igual de bien sobre el blanco de siempre, en oscuro o con el nodo
   pintado de cualquier color.
   Tamaños: --cal-texto multiplica lo de dentro y --cal-cabecera (que ya lleva
   dentro el del texto) lo de arriba. Dentro de cada parte todo va en em, así
   que una sola variable mueve la parte entera sin descolocarla. */
.cal-mb .item-card {
  padding: 0 !important;
  display: flex; flex-direction: column;
  --cal-linea: color-mix(in srgb, currentColor 13%, transparent);
}
.cal-mb-head {
  display: flex; align-items: center; gap: calc(8px * var(--node-scale, 1));
  padding: calc(12px * var(--node-scale, 1)) calc(14px * var(--node-scale, 1)) calc(8px * var(--node-scale, 1));
}
.cal-mb-titulo-caja { position: relative; flex: 1; min-width: 0; }
.cal-mb-titulo {
  display: inline-flex; align-items: baseline; gap: 0.3em;
  max-width: 100%;
  padding: 0.1em 0.3em; margin-left: -0.3em;
  border-radius: 6px;
  font-family: var(--font-display);
  font-size: calc(19px * var(--node-scale, 1) * var(--cal-cabecera, 1));
  line-height: 1.15;
  color: inherit;
  white-space: nowrap; overflow: hidden;
  transition: background 100ms;
}
.cal-mb-titulo:hover { background: var(--cal-linea); }
.cal-mb-mes { display: inline-block; font-weight: 800; letter-spacing: -0.02em; overflow: hidden; text-overflow: ellipsis; }
.cal-mb-mes::first-letter { text-transform: uppercase; }
.cal-mb-anio { font-weight: 600; opacity: 0.5; }
.cal-mb-titulo .material-symbols-rounded { font-size: 0.8em; opacity: 0.45; align-self: center; }
.cal-mb-navs { display: flex; align-items: center; gap: calc(4px * var(--node-scale, 1)); flex-shrink: 0; }
.cal-mb-nav {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.1em;
  min-width: 2.2em; height: 2.2em; padding: 0 0.6em;
  border: 1.5px solid var(--cal-linea); border-radius: 6px;
  background: transparent; color: inherit;
  font-size: calc(11px * var(--node-scale, 1) * var(--cal-cabecera, 1));
  font-weight: 700; white-space: nowrap;
  cursor: pointer;
  transition: background 100ms, border-color 100ms;
}
.cal-mb-nav:hover { background: var(--cal-linea); }
.cal-mb-nav .material-symbols-rounded { font-size: 1.45em; }
.cal-mb-vista { padding-right: 0.25em; }

/* Los menús que cuelgan de la cabecera: el de mes y año y el de vistas. */
.cal-mb-selector, .cal-mb-vistas {
  position: absolute; top: calc(100% + 6px); z-index: 20;
  background: var(--paper); color: var(--ink);
  border: 1.5px solid var(--line); border-radius: 8px;
  box-shadow: var(--pop);
  font-size: calc(11.5px * var(--node-scale, 1) * var(--cal-cabecera, 1));
  animation: ctx-slide-in 160ms var(--e-out);
}
.cal-mb-selector { left: -0.3em; width: 17em; padding: 0.8em; }
.cal-mb-vista-caja { position: relative; }
.cal-mb-vistas { right: 0; min-width: 9em; padding: 0.35em; display: flex; flex-direction: column; gap: 2px; }
.cal-mb-vistas button {
  text-align: left; padding: 0.5em 0.7em; border-radius: 6px;
  color: inherit; font-weight: 600; cursor: pointer;
}
.cal-mb-vistas button:hover { background: var(--bg-2); }
.cal-mb-selector-anio {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 0.6em;
  font-family: var(--font-display); font-weight: 800; font-size: 1.2em;
}
.cal-mb-selector-meses { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px; }
.cal-mb-selector-mes {
  padding: 0.55em 0; border-radius: 6px;
  border: 1.5px solid transparent;
  font-weight: 600; color: inherit; text-transform: capitalize;
  cursor: pointer;
}
.cal-mb-selector-mes:hover { background: var(--bg-2); }
.cal-mb-selector-mes.actual { border-color: var(--olive); }
/* El elegido con la pareja de colores puesta a mano, como en la lista de
   lenguajes: --olive-l no cambia en oscuro y el texto se volvía invisible. */
.cal-mb-selector-mes.active, .cal-mb-vistas button.active { background: var(--olive-l); color: var(--ink); font-weight: 800; }

/* ── Mes ── */
.cal-mb-dows {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  padding: 0 calc(14px * var(--node-scale, 1));
}
.cal-mb-dow {
  padding: 0 0.55em 0.45em;
  font-size: calc(10.5px * var(--node-scale, 1) * var(--cal-texto, 1));
  font-weight: 600; text-align: right; text-transform: capitalize;
  opacity: 0.55;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cal-mb-semana-cab { text-align: center; }
.cal-mb-grid {
  flex: 1; min-height: 0;
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  margin: 0 calc(14px * var(--node-scale, 1)) calc(12px * var(--node-scale, 1));
  border-top: 1px solid var(--cal-linea); border-left: 1px solid var(--cal-linea);
  font-size: calc(11.5px * var(--node-scale, 1) * var(--cal-texto, 1));
}
.cal-mb-semana {
  display: flex; justify-content: center; padding-top: 0.55em;
  border-right: 1px solid var(--cal-linea); border-bottom: 1px solid var(--cal-linea);
  font-size: 0.85em; font-weight: 700; opacity: 0.45;
}
.cal-mb-cell {
  position: relative; min-width: 0; min-height: 0;
  display: flex; flex-direction: column; gap: 2px;
  padding: 0.3em 0.35em;
  border-right: 1px solid var(--cal-linea); border-bottom: 1px solid var(--cal-linea);
  overflow: hidden; cursor: pointer;
  transition: background 100ms;
}
.cal-mb-cell.finde { background: color-mix(in srgb, currentColor 3%, transparent); }
.cal-mb-cell:hover { background: color-mix(in srgb, currentColor 7%, transparent); }
.cal-mb-cell.con-color { background: color-mix(in srgb, var(--dia) 32%, transparent); }
.cal-mb-cell.destino { background: color-mix(in srgb, var(--olive) 22%, transparent); box-shadow: inset 0 0 0 1.5px var(--olive); }
.cal-mb-cell.fuera .cal-mb-day { opacity: 0.38; }
.cal-mb-cell.fuera .cal-mb-event { opacity: 0.55; }
.cal-mb-cell.selected-day { box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--wine) 55%, transparent); }
.cal-mb-cell-top {
  display: flex; align-items: center; justify-content: flex-end; gap: 4px;
  min-height: 1.9em; flex-shrink: 0;
  position: relative; z-index: 2;
}
.cal-mb-day {
  display: inline-grid; place-items: center;
  min-width: 1.9em; height: 1.9em; padding: 0 0.35em;
  border-radius: 999px;
  font-weight: 600; font-variant-numeric: tabular-nums;
  color: var(--cal-numero, inherit);
  white-space: nowrap;
  transition: background 100ms;
}
.cal-mb-day:hover { background: var(--cal-linea); }
.cal-mb-cell.today .cal-mb-day { background: var(--olive); color: #1A1A1A; font-weight: 800; }
.cal-mb-cell.selected-day .cal-mb-day {
  box-shadow: inset 0 0 0 1.5px var(--wine); color: var(--wine-texto); font-weight: 800;
  animation: cal-day-pop 260ms var(--e-out);
}
@keyframes cal-day-pop {
  0% { transform: scale(0.86); }
  55% { transform: scale(1.06); }
  100% { transform: scale(1); }
}
/* El "+" de añadir un evento: solo aparece al pasar por la casilla, como en
   Notion, para que la rejilla en reposo sea solo números y eventos. */
.cal-mb-add {
  margin-right: auto;
  width: 1.7em; height: 1.7em;
  display: grid; place-items: center;
  border-radius: 6px; color: inherit;
  opacity: 0; cursor: pointer;
  transition: opacity 100ms, background 100ms;
}
.cal-mb-add .material-symbols-rounded { font-size: 1.35em; }
.cal-mb-cell:hover .cal-mb-add { opacity: 0.7; }
.cal-mb-add:hover { opacity: 1 !important; background: var(--cal-linea); }

/* Un evento: los de día entero, píldora de su color; los que tienen hora, un
   punto, la hora y el título, como en Google. */
.cal-mb-event {
  position: relative; z-index: 2; flex-shrink: 0;
  display: flex; align-items: center; gap: 0.35em;
  padding: 0.15em 0.45em 0.15em 0.5em;
  border-radius: 4px;
  font-size: 0.92em; font-weight: 600; line-height: 1.35;
  white-space: nowrap; overflow: hidden;
  cursor: pointer; touch-action: none;
  transition: background 100ms, opacity 100ms;
}
.cal-mb-event.entero { background: color-mix(in srgb, var(--ev) 24%, transparent); box-shadow: inset 3px 0 0 var(--ev); }
.cal-mb-event.entero:hover { background: color-mix(in srgb, var(--ev) 36%, transparent); }
.cal-mb-event.con-hora:hover { background: var(--cal-linea); }
/* Uno de varios días que sigue en la casilla de al lado: sin la esquina ni el
   filo de ese lado, para que se lea como una sola barra. */
.cal-mb-event.sigue-antes { border-top-left-radius: 0; border-bottom-left-radius: 0; box-shadow: none; }
.cal-mb-event.sigue-despues { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.cal-mb-event.moviendose { opacity: 0.4; }
.cal-mb-event.hecha .cal-mb-texto { text-decoration: line-through; opacity: 0.6; }
.cal-mb-texto { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.cal-mb-hora { flex-shrink: 0; font-weight: 500; opacity: 0.75; font-variant-numeric: tabular-nums; }
.cal-mb-punto { flex-shrink: 0; width: 0.55em; height: 0.55em; border-radius: 50%; background: var(--ev); }
.cal-mb-tarea { flex-shrink: 0; display: inline-grid; place-items: center; color: var(--ev); cursor: pointer; }
.cal-mb-tarea .material-symbols-rounded { font-size: 1.15em; }
.cal-mb-mas {
  position: relative; z-index: 2; align-self: flex-start;
  padding: 0.1em 0.45em; border-radius: 4px;
  font-size: 0.88em; font-weight: 700; color: inherit;
  opacity: 0.7; cursor: pointer;
}
.cal-mb-mas:hover { opacity: 1; background: var(--cal-linea); }

/* Una foto de fondo en el día: la imagen llena la casilla, con una sombra
   arriba para que el número en blanco se lea sobre cualquier foto. */
.cal-mb-cell-img { position: absolute; inset: 0; background-size: cover; background-position: center; }
.cal-mb-cell.has-image::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg, rgba(0,0,0,0.45) 0%, rgba(0,0,0,0) 45%, rgba(0,0,0,0) 70%, rgba(0,0,0,0.3) 100%);
}
.cal-mb-cell.has-image .cal-mb-day { color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,0.6); }
.cal-mb-cell.has-image.today .cal-mb-day { color: #1A1A1A; text-shadow: none; }
.cal-mb-cell.has-image .cal-mb-add,
.cal-mb-cell.has-image .cal-mb-mas { color: #fff; }
.cal-mb-cell.has-image .cal-mb-event { color: #fff; }
.cal-mb-cell.has-image .cal-mb-event.entero { background: var(--ev); box-shadow: 0 1px 3px rgba(0,0,0,0.35); }
.cal-mb-cell.has-image .cal-mb-event.con-hora { background: rgba(0,0,0,0.45); }

/* La lista entera de un día, cuando sus eventos no caben en la casilla. */
.cal-mb-lista {
  position: absolute; z-index: 25;
  left: 50%; top: calc(58px * var(--node-scale, 1));
  width: min(88%, 19em);
  max-height: calc(100% - 70px * var(--node-scale, 1));
  display: flex; flex-direction: column;
  background: var(--paper); color: var(--ink);
  border: 1.5px solid var(--line); border-radius: 8px;
  box-shadow: var(--pop);
  font-size: calc(12px * var(--node-scale, 1) * var(--cal-texto, 1));
  transform: translateX(-50%);
  animation: cal-lista-in 160ms var(--e-out);
}
@keyframes cal-lista-in {
  from { opacity: 0; transform: translate(-50%, 4px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}
/* Pegada a su día: empieza en la casilla y se queda dentro del nodo por los
   dos lados, sin importar en qué columna esté el día. */
.cal-mb-lista.anclada {
  left: clamp(8px, calc(var(--lista-x) - 4px), calc(100% - min(88%, 19em) - 8px));
  max-height: calc(100% - 16px);
  transform: none;
  animation-name: cal-lista-in-anclada;
}
@keyframes cal-lista-in-anclada {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}
.cal-mb-lista-cab {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 0.7em 0.7em 0.5em 0.9em;
  font-family: var(--font-display); font-weight: 800;
}
.cal-mb-lista-cab span { display: inline-block; }
.cal-mb-lista-cab span::first-letter { text-transform: uppercase; }
.cal-mb-lista-cuerpo { display: flex; flex-direction: column; gap: 4px; padding: 0 0.7em 0.7em; overflow-y: auto; }
.cal-mb-lista-cuerpo .cal-mb-event { font-size: 1em; padding: 0.35em 0.6em; white-space: normal; }
.cal-mb-lista-add {
  display: flex; align-items: center; gap: 4px;
  padding: 0.35em 0.5em; border-radius: 4px;
  border: 1.5px dashed var(--line-soft);
  color: var(--ink-2); font-weight: 600; cursor: pointer;
}
.cal-mb-lista-add:hover { background: var(--bg-2); color: var(--ink); }
.cal-mb-lista-add .material-symbols-rounded { font-size: 1.2em; }

/* ── Semana y día: las horas ── */
.cal-horas {
  flex: 1; min-height: 0;
  display: flex; flex-direction: column;
  margin: 0 calc(14px * var(--node-scale, 1)) calc(12px * var(--node-scale, 1));
  font-size: calc(11.5px * var(--node-scale, 1) * var(--cal-texto, 1));
}
.cal-horas-cab, .cal-horas-todo, .cal-horas-rejilla { display: grid; }
.cal-horas-esquina { font-size: 0.8em; font-weight: 700; opacity: 0.45; align-self: end; padding-bottom: 0.4em; }
.cal-horas-dia {
  display: flex; flex-direction: column; align-items: center; gap: 0.1em;
  padding: 0.1em 0 0.4em; color: inherit; cursor: pointer; border-radius: 6px;
}
.cal-horas-dia:hover { background: var(--cal-linea); }
.cal-horas-dia-nombre { font-size: 0.85em; font-weight: 600; opacity: 0.6; text-transform: capitalize; }
.cal-horas-dia-num {
  display: inline-grid; place-items: center;
  min-width: 1.9em; height: 1.9em; border-radius: 999px;
  font-size: 1.3em; font-weight: 700;
}
.cal-horas-dia.today .cal-horas-dia-num { background: var(--olive); color: #1A1A1A; }
.cal-horas-todo { border-top: 1px solid var(--cal-linea); border-bottom: 1.5px solid var(--cal-linea); }
.cal-horas-etiqueta { font-size: 0.75em; font-weight: 600; opacity: 0.5; padding: 0.4em 0.3em 0 0; text-align: right; }
.cal-horas-todo-dia {
  display: flex; flex-direction: column; gap: 2px; min-width: 0; min-height: 1.9em;
  padding: 2px; border-left: 1px solid var(--cal-linea);
  max-height: 5.4em; overflow-y: auto;
}
.cal-horas-cuerpo { flex: 1; min-height: 0; overflow-y: scroll; overscroll-behavior: contain; }
/* ── Las barras de desplazamiento del calendario ──
   Finas y del color de las líneas del propio nodo, en vez de la barra blanca
   del sistema, que en oscuro era un tablón.
   Y lo importante: la cabecera de los días y la fila de "todo el día" reservan
   el MISMO hueco que la barra de las horas (una barra invisible del mismo
   ancho). Sin eso, la barra solo le quitaba ancho a las horas y cada columna de
   arriba caía unos píxeles a la derecha de la suya, cada vez más hacia el
   domingo (lo vio el usuario). Van con ::-webkit-scrollbar y NO con
   scrollbar-width: si se pone la segunda, Chromium ignora la primera y los
   anchos dejarían de ser iguales. */
.cal-horas-cab, .cal-horas-todo { overflow-y: scroll; }
.cal-mb ::-webkit-scrollbar { width: 8px; height: 8px; }
.cal-mb ::-webkit-scrollbar-track { background: transparent; }
.cal-mb ::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, currentColor 26%, transparent);
  border-radius: 4px;
  border: 2px solid transparent; background-clip: padding-box;
}
.cal-mb ::-webkit-scrollbar-thumb:hover { background-color: color-mix(in srgb, currentColor 42%, transparent); }
.cal-horas-cab::-webkit-scrollbar-thumb, .cal-horas-todo::-webkit-scrollbar-thumb { background: transparent; }
.cal-horas-rejilla { position: relative; height: calc(24 * 3.4em); }
.cal-horas-regla { position: relative; }
.cal-horas-marca {
  height: calc(100% / 24);
  font-size: 0.75em; font-weight: 600; opacity: 0.5;
  text-align: right; padding-right: 0.5em;
  transform: translateY(-0.6em);
  font-variant-numeric: tabular-nums;
}
/* Las líneas de cada hora, pintadas como fondo: veinticuatro elementos por
   columna para una raya no merecen la pena. */
.cal-horas-col {
  position: relative; min-width: 0;
  border-left: 1px solid var(--cal-linea);
  background-image: linear-gradient(to bottom, var(--cal-linea) 1px, transparent 1px);
  background-size: 100% calc(100% / 24);
  cursor: pointer;
}
.cal-horas-col.finde { background-color: color-mix(in srgb, currentColor 3%, transparent); }
.cal-horas-evento {
  position: absolute; z-index: 2; overflow: hidden;
  display: flex; flex-direction: column;
  padding: 0.2em 0.4em;
  border-radius: 5px;
  background: color-mix(in srgb, var(--ev) 30%, var(--paper));
  box-shadow: inset 3px 0 0 var(--ev), 0 0 0 1px color-mix(in srgb, var(--ev) 40%, transparent);
  color: var(--ink);
  font-size: 0.9em; line-height: 1.25;
  cursor: grab; touch-action: none;
}
.cal-horas-evento.moviendose { z-index: 5; opacity: 0.85; box-shadow: inset 3px 0 0 var(--ev), var(--pop); cursor: grabbing; }
.cal-horas-evento.hecha .cal-horas-evento-titulo { text-decoration: line-through; opacity: 0.6; }
.cal-horas-evento-titulo { display: flex; align-items: center; gap: 0.3em; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cal-horas-evento-hora { font-size: 0.9em; opacity: 0.75; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cal-horas-estirar { position: absolute; left: 0; right: 0; bottom: 0; height: 6px; cursor: ns-resize; }
/* La hora de ahora: una raya roja con su punto, como en Google. */
.cal-horas-ahora { position: absolute; left: -1px; right: 0; height: 2px; background: var(--wine); z-index: 4; pointer-events: none; }
.cal-horas-ahora::before { content: ''; position: absolute; left: -5px; top: -4px; width: 10px; height: 10px; border-radius: 50%; background: var(--wine); }

/* ── Año ── */
.cal-anio {
  flex: 1; min-height: 0; overflow-y: auto;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(11em, 1fr)); gap: 1em 1.2em;
  padding: 0.2em calc(14px * var(--node-scale, 1)) calc(12px * var(--node-scale, 1));
  font-size: calc(10.5px * var(--node-scale, 1) * var(--cal-texto, 1));
  align-content: start;
}
.cal-anio-titulo {
  display: block; margin-bottom: 0.3em; padding: 0.1em 0.2em; border-radius: 4px;
  font-family: var(--font-display); font-weight: 800; font-size: 1.25em;
  color: inherit; text-transform: capitalize; cursor: pointer;
}
.cal-anio-titulo:hover { background: var(--cal-linea); }
.cal-anio-rejilla { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 1px; text-align: center; }
.cal-anio-dow { font-size: 0.85em; font-weight: 700; opacity: 0.45; text-transform: uppercase; }
.cal-anio-dia {
  aspect-ratio: 1; display: grid; place-items: center;
  border-radius: 50%; color: inherit; font-variant-numeric: tabular-nums; cursor: pointer;
}
.cal-anio-dia:hover { background: var(--cal-linea); }
.cal-anio-dia.con-eventos { font-weight: 800; box-shadow: inset 0 -2px 0 color-mix(in srgb, var(--olive) 80%, transparent); }
.cal-anio-dia.today { background: var(--olive); color: #1A1A1A; font-weight: 800; box-shadow: none; }

/* ── Agenda ── */
.cal-agenda, .cal-agenda-vacia {
  flex: 1; min-height: 0; overflow-y: auto;
  padding: 0 calc(14px * var(--node-scale, 1)) calc(12px * var(--node-scale, 1));
  font-size: calc(11.5px * var(--node-scale, 1) * var(--cal-texto, 1));
}
.cal-agenda-vacia { display: grid; place-items: center; opacity: 0.55; font-weight: 600; }
.cal-agenda-dia { display: grid; grid-template-columns: 4.2em minmax(0, 1fr); gap: 0.6em; padding: 0.55em 0; border-top: 1px solid var(--cal-linea); }
.cal-agenda-fecha { display: flex; align-items: baseline; gap: 0.3em; color: inherit; cursor: pointer; align-self: start; flex-wrap: wrap; text-align: left; }
.cal-agenda-num { font-size: 1.5em; font-weight: 800; font-family: var(--font-display); min-width: 1.4em; }
.cal-agenda-dia.today .cal-agenda-num { color: var(--olive-texto); }
.cal-agenda-dow { font-size: 0.8em; font-weight: 600; opacity: 0.6; text-transform: uppercase; }
.cal-agenda-lista { display: flex; flex-direction: column; gap: 2px; }
.cal-agenda-evento {
  display: flex; align-items: center; gap: 0.55em; flex-wrap: wrap;
  padding: 0.35em 0.5em; border-radius: 6px; cursor: pointer;
}
.cal-agenda-evento:hover { background: var(--cal-linea); }
.cal-agenda-evento.hecha .cal-agenda-texto { text-decoration: line-through; opacity: 0.6; }
.cal-agenda-hora { min-width: 7.5em; opacity: 0.7; font-variant-numeric: tabular-nums; }
.cal-agenda-texto { font-weight: 700; }
.cal-agenda-lugar { opacity: 0.6; font-size: 0.9em; }

/* ── El menú lateral de un día y su color ── */
.cal-menu-fecha {
  padding: 2px 6px 4px;
  font-family: var(--font-mono); font-size: 9px; font-weight: 700;
  color: var(--ink-3); text-transform: uppercase; text-align: center;
}
.ctx-popout.cal-dia-color { position: fixed; top: 96px; left: 100px; z-index: 203; }
.cal-menu-sin-color {
  display: flex; align-items: center; gap: 6px; margin-top: 10px;
  padding: 6px 8px; border-radius: 2px; border: 1.5px solid var(--line-soft);
  color: var(--ink-2); font-size: 12px; font-weight: 600; cursor: pointer;
}
.cal-menu-sin-color:hover { background: var(--bg-2); color: var(--ink); }
.cal-menu-sin-color .material-symbols-rounded { font-size: 16px; }

/* ── El editor de un evento ──
   Un panel al lado de la barra, como los demás de la aplicación, con todo lo
   del editor de Google en una columna. Los botones: gris, y rojo para borrar. */
.cal-editor-fondo { position: fixed; inset: 0; z-index: 201; }
.cal-editor {
  position: fixed; top: 96px; left: 14px; z-index: 202;
  width: 360px; max-height: calc(100vh - 112px); max-height: calc(100dvh - 112px);
  overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin;
  display: flex; flex-direction: column; gap: 10px;
  padding: 10px 14px 14px;
  background: var(--paper); color: var(--ink);
  border: 1.5px solid var(--line); border-radius: 2px;
  box-shadow: var(--pop);
  font-size: 13px;
  animation: ctx-slide-in 200ms var(--e-out);
}
.cal-editor-cab { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.cal-editor-icono {
  display: grid; place-items: center; width: 30px; height: 30px; flex-shrink: 0;
  border-radius: 2px; color: var(--ink-2); cursor: pointer;
}
.cal-editor-icono:hover { background: var(--bg-2); color: var(--ink); }
.cal-editor-icono .material-symbols-rounded { font-size: 18px; }
.cal-editor-tipos { display: flex; border: 1.5px solid var(--line-soft); border-radius: 6px; overflow: hidden; }
.cal-editor-tipos button { padding: 5px 12px; font-size: 12px; font-weight: 700; color: var(--ink-2); cursor: pointer; }
.cal-editor-tipos button.active { background: var(--olive-l); color: var(--ink); }
.cal-editor-titulo {
  width: 100%; padding: 6px 2px;
  border-bottom: 2px solid var(--line-soft);
  font-family: var(--font-display); font-size: 20px; font-weight: 800; letter-spacing: -0.01em;
  color: var(--ink);
}
.cal-editor-titulo:focus { border-bottom-color: var(--olive); }
.cal-editor-bloque { display: flex; align-items: flex-start; gap: 10px; }
.cal-editor-bloque > .material-symbols-rounded { font-size: 18px; color: var(--ink-3); margin-top: 6px; flex-shrink: 0; }
.cal-editor-col { display: flex; flex-direction: column; gap: 6px; flex: 1; min-width: 0; }
.cal-editor-fila { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.cal-editor-campo {
  min-width: 0; padding: 5px 7px;
  border: 1.5px solid var(--line-soft); border-radius: 2px;
  background: var(--paper-2); color: var(--ink);
  font-size: 12.5px; font-weight: 500;
  color-scheme: light dark;
}
.cal-editor-campo:focus { border-color: var(--olive); }
select.cal-editor-campo { cursor: pointer; }
.cal-editor-num { width: 58px; }
.cal-editor-ancho { flex: 1; width: 100%; }
.cal-editor-notas { min-height: 64px; resize: vertical; line-height: 1.4; }
.cal-editor-guion { color: var(--ink-3); }
.cal-editor-etiqueta { font-size: 12px; font-weight: 600; color: var(--ink-2); }
.cal-editor-check { cursor: pointer; font-size: 12.5px; font-weight: 600; color: var(--ink-2); }
.cal-editor-check input { width: 15px; height: 15px; accent-color: var(--olive); cursor: pointer; }
.cal-editor-dias { display: flex; gap: 4px; }
.cal-editor-dias button {
  width: 26px; height: 26px; border-radius: 50%;
  border: 1.5px solid var(--line-soft);
  font-size: 11px; font-weight: 700; color: var(--ink-2); text-transform: uppercase; cursor: pointer;
}
.cal-editor-dias button.active { background: var(--olive); border-color: var(--olive); color: var(--olive-ink); }
.cal-editor-mas {
  align-self: flex-start; padding: 4px 0;
  font-size: 12.5px; font-weight: 700; color: var(--ink-2); cursor: pointer;
}
.cal-editor-mas:hover { color: var(--ink); text-decoration: underline; }
.cal-editor-pie, .cal-editor-borrar { display: flex; gap: 8px; flex-wrap: wrap; padding-top: 6px; border-top: 1.5px solid var(--line-soft); }
.cal-editor-borrar { flex-direction: column; }
.cal-editor-boton {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 7px 12px;
  border: 1.5px solid var(--line); border-radius: 2px;
  background: var(--paper); color: var(--ink-2);
  box-shadow: 1px 1px 0 var(--line);
  font-size: 12.5px; font-weight: 700; cursor: pointer;
}
.cal-editor-boton:hover { background: var(--bg-2); color: var(--ink); }
.cal-editor-boton .material-symbols-rounded { font-size: 16px; }
.cal-editor-boton.peligro { color: var(--wine-texto); border-color: var(--wine); box-shadow: 1px 1px 0 var(--wine); }
.cal-editor-boton.peligro:hover { background: color-mix(in srgb, var(--wine) 12%, transparent); }
/* En el teléfono, abajo y de lado a lado, como los demás paneles. */
html[data-mobile="1"] .cal-editor {
  top: auto; bottom: 8px; left: 8px; right: 8px; width: auto;
  max-height: 72vh; max-height: 72dvh;
}
html[data-mobile="1"] .ctx-popout.cal-dia-color { top: auto; bottom: 8px; left: 8px; right: 8px; width: auto; }

/* Day context menu — positioned lower so it doesn't cover the top toolbar */
.ctx-side.ctx-side-day { position: fixed; top: 96px; left: 14px; z-index: 202; }
/* Aquí vivían .text-color-grid y .text-color-swatch: la rejilla de siete
   columnas y sus casillas, de cuando el color del texto se elegía con siete
   círculos escritos a mano. Los eligió el selector único hace tiempo, y la
   rejilla se quedó encajando ese selector en una columna de treinta píxeles,
   que es lo que hacía que el panel saliera estirado hacia abajo. */
/* --fuente-nodo: la tipografía elegida para esa nota (Fuentes.jsx). Tiene que
   ir aquí y no solo en .note-inner: esta regla pesa más y la pisaba. */
.note .note-inner.rich, .note .note-edit.rich {
  padding: 10px 12px;
  font-family: var(--fuente-nodo, var(--font-body));
  line-height: 1.45;
  overflow: auto;
  outline: none;
  white-space: normal;
  word-break: break-word;
}
.note .note-edit.rich:empty::before {
  content: attr(data-placeholder);
  color: var(--ink-3);
  font-style: italic;
  pointer-events: none;
}
.note-inner.rich h1, .note-edit.rich h1 {
  font-family: var(--fuente-nodo, var(--font-display));
  /* Multiplica por --text-scale para que los botones A+/A− funcionen también
     sobre el texto con formato de Título/Subtítulo */
  font-size: calc(22px * var(--vista-escala, var(--text-scale, 1)));
  font-weight: 800;
  line-height: 1.1;
  margin: 4px 0 6px;
  letter-spacing: -0.02em;
}
.note-inner.rich h2, .note-edit.rich h2 {
  font-family: var(--fuente-nodo, var(--font-display));
  font-size: calc(17px * var(--vista-escala, var(--text-scale, 1)));
  font-weight: 700;
  line-height: 1.2;
  margin: 4px 0 4px;
}
.note-inner.rich ul, .note-edit.rich ul {
  list-style: disc;
  padding-left: 20px;
  margin: 4px 0;
}
.note-inner.rich ol, .note-edit.rich ol {
  list-style: decimal;
  padding-left: 22px;
  margin: 4px 0;
}
.note-inner.rich li, .note-edit.rich li { margin: 2px 0; }
.note-inner.rich blockquote, .note-edit.rich blockquote {
  border-left: 3px solid currentColor;
  opacity: 0.85;
  padding: 2px 0 2px 10px;
  margin: 4px 0;
  font-style: italic;
}
.note-inner.rich pre, .note-edit.rich pre {
  font-family: var(--font-mono);
  font-size: 12px;
  background: #f6f8fa;
  color: #24292e;
  padding: 8px 10px;
  border-radius: 2px;
  margin: 4px 0;
  white-space: pre-wrap;
  border: 1px solid rgba(0,0,0,0.08);
}
.note-inner.rich pre code, .note-edit.rich pre code {
  background: transparent !important;
  padding: 0 !important;
  border-radius: 0 !important;
  font-size: 12px;
  display: block;
}
/* Always leave a clickable paragraph after a code block so the user can
   click below to continue writing normal text. */
.note-edit.rich pre + p,
.note-inner.rich pre + p {
  min-height: 1.5em;
  margin: 4px 0;
  cursor: text;
}
.note-inner.rich code, .note-edit.rich code {
  font-family: var(--font-mono);
  font-size: 12px;
  background: rgba(175, 184, 193, 0.2);
  padding: 1px 5px;
  border-radius: 2px;
}

.image-change-btn {
  position: absolute;
  top: calc(6px * var(--node-scale, 1)); right: calc(6px * var(--node-scale, 1));
  width: calc(30px * var(--node-scale, 1)); height: calc(30px * var(--node-scale, 1));
  border-radius: 2px;
  display: grid; place-items: center;
  background: rgba(255,255,255,0.92);
  border: 1.5px solid var(--line);
  box-shadow: 1px 1px 0 var(--line);
  opacity: 0;
  transition: opacity 140ms;
}
.image-card:hover .image-change-btn { opacity: 1; }
.image-change-btn:hover { background: white; transform: translate(-1px, -1px); box-shadow: 2px 2px 0 var(--line); }
.image-change-btn .material-symbols-rounded { font-size: calc(16px * var(--node-scale, 1)); color: var(--brand-gray-dark, #1A1A1A); }
[data-theme="dark"] .image-change-btn { background: rgba(30, 30, 30, 0.92); }
[data-theme="dark"] .image-change-btn:hover { background: rgba(45, 45, 45, 1); }
[data-theme="dark"] .image-change-btn .material-symbols-rounded { color: #FAF9F6; }
.image-card.drag-over .item-card { outline: 2px dashed var(--olive); outline-offset: 2px; background: var(--olive-l); }

/* Cover picks — vibrant with checkmark on select */
.cover-pick {
  position: relative;
  width: 50px; height: 36px;
  border-radius: 2px;
  border: 1.5px solid var(--line);
  cursor: pointer;
  transition: transform 120ms var(--e-out);
  overflow: hidden;
}
.cover-pick:hover { transform: translateY(-2px) scale(1.04); }
/* El de subir una imagen: hueco con borde de trazos, que se lee como "pon
   aquí algo tuyo" y no como un color más de la lista. */
.cover-pick.cover-subir {
  display: grid; place-items: center;
  background: var(--paper-2);
  border-style: dashed;
  color: var(--ink-2);
}
.cover-pick.cover-subir .material-symbols-rounded { font-size: 20px; }
.cover-pick.cover-subir:hover { color: var(--ink); background: var(--paper); }
.cover-pick.active {
  outline: 3px solid var(--olive);
  outline-offset: 2px;
}
.cover-pick.active::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'><circle cx='12' cy='12' r='9' fill='white' stroke='%231A1A1A' stroke-width='1.5'/><path d='M7 12 L11 16 L17 9' stroke='%234E5D32' stroke-width='2.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-position: center;
  background-repeat: no-repeat;
  background-size: 20px;
}
.emoji-pick.active {
  outline: 3px solid var(--olive);
  outline-offset: 2px;
  background: var(--olive-l);
  border-color: var(--olive);
}

/* Table */
.table-card .item-card { padding: 0 !important; background: transparent !important; border: none !important; box-shadow: none !important; display: flex; }
.tbl-box { border: 1.5px solid var(--line); border-radius: 2px; flex: 1 1 auto; height: 100%; background: var(--paper); display: flex; flex-direction: column; position: relative; }
.tbl-colhead-row { display: grid; flex-shrink: 0; border-bottom: 1.5px solid var(--line); background: var(--paper); }
.tbl-corner { background: var(--paper); border-right: 1px solid var(--line-soft); }
.tbl-colhead { padding: 6px 4px; font-family: var(--font-mono); font-size: 12px; font-weight: 700; color: var(--ink-2); text-align: center; border-right: 1px solid var(--line-soft); user-select: none; }
.tbl-colhead:last-child { border-right: none; }
.tbl-colhead.active { background: var(--ink-2) !important; color: white; }
.tbl-title-row { flex-shrink: 0; padding: 6px 8px; background: var(--paper); border-bottom: 1.5px solid var(--line); display: flex; align-items: center; justify-content: center; }
.tbl-title { font-family: var(--font-display); font-weight: 700; font-size: 15px; text-align: center; background: transparent; border: none; flex: 1; color: var(--ink); }
.tbl-title::placeholder { color: var(--ink-3); font-style: italic; }
.tbl-grid { background: var(--paper); flex: 1 1 auto; display: flex; flex-direction: column; overflow: hidden; }
.tbl-row { display: grid; border-bottom: 1px solid var(--line-soft); min-height: 30px; flex: 1 1 0; }
.tbl-row:last-child { border-bottom: none; }
.tbl-rownum { background: var(--paper); border-right: 1.5px solid var(--line); display: grid; place-items: center; font-family: var(--font-mono); font-size: 11px; color: var(--ink-3); user-select: none; }
.tbl-rownum.active { background: var(--ink-2) !important; color: white; }
.tbl-cell { position: relative; padding: 4px 6px; border-right: 1px solid var(--line-soft); font-size: 14px; cursor: text; min-height: 30px; display: flex; align-items: center; overflow: visible; }
/* Until the table node is selected, the grid is inert so a first click selects/drags
   the whole node (only after it's selected do cells become interactive). */
.item:not(.selected) .tbl-box { pointer-events: none; }
.tbl-cell.header-row { font-weight: 600; }
.tbl-cell:last-child { border-right: none; }
.tbl-cell.selected { box-shadow: inset 0 0 0 9999px color-mix(in srgb, var(--olive) 16%, transparent); }
.tbl-cell.focus { outline: 2px solid var(--ink); outline-offset: -2px; z-index: 2; }
.tbl-cell-view { width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; pointer-events: none; }
.tbl-cell-input { width: 100%; border: none; background: transparent; font: inherit; padding: 0; color: inherit; outline: none; }
.tbl-caption-row { flex-shrink: 0; padding: 10px 12px; background: var(--paper); border-top: 1.5px solid var(--line-soft); }
.tbl-caption { width: 100%; background: transparent; border: none; font-size: 12px; color: var(--ink-3); text-align: center; }
.tbl-caption::placeholder { color: var(--ink-3); font-style: italic; }

/* Formula autocomplete dropdown (rendered via portal, fixed-positioned) */
.tbl-formula-suggest {
  background: var(--paper);
  border: 1.5px solid var(--line);
  border-radius: 2px;
  box-shadow: var(--pop);
  min-width: 140px;
  max-height: 240px;
  overflow-y: auto;
  z-index: 300;
}
/* Highlight cells referenced inside a formula being built */
.tbl-cell.ref-highlight { outline: 2px dashed var(--olive); outline-offset: -2px; background: var(--olive-l) !important; z-index: 1; }
.tbl-formula-suggest-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 6px 10px;
  background: transparent;
  border: none;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  color: var(--ink);
}
.tbl-formula-suggest-item:hover,
.tbl-formula-suggest-item.active { background: var(--olive-l); }
.tbl-formula-suggest-item .desc { display: block; font-family: var(--font-body); font-weight: 400; font-size: 10px; color: var(--ink-3); margin-top: 2px; }
.tbl-formula-help {
  padding: 6px 10px;
  border-top: 1px solid var(--line-soft);
  font-size: 10px;
  color: var(--ink-3);
  font-style: italic;
  text-align: center;
}

/* Comment */
/* El comentario es una tarjeta crema, clara en los dos temas (--c-cream no
   cambia en oscuro). Su texto no puede seguir al tema: un comentario nuevo nace
   sin color propio —las notas nacen blancas—, así que su tinta era la del tema,
   casi blanca en modo oscuro, y lo escrito desaparecía sobre el crema.
   Encontrado probando la aplicación en oscuro. El mismo arreglo que ya tiene la
   tarjeta de archivo: dentro de la tarjeta se clavan los valores del tema claro.
   Si alguien le pone un color oscuro, su texto sigue saliendo en blanco, porque
   ese se pone directamente en el propio nodo. */
.comment-card {
  --ink:   #1A1A1A;
  --ink-2: #595459;
  --ink-3: #8E8A8E;
}
.comment-card .item-card { background: var(--c-cream); padding: 9px 11px; display: flex; flex-direction: column; gap: 6px; }
.comment-head { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.comment-avatar { width: 24px; height: 24px; border-radius: 50%; border: 1.5px solid var(--line); flex-shrink: 0; display: grid; place-items: center; font-weight: 700; font-size: 10px; }
.comment-body { flex: 1; min-width: 0; }
.comment-name { font-size: 11px; font-weight: 700; }
.comment-text { font-size: 12px; line-height: 1.35; }
/* Comment body reuses the Note rich styles but without the note's own padding */
.comment-rich { flex: 1; min-height: 0; overflow: auto; padding: 0; font-size: 12px; line-height: 1.4; }
.comment-rich.note-edit, .comment-rich.note-inner { padding: 0; }
.comment-rich:empty::before { content: attr(data-placeholder); color: var(--ink-3); font-style: italic; pointer-events: none; }

/* ============================================
   CONNECTORS
   ============================================ */
/* Lines layer sits BELOW the nodes (items use z-index 2, frames 1)
   so arrows never paint over a node. */
.connectors { position: absolute; inset: 0; pointer-events: none; overflow: visible; z-index: 3; }
/* Handles layer sits ABOVE every node so the center anchors stay grabbable. */
.connectors-top { z-index: 110; }
/* La raya que se ve NO coge el ratón: va pintada encima de su zona de agarre
   (.connector-hit, 18 px de ancho) y, cogiéndolo ella, un clic justo encima
   de la raya —que es donde uno pulsa— no llegaba a nada y la flecha no se
   seleccionaba. Solo funcionaba pulsando un poco al lado. */
.connector-path { fill: none; stroke: var(--ink); stroke-width: 2; stroke-linecap: round; pointer-events: none; }
.connector-path.selected { stroke: var(--wine); stroke-width: 3; }
.connector-hit { fill: none; stroke: transparent; stroke-width: 18; pointer-events: stroke; cursor: pointer; }
.connector-handle { fill: var(--wine); stroke: var(--paper); stroke-width: 2; pointer-events: auto; cursor: grab; }
/* El candado de una flecha bloqueada (Connector.jsx): en su centro, sin tiradores. */
/* Un botón de la barra que no se puede usar ahora (la forma de una flecha
   bloqueada): apagado, para que no parezca que no responde. */
.ctx-btn:disabled { opacity: 0.38; cursor: not-allowed; }
.connector-candado-fondo { fill: var(--paper); stroke: var(--line, #1E1A1D); stroke-width: 1.5; }
.connector-candado { fill: var(--ink, #1A1A1A); }
.connector-candado-arco { fill: none; stroke: var(--ink, #1A1A1A); stroke-width: 1.6; stroke-linecap: round; }
.connector-handle.endpoint { fill: var(--paper); stroke: var(--wine); stroke-width: 2.5; }
/* Orthogonal (Miro-style) editing handles */
.connector-handle.waypoint { fill: var(--wine); stroke: var(--paper); stroke-width: 2; }
/* El enganche: relleno, para distinguirlo del tirador hueco del centro (que
   cambia la flecha de nodo). Este solo se pasea por el borde de su nodo. */
.connector-handle.anchor-slide { fill: var(--olive); stroke: var(--paper); stroke-width: 2; cursor: move; }
/* Crece al pasar por encima sin fijar un radio: el radio va en proporción al
   zoom (ver Connector.jsx) y uno fijo lo encogía con el zoom alejado. */
.connector-handle.anchor-slide:hover, .connector-handle.seg-move:hover { transform: scale(1.3); transform-box: fill-box; transform-origin: center; }
.connector-handle.seg-move { fill: var(--paper); stroke: var(--wine); stroke-width: 2.5; }
.connector-handle.seg-move:hover { fill: var(--wine); }

/* ── Las líneas, con el dedo ──
   Un tirador de 8px de radio se apunta bien con un ratón, que señala un punto
   exacto. Con el dedo es imposible: la yema cubre unos 40px y tapa justo lo que
   quiere tocar. Aquí crecen los tiradores y, sobre todo, la franja invisible con
   la que se agarra la línea — que es lo que quita la necesidad de puntería. En
   el escritorio no cambia nada. */
html[data-mobile="1"] .connector-handle { r: 13; stroke-width: 2.5; }
html[data-mobile="1"] .connector-handle.waypoint { r: 12; }
html[data-mobile="1"] .connector-handle.anchor-slide,
html[data-mobile="1"] .connector-handle.anchor-slide:hover { r: 12; }
html[data-mobile="1"] .connector-hit { stroke-width: 40; }
.arrowhead { fill: var(--ink); pointer-events: none; }
.connector-path.selected ~ .arrowhead { fill: var(--olive); }
/* Dotted "covered" segment (center → node edge), drawn on top of the node */
.connector-covered { fill: none; stroke-width: 2; stroke-dasharray: 1 5; stroke-linecap: round; opacity: 0.55; pointer-events: none; }
/* Connector label chip */
.connector-label {
  display: inline-block;
  background: var(--ink);
  color: var(--paper);
  font-size: 11px; font-weight: 600;
  padding: 2px 8px;
  border-radius: 2px;
  white-space: nowrap;
  border: 1.5px solid var(--line);
  pointer-events: none;
}

/* ============================================
   CONTEXT SIDEBAR (left side when item selected)
   ============================================ */
.ctx-side {
  position: absolute;
  top: 96px; left: 14px;
  background: var(--menu-fondo);
  border: 1.5px solid var(--line);
  border-radius: 2px;
  box-shadow: var(--pop);
  padding: 6px;
  display: flex; flex-direction: column;
  gap: 2px;
  z-index: 70;
  /* 86 y no 76: con el selector de color dentro, setenta y seis se quedaban
     cortos y las casillas se salian del panel. Diez pixeles mas y entran, y de
     paso respiran las etiquetas de los botones. */
  width: 86px;
  animation: ctx-slide-in 180ms var(--e-out);
  /* En una ventana baja, las barras largas (la de formato de texto tiene
     dieciséis botones) se salían por debajo de la pantalla y no había manera
     de llegar a las últimas opciones. Ahora se desplaza por dentro.
     El móvil no entra aquí: allí la barra es horizontal y ya se desplaza a lo
     ancho, y su regla está más abajo en este archivo. */
  max-height: calc(100vh - 112px);
  max-height: calc(100dvh - 112px);
  overflow-y: auto;
  overscroll-behavior: contain;
  /* Una barra de desplazamiento fina: la normal se comería la etiqueta de los
     botones, que son estrechos. */
  scrollbar-width: thin;
  scrollbar-color: var(--line-soft) transparent;
}
.ctx-side::-webkit-scrollbar { width: 6px; }
.ctx-side::-webkit-scrollbar-thumb { background: var(--line-soft); border-radius: 3px; }
.ctx-side::-webkit-scrollbar-track { background: transparent; }

/* Los paneles que se abren al lado tienen el mismo problema: el de iconos o el
   de emojis no cabe en una pantalla baja. */
.ctx-popout {
  max-height: calc(100vh - 112px);
  max-height: calc(100dvh - 112px);
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
}
@keyframes ctx-slide-in {
  from { opacity: 0; transform: translateX(-6px); }
  to   { opacity: 1; transform: none; }
}
.ctx-side.text-format { top: 96px; left: 14px; }

.ctx-close {
  display: grid; place-items: center;
  width: 100%; height: 28px;
  margin-bottom: 4px;
  border-radius: 2px;
  color: var(--ink-2);
  transition: background 100ms;
}
.ctx-close:hover { background: var(--bg-2); color: var(--ink); }
.ctx-close .material-symbols-rounded { font-size: 18px; }

.ctx-btn {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 8px 4px 6px;
  border-radius: 2px;
  font-size: 10px;
  font-weight: 600;
  color: var(--ink-2);
  background: transparent;
  transition: background 100ms, color 100ms;
  position: relative;
  cursor: pointer;
}
.ctx-btn:hover { background: var(--menu-hover); color: var(--ink); }
.ctx-btn.active { background: var(--olive-l); color: var(--ink); }
.ctx-btn.danger:hover { background: color-mix(in srgb, var(--wine) 14%, transparent); color: var(--wine-texto); }

/* ── El tamaño de letra, como en Word ──
   Un número a la vista con su flecha; al tocarlo se abre su panel al lado de la
   barra, como el del color. El número va en letra de ancho fijo para que no
   baile al pasar de 9 a 12. */
.ctx-tamano { cursor: pointer; }
.ctx-tamano-num {
  display: inline-flex; align-items: center; justify-content: center; gap: 1px;
  min-width: 42px; height: 26px; padding: 0 2px 0 7px;
  border: 1.5px solid var(--line-soft); border-radius: 6px;
  background: var(--paper);
  font-family: var(--font-mono); font-size: 12.5px; font-weight: 700;
  font-variant-numeric: tabular-nums; color: var(--ink);
}
.ctx-btn .ctx-tamano-num .material-symbols-rounded { font-size: 16px; color: var(--ink-3); }
.ctx-tamano:hover .ctx-tamano-num { border-color: var(--line); }
.ctx-tamano.active .ctx-tamano-num { border-color: var(--olive); }

/* El panel: el campo con − y + a los lados, y los tamaños de siempre en una
   rejilla de cuatro, que cabe entera sin desplazarse. */
.ctx-tamano-fila { display: flex; align-items: center; gap: 6px; margin-bottom: 10px; }
.ctx-tamano-campo {
  flex: 1; min-width: 0; height: 34px;
  text-align: center;
  border: 1.5px solid var(--line); border-radius: 2px;
  background: var(--paper-2); color: var(--ink);
  font-family: var(--font-mono); font-size: 15px; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.ctx-tamano-campo:focus { border-color: var(--olive); }
.ctx-tamano-paso {
  width: 34px; height: 34px; flex-shrink: 0;
  display: grid; place-items: center;
  border: 1.5px solid var(--line); border-radius: 2px;
  background: var(--paper); color: var(--ink-2);
  box-shadow: 1px 1px 0 var(--line);
  cursor: pointer;
  transition: background 100ms, color 100ms;
}
.ctx-tamano-paso:hover { background: var(--bg-2); color: var(--ink); }
.ctx-tamano-paso .material-symbols-rounded { font-size: 18px; }
.ctx-tamano-rejilla { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 5px; }
.ctx-tamano-op {
  height: 32px;
  border: 1.5px solid var(--line-soft); border-radius: 2px;
  background: var(--paper); color: var(--ink-2);
  font-family: var(--font-mono); font-size: 12.5px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: background 100ms, border-color 100ms, color 100ms;
}
.ctx-tamano-op:hover { background: var(--bg-2); border-color: var(--line); color: var(--ink); }
/* El elegido, con la pareja de colores de la lista de lenguajes y por lo mismo:
   --olive-l no cambia en oscuro y --ink sí, y el número salía blanco sobre verde
   claro. Visto probando en modo oscuro. */
.ctx-tamano-op.active { background: var(--olive-l); border-color: var(--olive); color: var(--ink); }
.ctx-tamano-pie { margin-top: 10px; font-size: 11px; line-height: 1.35; color: var(--ink-3); }

/* La vista previa de la leyenda: su tamaño normal lo pone la hoja de estilos
   según el tipo de nodo, así que para enseñar otro hay que ganarle aquí. Solo
   mientras el ratón está encima de un tamaño del panel. */
[data-vista-leyenda] .node-caption { font-size: var(--vista-leyenda) !important; }
.ctx-btn .material-symbols-rounded { font-size: 20px; }
.ctx-btn span:last-child {
  font-size: 9.5px;
  text-align: center;
  line-height: 1.15;
}

.ctx-color-chip {
  width: 22px; height: 22px;
  border-radius: 2px;
  border: 1.5px solid var(--line);
  box-shadow: 1px 1px 0 var(--line);
}
.ctx-letter {
  width: 22px; height: 22px;
  display: grid; place-items: center;
  font-family: var(--font-display);
  font-size: 14px;
  color: var(--ink);
}

.ctx-badge {
  position: absolute;
  top: 4px; right: 4px;
  min-width: 16px; height: 16px;
  border-radius: 2px;
  background: var(--wine);
  color: var(--wine-ink);
  font-size: 9px;
  font-weight: 700;
  display: grid; place-items: center;
  padding: 0 4px;
  border: 1.5px solid var(--paper);
}

.ctx-sep-h {
  height: 1px;
  background: var(--line-soft);
  margin: 4px 6px;
}

/* Popouts */
.ctx-popout {
  position: absolute;
  top: 96px; left: 100px;
  background: var(--paper);
  border: 1.5px solid var(--line);
  border-radius: 2px;
  box-shadow: var(--pop);
  z-index: 71;
  width: 260px;
  animation: ctx-slide-in 200ms var(--e-out);
}
.ctx-pop-section { padding: 12px; }
.ctx-pop-title { font-family: var(--font-display); font-size: 13px; font-weight: 700; margin-bottom: 10px; letter-spacing: -0.01em; }
.ctx-pop-sub { font-size: 10px; font-weight: 700; color: var(--ink-3); text-transform: uppercase; letter-spacing: 0.05em; margin: 12px 0 6px; font-family: var(--font-mono); }
.ctx-field { display: flex; flex-direction: column; gap: 6px; font-size: 11px; font-weight: 700; color: var(--ink-3); }
.ctx-field input,
.ctx-field textarea {
  width: 100%;
  border: 1.5px solid var(--line);
  border-radius: 2px;
  background: var(--paper-2);
  color: var(--ink);
  padding: 8px 10px;
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.35;
}
.ctx-field textarea { min-height: 86px; resize: vertical; }
.ctx-wide-btn {
  margin-top: 10px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 8px 10px;
  border: 1.5px solid var(--line);
  border-radius: 2px;
  background: var(--ink);
  color: var(--bg);
  font-size: 12px;
  font-weight: 700;
}
.ctx-wide-btn .material-symbols-rounded { font-size: 15px; }

.ctx-color-tabs {
  display: flex;
  background: var(--bg-2);
  border-radius: 2px;
  padding: 3px;
  margin-bottom: 10px;
  gap: 2px;
}
.ctx-color-tabs button {
  flex: 1;
  padding: 5px 8px;
  display: flex; align-items: center; gap: 6px; justify-content: center;
  border-radius: 2px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ink-2);
  transition: background 100ms;
}
.ctx-color-tabs button.active { background: var(--paper); color: var(--ink); box-shadow: 1px 1px 0 var(--line-soft); }
.ctx-color-tabs .tab-chip { width: 14px; height: 14px; border-radius: 2px; }

.ctx-sticky-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 6px;
}
.ctx-sticky-swatch {
  aspect-ratio: 1;
  border-radius: 2px;
  cursor: pointer;
  transition: transform 120ms var(--e-out);
  border: 1.5px solid var(--line);
  position: relative;
}
.ctx-sticky-swatch:hover { transform: scale(1.06); }
.ctx-sticky-swatch.active::after {
  content: '';
  position: absolute; inset: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M5 12 L10 17 L19 7' stroke='black' stroke-width='3.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-size: 65%;
  background-position: center;
  background-repeat: no-repeat;
}

.ctx-strip-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 5px;
}
.ctx-strip-swatch {
  aspect-ratio: 1;
  border-radius: 2px;
  cursor: pointer;
  border: 1.5px solid var(--line);
  transition: transform 120ms var(--e-out);
  position: relative;
}
.ctx-strip-swatch:hover { transform: scale(1.08); }
.ctx-strip-swatch.active::after {
  content: '';
  position: absolute; inset: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M5 12 L10 17 L19 7' stroke='white' stroke-width='3.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-size: 70%;
  background-position: center;
  background-repeat: no-repeat;
}

/* Emoji picker */
.ctx-emoji-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 3px;
}
.ctx-emoji-btn {
  aspect-ratio: 1;
  display: grid; place-items: center;
  border-radius: 2px;
  font-size: 18px;
  background: transparent;
  transition: background 100ms, transform 120ms var(--e-out);
}
.ctx-emoji-btn:hover { background: var(--bg-2); transform: scale(1.15); }

.ctx-icon-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 4px; }
.ctx-icon-grid-scroll { max-height: 240px; overflow-y: auto; padding-right: 2px; }
.ctx-icon-search { width: 100%; margin-bottom: 7px; padding: 6px 9px; font-size: 12.5px; border: 1.5px solid var(--line-soft); border-radius: 4px; background: var(--paper); color: var(--ink); outline: none; }
.ctx-icon-search:focus { border-color: var(--olive); }
.ctx-icon-empty { grid-column: 1 / -1; text-align: center; padding: 16px; color: var(--ink-3); font-size: 12px; }
.ctx-icon-btn { aspect-ratio: 1; display: grid; place-items: center; border-radius: 4px; background: var(--bg-2); border: 1.5px solid transparent; cursor: pointer; transition: background 100ms, border-color 100ms; }
.ctx-icon-btn:hover { background: var(--olive-l); }
.ctx-icon-btn.active { border-color: var(--olive); background: var(--olive-l); }
.ctx-icon-btn .material-symbols-rounded { font-size: 18px; color: var(--ink); }

.ctx-reactions-current { display: flex; flex-wrap: wrap; gap: 4px; }
.ctx-react-pill {
  display: flex; align-items: center; gap: 4px;
  padding: 4px 8px;
  background: var(--bg-2);
  border: 1.5px solid var(--line-soft);
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
}
.ctx-react-pill:hover { background: var(--wine-l); border-color: var(--wine); }

/* Reactions display on items */
.item-reactions {
  display: flex; flex-wrap: wrap; gap: 3px;
  padding: 4px 8px 0;
}
.item-reaction-pill {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 2px 6px;
  background: rgba(255,255,255,0.85);
  border: 1.5px solid var(--line-soft);
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  backdrop-filter: blur(4px);
}

/* Comments */
.ctx-comments-list { display: flex; flex-direction: column; gap: 8px; max-height: 240px; overflow-y: auto; margin-bottom: 8px; }
.ctx-comments-empty { font-size: 11px; color: var(--ink-3); font-style: italic; padding: 4px 0; }
.ctx-comment { background: var(--bg-2); border-radius: 2px; padding: 7px 9px; }
.ctx-comment-head { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; }
.ctx-comment-avatar { width: 18px; height: 18px; border-radius: 50%; background: var(--olive); color: var(--olive-ink); font-size: 9px; font-weight: 700; display: grid; place-items: center; }
.ctx-comment-author { font-size: 11px; font-weight: 700; }
.ctx-comment-time { font-size: 10px; color: var(--ink-3); font-family: var(--font-mono); margin-left: auto; }
.ctx-comment-del { width: 18px; height: 18px; display: grid; place-items: center; background: transparent; border: none; cursor: pointer; color: var(--ink-3); border-radius: 2px; padding: 0; }
.ctx-comment-del:hover { background: var(--wine); color: var(--wine-ink); }
.ctx-comment-del .material-symbols-rounded { font-size: 14px; }
.ctx-comment-body { font-size: 12px; line-height: 1.35; }

.ctx-comment-composer {
  display: flex; flex-direction: column; gap: 6px;
  padding: 8px 0 0;
  border-top: 1px solid var(--line-soft);
}
.ctx-comment-composer textarea {
  width: 100%;
  min-height: 50px;
  padding: 8px 10px;
  background: var(--bg-2);
  border: 1.5px solid var(--line-soft);
  border-radius: 2px;
  font-size: 12px;
  resize: none;
}
.ctx-comment-composer textarea:focus { border-color: var(--olive); }

/* Comment marker on item */
.item-comment-badge {
  position: absolute;
  top: -8px; right: -8px;
  background: #3D8AE8;
  color: white;
  border: 2px solid var(--paper);
  border-radius: 999px;
  min-width: 22px; height: 22px;
  font-size: 11px;
  font-weight: 700;
  display: grid; place-items: center;
  z-index: 5;
  cursor: pointer;
  padding: 0 6px;
  box-shadow: 0 2px 6px rgba(0,0,0,0.18);
}
.item-comment-badge::after {
  content: '';
  position: absolute;
  bottom: -5px; left: 50%;
  transform: translateX(-50%);
  width: 0; height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 5px solid #3D8AE8;
}

/* Text style application */
.ts-bullets, .ts-numbered { padding-left: 16px; }
.ts-bullets li, .ts-numbered li { display: list-item; }
.ts-bullets { list-style: disc; }
.ts-numbered { list-style: decimal; }
.ts-quote {
  border-left: 3px solid var(--olive);
  padding-left: 8px !important;
  color: var(--ink-2);
  font-style: italic;
}
.item-toolbar {
  position: absolute;
  display: flex; align-items: center; gap: 2px;
  background: var(--ink);
  border-radius: 2px;
  padding: 3px;
  box-shadow: var(--pop);
  z-index: 60;
  border: 1.5px solid var(--line);
}
.item-toolbar button { width: 26px; height: 26px; border-radius: 2px; color: var(--bg); display: grid; place-items: center; transition: background 100ms; }
.item-toolbar button:hover { background: rgba(255,255,255,0.12); }
.item-toolbar .swatch-btn { width: 18px; height: 18px; border-radius: 50%; border: 1.5px solid rgba(255,255,255,0.4); }
.item-toolbar .swatch-btn.active { border-color: white; box-shadow: 0 0 0 1.5px var(--olive); }
.item-toolbar .material-symbols-rounded { font-size: 15px; }
.item-toolbar .divider { width: 1px; height: 16px; background: rgba(255,255,255,0.2); margin: 0 3px; }

/* Resize handles */
.handles { position: absolute; inset: -6px; pointer-events: none; }
.handle { 
  position: absolute; 
  width: 10px; 
  height: 10px; 
  background: var(--paper); 
  border: 1.5px solid var(--olive); 
  border-radius: 2px; 
  pointer-events: auto; 
  transform: scale(var(--handle-scale, 1));
  transform-origin: center;
  z-index: 10;
}
.handle::before {
  content: '';
  position: absolute;
  top: -8px; left: -8px; right: -8px; bottom: -8px;
  pointer-events: auto;
}
.handle.tl { top: 0; left: 0; cursor: nwse-resize; }
.handle.tr { top: 0; right: 0; cursor: nesw-resize; }
.handle.bl { bottom: 0; left: 0; cursor: nesw-resize; }
.handle.br { bottom: 0; right: 0; cursor: nwse-resize; }
/* Girar: va por fuera de la caja y por debajo a la DERECHA, donde no pisa
   ninguna esquina de redimensionado. Es redondo a propósito, para que no se
   confunda con los cuadraditos que cambian el tamaño.

   A la derecha y no a la izquierda porque la barra de acciones del nodo
   seleccionado sale siempre por la izquierda: probando la aplicación con un
   título pegado al borde izquierdo, la bola quedaba DEBAJO de esa barra y no
   había forma de alcanzarla. Por la derecha no la tapa nada.

   ── Por qué su sitio se calcula con el zoom ──
   Los tiradores crecen al alejarse (--handle-scale) para seguir siendo
   agarrables, pero la DISTANCIA entre este y la esquina estaba escrita en
   píxeles del lienzo, y esa encoge con el zoom. Al alejarse, el tirador crecía
   y el hueco menguaba: se montaba encima del cuadradito de la esquina, y al
   intentar girar se agarraba el de cambiar el tamaño. A lo lejos no había
   manera de girar nada.

   Ahora tanto su tamaño como su separación se multiplican por --handle-libre
   (1 / zoom, sin tope), así que en la PANTALLA miden siempre lo mismo: 22 px de
   bola a 44 px por debajo de la esquina, estés al 20 % o al 250 %. Las
   zonas de agarre de los dos no llegan a tocarse a ningún zoom: las dos son
   cuadradas, así que lo que cuenta es la separación en UN eje, y en vertical hay
   44 px frente a los 34 que suman sus medios anchos (13 del cuadradito y 21 de
   la bola). La primera versión la ponía a 30 px y medida se rozaban por una
   esquina al 50 % y al 30 %. */
.handle.rot {
  width: 22px; height: 22px;
  /* El centro de la bola a 26 px a la derecha y 44 px por debajo de la
     esquina, en píxeles de pantalla; los 11 px son su medio ancho, porque
     right y bottom colocan el borde y no el centro. */
  right: calc(-26px * var(--handle-libre, 1) - 11px);
  bottom: calc(-44px * var(--handle-libre, 1) - 11px);
  transform: scale(var(--handle-libre, 1));
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  cursor: grab;
  box-shadow: 0 1px 3px rgba(0,0,0,0.18);
}
.handle.rot:active { cursor: grabbing; }
.handle.rot .material-symbols-rounded { font-size: 15px; color: var(--olive-texto); }
.handle.rot::before { top: -10px; left: -10px; right: -10px; bottom: -10px; }

/* ── Los tiradores del recorte, del mismo tamaño a cualquier distancia ──
   Miden 12 px del lienzo, así que al 30 % de zoom se quedaban en 3,6 px de
   pantalla: un punto que hay que acertar con el ratón. Crecen con el zoom igual
   que el de girar, y además llevan una zona de agarre invisible alrededor,
   porque un tirador de recorte se busca a ojo y no con precisión. */
.crop-handle {
  transform: scale(var(--handle-libre, 1));
  transform-origin: center;
}
.crop-handle::before {
  content: '';
  position: absolute;
  top: -9px; left: -9px; right: -9px; bottom: -9px;
}

/* ============================================
   Subtle enter animation (only the incoming page)
   ============================================ */
@keyframes inside-enter {
  0% { opacity: 0; transform: translateY(6px); }
  100% { opacity: 1; transform: none; }
}
.canvas-wrap.entering .canvas-surface > .canvas-content > .item,
.canvas-wrap.entering .canvas-surface > .canvas-content > svg { animation: inside-enter 240ms var(--e-out) both; }
.canvas-wrap.entering .canvas-surface > .canvas-content > .item:nth-child(2) { animation-delay: 30ms; }
.canvas-wrap.entering .canvas-surface > .canvas-content > .item:nth-child(3) { animation-delay: 60ms; }
.canvas-wrap.entering .canvas-surface > .canvas-content > .item:nth-child(4) { animation-delay: 90ms; }
.canvas-wrap.entering .canvas-surface > .canvas-content > .item:nth-child(n+5) { animation-delay: 120ms; }

/* ============================================
   STATUS / TOAST
   ============================================ */
.status-bar { position: absolute; left: 16px; bottom: 16px; display: flex; gap: 6px; z-index: 40; }
.status-pill { background: var(--paper); border: 1.5px solid var(--line); border-radius: 999px; padding: 5px 10px; font-size: 11.5px; font-weight: 600; box-shadow: var(--pop-sm); display: flex; align-items: center; gap: 6px; }
.status-pill .dot-live { width: 6px; height: 6px; border-radius: 50%; background: var(--olive); }
.status-pill.accent { background: var(--wine); color: var(--wine-ink); border-color: var(--line); }

/* ============================================
   MODALS (new project + doc editor)
   ============================================ */
.modal-backdrop { position: fixed; inset: 0; background: color-mix(in srgb, var(--ink) 50%, transparent); backdrop-filter: blur(3px); z-index: 200; display: grid; place-items: center; animation: fade-in 160ms var(--e-out); }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
/* max-height y desplazamiento propio: con las 60 portadas 3D, «Editar
   proyecto» medía 834 px y a 1280×768 sus botones quedaban por debajo de la
   pantalla, sin forma de llegar a ellos (lo encontraron dos bots). */
.modal { background: var(--paper); border: 1.5px solid var(--line); border-radius: 2px; box-shadow: var(--pop-deep); padding: 22px; width: 420px; max-width: calc(100vw - 40px); max-height: calc(100vh - 40px); max-height: calc(100dvh - 40px); overflow-y: auto; box-sizing: border-box; animation: scale-in 200ms var(--e-out); }
@keyframes scale-in { from { transform: scale(0.94); opacity: 0; } to { transform: scale(1); opacity: 1; } }
.modal h2 { font-family: var(--font-display); font-size: 22px; font-weight: 800; letter-spacing: -0.02em; margin: 0 0 6px; }
.modal p { color: var(--ink-2); font-size: 13px; margin: 0 0 16px; }
.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; }
.field label { font-size: 12px; font-weight: 700; color: var(--ink-2); }
.field input { padding: 9px 12px; border: 1.5px solid var(--line); border-radius: 2px; font-size: 14px; background: var(--paper-2); }
.field input:focus { outline: 2px solid var(--olive); outline-offset: 1px; }
.emoji-row { display: flex; gap: 5px; flex-wrap: wrap; }
.emoji-pick.sin-icono { color: var(--ink-3); }
.emoji-pick.sin-icono .material-symbols-rounded { font-size: 18px; }
.emoji-pick { width: 34px; height: 34px; border-radius: 2px; border: 1.5px solid var(--line); display: grid; place-items: center; font-size: 18px; background: var(--paper); cursor: pointer; transition: transform 120ms var(--e-out); }
.emoji-pick:hover { transform: translateY(-1px); }
.emoji-pick.active { background: var(--olive); border-color: var(--olive); }
.cover-row { display: flex; gap: 5px; flex-wrap: wrap; }
.cover-pick { width: 48px; height: 30px; border-radius: 2px; border: 1.5px solid var(--line); cursor: pointer; transition: transform 120ms var(--e-out); }
.cover-pick:hover { transform: translateY(-1px); }
.cover-pick.active { outline: 2px solid var(--ink); outline-offset: 2px; }

/* ── El texto de dentro de una figura ──
   Sin fondo ni borde: el marco ya lo pone la figura. El aviso de que está vacía
   se enseña como en las notas, con el atributo del propio elemento, para no
   guardar un texto de mentira dentro del nodo. */
.figura-texto:empty::before,
.figura-texto:has(> br:only-child)::before {
  content: attr(data-placeholder);
  color: var(--ink-3, #8E8A8E);
  opacity: 0.75;
  pointer-events: none;
}

/* Las cuatro figuras para elegir, en la barra de la derecha. */
.ctx-figura-grid {
  display: grid;
  /* Cuatro columnas y dos filas para las ocho: en dos columnas la lista se iba
     al doble de alto que el panel y había que buscarlas con la rueda. */
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
}
.ctx-figura-swatch {
  display: grid;
  place-items: center;
  padding: 6px;
  border-radius: 7px;
  cursor: pointer;
  background: transparent;
  border: 1.5px solid var(--line-soft);
  transition: transform 120ms var(--e-out), border-color 120ms, background 120ms;
}
.ctx-figura-swatch:hover { border-color: var(--line); background: var(--paper); }
.ctx-figura-swatch:active { transform: scale(0.95); }
.ctx-figura-swatch.active { border-color: var(--wine); background: var(--paper); }
.ctx-figura-swatch svg { width: 30px; height: 24px; }

/* ── La barra de la portada ──
   Un arcoíris por el que se arrastra. Para una portada nadie busca "el
   #7B3FE4": busca "un poco más morado que ese", y eso se hace moviéndose, no
   eligiendo entre casillas. */
.portada-barra {
  position: relative;
  height: 26px;
  border-radius: 6px;
  border: 1.5px solid var(--line);
  cursor: pointer;
  touch-action: none;
  background: linear-gradient(90deg,
    hsl(0, 72%, 55%) 0%, hsl(45, 80%, 55%) 12.5%, hsl(90, 60%, 45%) 25%,
    hsl(135, 55%, 42%) 37.5%, hsl(180, 60%, 42%) 50%, hsl(225, 65%, 52%) 62.5%,
    hsl(270, 60%, 55%) 75%, hsl(315, 65%, 55%) 87.5%, hsl(360, 72%, 55%) 100%);
}
.portada-barra:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.portada-barra-tirador {
  position: absolute;
  top: -4px; bottom: -4px;
  width: 12px;
  transform: translateX(-50%);
  border-radius: 4px;
  background: transparent;
  border: 2.5px solid #FFFFFF;
  box-shadow: 0 0 0 1.5px var(--line), 0 2px 6px rgba(0, 0, 0, 0.35);
  pointer-events: none;
}
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px; }

/* Doc fullscreen modal */
.doc-modal-backdrop { position: fixed; inset: 0; background: color-mix(in srgb, var(--ink) 60%, transparent); backdrop-filter: blur(4px); z-index: 200; display: grid; place-items: center; animation: fade-in 160ms var(--e-out); }
/* El documento ocupa la pantalla entera, como un procesador de textos: escribir
   un texto largo dentro de una ventanita en medio del lienzo no tenía sentido,
   y además dejaba un borde que cerraba el editor al pulsarlo por accidente. */
.doc-modal {
  background: var(--paper);
  border: none;
  border-radius: 0;
  box-shadow: none;
  width: 100vw;
  height: 100vh;
  height: 100dvh;
  display: flex; flex-direction: column;
  animation: fade-in 140ms var(--e-out);
  overflow: hidden;
}
.doc-modal-head { display: flex; align-items: center; gap: 10px; padding: 12px 18px; border-bottom: 1.5px solid var(--line); background: var(--paper-2); }
.doc-title-input { font-family: var(--font-display); font-weight: 800; font-size: 20px; flex: 1; letter-spacing: -0.02em; }
.doc-modal-body { display: flex; flex: 1; min-height: 0; }

/* ── Barra de herramientas: horizontal y por categorías ── */
.doc-ribbon {
  flex: 0 0 auto;
  display: flex; align-items: stretch; flex-wrap: wrap;
  gap: 0; padding: 4px 12px 0;
  border-bottom: 1.5px solid var(--line);
  background: var(--paper-2);
}
.doc-group {
  display: flex; flex-direction: column; align-items: center;
  padding: 0 10px;
  border-right: 1px solid var(--line-soft);
}
.doc-group:last-child { border-right: none; }
.doc-group-btns { display: flex; align-items: center; gap: 2px; }
.doc-group-name {
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase;
  color: var(--ink-3); margin-top: 1px; padding-bottom: 3px;
}
.doc-ribbon button {
  width: 32px; height: 30px; display: grid; place-items: center;
  color: var(--ink-2); border-radius: 3px; transition: background 100ms;
}
.doc-ribbon button:hover { background: var(--bg); color: var(--ink); }
.doc-ribbon button.active { background: var(--olive); color: var(--olive-ink); }
.doc-ribbon button:disabled { opacity: 0.32; cursor: default; }
.doc-ribbon button:disabled:hover { background: none; color: var(--ink-2); }
.doc-ribbon .material-symbols-rounded { font-size: 19px; }
.doc-ribbon .doc-tool-label { font-family: var(--font-display); font-weight: 800; font-size: 17px; }
.doc-ribbon button i { font-style: italic; font-weight: 800; font-size: 16px; }
.doc-font-btn { width: auto !important; padding: 0 4px; gap: 0; display: flex !important; align-items: center; }
.doc-font-btn .doc-caret { font-size: 15px !important; opacity: 0.6; }
.doc-size-ctrl { display: flex; align-items: center; }
.doc-ribbon .doc-size-num {
  font-family: var(--font-display); font-weight: 800; font-size: 13px;
  width: 34px; letter-spacing: -0.2px;
}
/* Por encima del velo del documento (200) y de su propia capa de cierre (209) */
.doc-tool-pop {
  z-index: 1300; background: var(--paper); border: 1.5px solid var(--line);
  border-radius: 4px; box-shadow: 0 12px 34px rgba(0,0,0,0.17); padding: 8px;
}
.doc-pop-title {
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.4px; text-transform: uppercase;
  color: var(--ink-2); margin-bottom: 7px;
}
.doc-size-list {
  display: grid; grid-template-columns: repeat(2, 46px); gap: 3px;
  max-height: 300px; overflow-y: auto;
}
.doc-size-list button {
  height: 28px; border-radius: 3px; font-weight: 700; font-size: 12.5px;
  color: var(--ink-2); display: grid; place-items: center;
}
.doc-size-list button:hover { background: var(--bg); color: var(--ink); }
.doc-size-list button.active { background: var(--olive); color: var(--olive-ink); }
.doc-color-grid { display: grid; grid-template-columns: repeat(4, 26px); gap: 5px; }
.doc-color-swatch {
  width: 26px; height: 26px; border-radius: 3px; border: 1.5px solid var(--line);
  display: grid; place-items: center; color: var(--ink-2);
}
.doc-color-swatch:hover { transform: scale(1.12); }
.doc-menu-list { display: flex; flex-direction: column; gap: 2px; min-width: 132px; max-height: 300px; overflow-y: auto; }
.doc-menu-list button {
  height: 30px; padding: 0 10px; border-radius: 3px; text-align: left;
  font-size: 13px; color: var(--ink-2); display: flex; align-items: center;
}
.doc-menu-list button:hover { background: var(--bg); color: var(--ink); }
/* El editor y su barra de estado, apilados dentro del cuerpo del documento */
.doc-modal-pane-wrap { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.doc-modal-pane-wrap .doc-modal-editor-pane { flex: 1; min-height: 0; }
.doc-status {
  flex: 0 0 auto; display: flex; align-items: center; gap: 6px;
  padding: 5px 14px; border-top: 1.5px solid var(--line);
  background: var(--paper-2); color: var(--ink-3);
  font-size: 11px; font-weight: 600; letter-spacing: 0.2px;
}
.doc-status-sep { opacity: 0.5; }
/* Elementos nuevos dentro del documento */
.doc-color-libre { display: flex; align-items: center; gap: 6px; margin-top: 9px; padding-top: 9px; border-top: 1px solid var(--line-soft); }
/* La bolita de arcoíris del botón que abre el panel de color. */
.doc-color-arco {
  width: 14px; height: 14px; border-radius: 50%; flex: 0 0 auto;
  border: 1.5px solid var(--line);
  background: conic-gradient(#E6544F, #DDAF2C, #90B968, #3CA59E, #3D5A80, #955BA5, #E6544F);
}
.doc-color-ok {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  flex: 1; height: 26px; border-radius: 3px; font-size: 11.5px; font-weight: 700;
  background: var(--bg); color: var(--ink-2); border: 1.5px solid var(--line-soft);
}
.doc-color-ok:hover, .doc-color-ok.abierto { background: var(--olive); color: var(--olive-ink); border-color: var(--olive); }
.doc-modal-content h3 { font-family: var(--font-display); font-size: 17px; font-weight: 700; margin: 16px 0 8px; }
/* Bloque de código. Antes no tenía estilo propio: el <pre> se quedaba con el
   ajuste por defecto (sin partir líneas), así que una línea larga sacaba una
   barra de desplazamiento horizontal y el texto se salía de la caja. Se copia
   lo que hacen las notas, pero con los colores del tema en vez de fijos, que en
   modo oscuro cantaban. */
/* ── Bloque de código: un editor aparte, no texto enriquecido ──
   El <textarea> transparente va encima de la capa coloreada. Para que el cursor
   caiga exactamente sobre la letra que toca, las dos capas tienen que compartir
   TODAS las medidas del texto: familia, tamaño, interlineado, relleno, ajuste de
   línea y tabulación. Cualquier diferencia se nota como un desfase creciente. */
.doc-modal-content pre.odi-code {
  position: relative;
  display: block;
  background: var(--bg-2, var(--bg));
  border: 1.5px solid var(--line-soft);
  border-left: 3px solid var(--olive);
  border-radius: 3px;
  margin: 14px 0;
  padding: 0;
  overflow: hidden;
}
.odi-code:focus-within { border-color: var(--olive); }
.odi-code-head {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 10px;
  border-bottom: 1px solid var(--line-soft);
  background: color-mix(in srgb, var(--ink) 5%, transparent);
  user-select: none;
}
.odi-code-lang {
  font-family: var(--font-mono); font-size: 10px; font-weight: 700;
  letter-spacing: 0.5px; text-transform: uppercase; color: var(--ink-3);
}
.odi-code-tip { margin-left: auto; font-size: 10px; color: var(--ink-3); font-weight: 600; white-space: nowrap; }
.odi-code-body { position: relative; }
.odi-code-hl,
.odi-code-src {
  margin: 0;
  padding: 10px 13px;
  border: 0;
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1.6;
  letter-spacing: 0;
  tab-size: 2;
  white-space: pre-wrap;
  overflow-wrap: break-word;
  word-break: normal;
  box-sizing: border-box;
  width: 100%;
  background: transparent;
}
.odi-code-hl { color: var(--ink); pointer-events: none; min-height: 1.6em; }
.odi-code-hl code { display: block; background: none !important; padding: 0 !important; font: inherit; }
.odi-code-src {
  position: absolute; inset: 0;
  resize: none; overflow: hidden; display: block;
  color: transparent;
  caret-color: var(--olive);
  -webkit-text-fill-color: transparent;
}
.odi-code-src::selection { background: color-mix(in srgb, var(--olive) 35%, transparent); }
.odi-code-src:focus { outline: none; }

/* ── Colores del código ──
   La hoja que trae el resaltador (lib/github.min.css) es de tema claro y sobre
   el documento en oscuro daba azules ilegibles, así que los colores se definen
   aquí, con un juego para cada tema. Van con !important porque esa hoja se
   carga después.

   Cada FAMILIA de cosas lleva su tono, no un color por capricho: lo que declara
   algo (palabras clave) en morado, lo que nombra (funciones y clases) en azul y
   cian, los datos (cadenas y números) en verde y naranja, lo que viene de fuera
   (tipos y funciones del lenguaje) en dorado, y lo accesorio (comentarios,
   signos) apagado. Así el ojo separa por color antes de leer. */
:root {
  --cod-comentario: #7A8B99;   --cod-clave:    #A63FBF;
  --cod-cadena:     #2E8B4A;   --cod-numero:   #C9721F;
  --cod-funcion:    #2C6FCF;   --cod-clase:    #0E8B94;
  --cod-tipo:       #9A7B12;   --cod-variable: #C0392B;
  --cod-literal:    #C2185B;   --cod-meta:     #6B7F2E;
  --cod-signo:      #857E8C;   --cod-etiqueta: #7A5AC7;
  --cod-atributo:   #B5651D;   --cod-regexp:   #0F8A7E;
}
[data-theme="dark"] {
  --cod-comentario: #6E7A85;   --cod-clave:    #D8A0F0;
  --cod-cadena:     #8FD17A;   --cod-numero:   #F5A65B;
  --cod-funcion:    #6FB6FF;   --cod-clase:    #4FD6D0;
  --cod-tipo:       #EFD05C;   --cod-variable: #FF8C7A;
  --cod-literal:    #FF7EB6;   --cod-meta:     #BEDC7A;
  --cod-signo:      #9A93A5;   --cod-etiqueta: #C4A7F5;
  --cod-atributo:   #FFB870;   --cod-regexp:   #5FE0C0;
}
.odi-code-hl .hljs-comment,
.odi-code-hl .hljs-quote            { color: var(--cod-comentario) !important; font-style: italic; }
.odi-code-hl .hljs-doctag            { color: var(--cod-comentario) !important; font-weight: 700; }
.odi-code-hl .hljs-keyword,
.odi-code-hl .hljs-selector-tag,
.odi-code-hl .hljs-keyword.hljs-meta { color: var(--cod-clave) !important; font-weight: 600; }
.odi-code-hl .hljs-string,
.odi-code-hl .hljs-addition,
.odi-code-hl .hljs-char.escape_,
.odi-code-hl .hljs-formula           { color: var(--cod-cadena) !important; }
.odi-code-hl .hljs-regexp,
.odi-code-hl .hljs-link,
.odi-code-hl .hljs-symbol            { color: var(--cod-regexp) !important; }
.odi-code-hl .hljs-number,
.odi-code-hl .hljs-bullet             { color: var(--cod-numero) !important; }
.odi-code-hl .hljs-literal            { color: var(--cod-literal) !important; font-weight: 600; }
.odi-code-hl .hljs-title,
.odi-code-hl .hljs-title.function_,
.odi-code-hl .hljs-section,
.odi-code-hl .hljs-selector-id        { color: var(--cod-funcion) !important; font-weight: 600; }
.odi-code-hl .hljs-title.class_,
.odi-code-hl .hljs-title.class_.inherited__,
.odi-code-hl .hljs-selector-class     { color: var(--cod-clase) !important; font-weight: 600; }
.odi-code-hl .hljs-type,
.odi-code-hl .hljs-built_in,
.odi-code-hl .hljs-variable.language_ { color: var(--cod-tipo) !important; }
.odi-code-hl .hljs-variable,
.odi-code-hl .hljs-template-variable,
.odi-code-hl .hljs-property,
.odi-code-hl .hljs-selector-attr,
.odi-code-hl .hljs-selector-pseudo    { color: var(--cod-variable) !important; }
.odi-code-hl .hljs-attr,
.odi-code-hl .hljs-attribute          { color: var(--cod-atributo) !important; }
.odi-code-hl .hljs-name,
.odi-code-hl .hljs-tag,
.odi-code-hl .hljs-template-tag       { color: var(--cod-etiqueta) !important; }
.odi-code-hl .hljs-meta,
.odi-code-hl .hljs-meta .hljs-string  { color: var(--cod-meta) !important; }
.odi-code-hl .hljs-params,
.odi-code-hl .hljs-subst              { color: var(--ink) !important; }
.odi-code-hl .hljs-operator,
.odi-code-hl .hljs-punctuation        { color: var(--cod-signo) !important; }
.odi-code-hl .hljs-deletion           { color: var(--cod-variable) !important; }
.odi-code-hl .hljs-emphasis           { font-style: italic; }
.odi-code-hl .hljs-strong             { font-weight: 700; }

.doc-ribbon .doc-color-btn { display: flex !important; flex-direction: column; align-items: center; justify-content: center; gap: 0; }
.doc-ribbon .doc-color-btn .material-symbols-rounded { font-size: 17px; line-height: 1; }
.doc-color-bar { width: 17px; height: 4px; border-radius: 1px; margin-top: 1px; display: block; box-shadow: inset 0 0 0 1px rgba(0,0,0,0.12); }
/* Siempre un párrafo pulsable detrás del bloque, para poder seguir escribiendo
   texto normal sin quedarse atrapado dentro del código. */
.doc-modal-content pre.odi-code + p { min-height: 1.5em; margin: 12px 0; cursor: text; }
.doc-modal-content hr { border: none; border-top: 1.5px solid var(--line); margin: 18px 0; }
.doc-modal-content sup, .doc-modal-content sub { font-size: 0.72em; line-height: 0; }
.doc-modal-content mark { background: #FFF3A3; color: inherit; padding: 0 1px; }
.doc-modal-editor-pane {
  flex: 1;
  overflow-y: auto;
  background: var(--bg-2, var(--bg));
  padding: 30px;
}
.doc-modal-content {
  width: 100%;
  max-width: 720px;               /* portrait page proportions (A4-like), not square */
  margin: 0 auto;                 /* horizontal centering without flex (avoids scroll clipping) */
  min-height: max(calc(100% - 10px), 940px); /* at least a full page tall → reads like a document */
  height: auto;                   /* grow with content into the page, not the gray void */
  background: var(--paper);
  border: 1.5px solid var(--line);
  border-radius: 4px;
  box-shadow: var(--pop-sm);
  padding: 64px 76px;
  box-sizing: border-box;
  outline: none;
  font-size: 16px;
  line-height: 1.7;
  color: var(--ink);
  overflow-wrap: break-word;
}
.doc-modal-content:empty::before { content: 'Empieza a escribir…'; color: var(--ink-3); pointer-events: none; }
[data-lang="en"] .doc-modal-content:empty::before { content: 'Start writing…'; }
.doc-modal-content h1 { font-family: var(--font-display); font-size: 28px; font-weight: 800; letter-spacing: -0.02em; margin: 24px 0 12px; }
.doc-modal-content h2 { font-family: var(--font-display); font-size: 22px; font-weight: 700; letter-spacing: -0.01em; margin: 20px 0 10px; }
.doc-modal-content p { margin: 0 0 12px; }
.doc-modal-content ul, .doc-modal-content ol { margin: 0 0 12px; padding-left: 24px; }
.doc-modal-content li { margin: 4px 0; }
.doc-modal-content blockquote { border-left: 3px solid var(--olive); padding: 4px 0 4px 14px; margin: 0 0 12px; color: var(--ink-2); font-style: italic; }
.doc-modal-content code { font-family: var(--font-mono); font-size: 13px; background: var(--bg-2); padding: 2px 5px; border-radius: 2px; }
/* Images shrink to fit the document width instead of expanding it */
.doc-modal-content img, .doc-body-preview img { max-width: 100%; height: auto; display: block; margin: 8px 0; border-radius: 2px; }
.doc-modal-content a, .doc-body-preview a { color: var(--wine-texto); text-decoration: underline; text-decoration-color: color-mix(in srgb, var(--wine) 55%, transparent); text-underline-offset: 2px; font-weight: 600; cursor: pointer; }
.doc-modal-content a:hover { text-decoration-color: var(--wine); }

/* Floating link editor (appears next to the selected text) */
.doc-link-overlay { position: fixed; inset: 0; z-index: 209; }
.doc-link-pop {
  z-index: 210; display: flex; align-items: center; gap: 7px;
  background: var(--paper); border: 1.5px solid var(--line); border-radius: 4px;
  box-shadow: var(--pop); padding: 6px 8px; max-width: 360px;
  animation: scale-in 110ms var(--e-out);
}
.doc-link-input { flex: 1; min-width: 200px; font-size: 13px; padding: 4px 2px; border: none; outline: none; background: transparent; color: var(--ink); }
.doc-link-ok { background: var(--olive); color: var(--olive-ink); font-size: 12.5px; font-weight: 700; padding: 5px 11px; border-radius: 3px; white-space: nowrap; }
.doc-link-ok:hover { filter: brightness(1.08); }
.doc-link-rm { display: grid; place-items: center; width: 26px; height: 26px; color: var(--ink-3); border-radius: 3px; }
.doc-link-rm:hover { background: var(--bg); color: var(--olive-texto); }
.doc-cols { column-count: 2; column-gap: 2em; }
.doc-modal-content.doc-cols { column-count: 2 !important; column-gap: 3em; column-rule: 1px solid var(--line-soft); }
.doc-card .doc-body-preview.doc-cols {
  display: block !important;
  column-count: 2 !important;
  column-gap: 10px !important;
  column-rule: 1px solid var(--line-soft) !important;
}
.doc-card .doc-body-preview.doc-cols > * { break-inside: avoid; margin: 0 0 4px; }
.doc-card .doc-body-preview.doc-cols p { margin: 0 0 4px; }

.icon-row { display: flex; gap: 5px; flex-wrap: wrap; }
.icon-pick { width: 34px; height: 34px; border-radius: 2px; border: 1.5px solid var(--line); display: grid; place-items: center; background: var(--paper); cursor: pointer; transition: transform 120ms var(--e-out); }
.icon-pick:hover { transform: translateY(-1px); }
.icon-pick.active { background: var(--olive); color: var(--olive-ink); }
.icon-pick .material-symbols-rounded { font-size: 18px; }

/* Context menu */
.context-menu { position: absolute; background: var(--paper); border: 1.5px solid var(--line); border-radius: 2px; box-shadow: var(--pop); padding: 4px; min-width: 180px; z-index: 150; animation: scale-in 120ms var(--e-out); }
.context-menu-create { max-height: 78vh; overflow-y: auto; min-width: 210px; }
.context-menu button:disabled { opacity: 0.4; cursor: default; }
.context-menu button { display: flex; align-items: center; gap: 8px; width: 100%; padding: 6px 10px; border-radius: 2px; font-size: 13px; text-align: left; }
.context-menu button:hover { background: var(--bg); }
.context-menu button.danger { color: var(--wine-texto); }
.context-menu button.danger:hover { background: var(--wine-l); }
.context-menu .material-symbols-rounded { font-size: 15px; }
.ctx-sep { height: 1px; background: var(--line-soft); margin: 4px 0; }

/* New item animation */
@keyframes item-fade-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
.item.new-item .item-card { animation: item-fade-in 180ms var(--e-out); }

/* ============================================
   AUDIO item styling (Milanote Emulation)
   ============================================ */
.audio-card .item-card {
  display: flex;
  flex-direction: column;
  padding: 0;
  background: var(--paper);
}
.audio-player-header {
  height: 52px;
  background: #f1f3f4;
  border-bottom: 1.5px solid var(--line);
  display: flex;
  align-items: center;
  padding: 0 10px;
  gap: 8px;
}
.audio-play-btn {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: #4c525d;
  color: white;
  display: grid;
  place-items: center;
  border: none;
  cursor: pointer;
  transition: transform 100ms, background 100ms;
  flex-shrink: 0;
}
.audio-play-btn:hover {
  transform: scale(1.05);
  background: #393e47;
}
.audio-play-btn:active {
  transform: scale(0.97);
}
.audio-play-btn .material-symbols-rounded {
  font-size: 16px;
}
.audio-volume-btn {
  width: 24px;
  height: 24px;
  display: grid;
  place-items: center;
  border: none;
  cursor: pointer;
  color: var(--ink-2);
  transition: color 100ms;
  flex-shrink: 0;
}
.audio-volume-btn:hover {
  color: var(--ink);
}
.audio-volume-btn .material-symbols-rounded {
  font-size: 18px;
}
.audio-scrubber-container {
  flex: 1;
  display: flex;
  align-items: center;
  position: relative;
  margin: 0 2px;
}
.audio-scrubber {
  width: 100%;
  -webkit-appearance: none;
  appearance: none;
  height: 4px;
  border-radius: 2px;
  background: #dcdce0;
  outline: none;
  cursor: pointer;
  position: relative;
}
.audio-scrubber::-webkit-slider-runnable-track {
  background: transparent;
}
.audio-scrubber::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #4c525d;
  cursor: pointer;
  border: none;
  transition: transform 100ms;
  margin-top: 0px;
}
.audio-scrubber:hover::-webkit-slider-thumb {
  transform: scale(1.3);
}
.audio-scrubber-progress {
  position: absolute;
  left: 0;
  top: 50%;
  height: 4px;
  background: #4c525d;
  border-radius: 2px;
  transform: translateY(-50%);
  pointer-events: none;
}
.audio-time {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--ink-2);
  white-space: nowrap;
  margin-left: 2px;
  flex-shrink: 0;
}
.audio-body {
  flex: 1;
  display: flex;
  align-items: center;
  padding: 10px 12px;
  gap: 12px;
  background: inherit;
  overflow: hidden;
}
.audio-file-icon {
  width: 32px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.audio-details {
  display: flex;
  flex-direction: column;
  gap: 2px;
  overflow: hidden;
}
.audio-file-name {
  font-size: 13px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* color is set inline by JS to handle dark backgrounds */
}
.audio-name-input {
  font-size: 13px;
  font-weight: 700;
  width: 100%;
  border: none;
  outline: none;
  background: transparent;
  padding: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: inherit;
  line-height: 1.2;
}
.audio-name-input:focus {
  outline: none;
}
.audio-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--ink-3);
}
.audio-download-link {
  color: inherit;
  font-weight: 700;
  text-decoration: underline;
  cursor: pointer;
  opacity: 0.7;
}
.audio-download-link:hover {
  opacity: 1;
}
.audio-empty {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  color: var(--ink-3);
  cursor: pointer;
  padding: 12px;
  background: inherit;
}
.audio-empty:hover {
  color: var(--olive-texto);
  background: var(--olive-l);
}
.audio-empty .material-symbols-rounded {
  font-size: 28px;
}
.audio-caption-row {
  border-top: 1.5px solid var(--line-soft);
  padding: 6px 12px;
  background: var(--paper-2);
}
.audio-caption-input {
  width: 100%;
  font-size: 11.5px;
  font-style: italic;
  color: var(--ink-2);
  outline: none;
  border: none;
  background: transparent;
  padding: 0;
}
.audio-caption-input::placeholder {
  color: var(--ink-3);
}

/* ============================================
   COLOR NODE
   ============================================ */
.color-card .item-card { background: var(--paper); }
.color-swatch {
  flex: 1; min-height: 0; position: relative;
  display: flex; align-items: flex-start; justify-content: flex-start;
  padding: 14px;
}
.color-hex { font-family: var(--font-mono); font-weight: 700; font-size: calc(13px * var(--node-scale, 1)); letter-spacing: 0.02em; }
.color-name-row { flex-shrink: 0; padding: 12px 14px; background: var(--paper); border-top: 1.5px solid var(--line-soft); }
.color-name { font-family: var(--font-body); font-weight: 600; font-size: calc(13px * var(--node-scale, 1)); color: var(--ink); }

/* Color picker pane (hex node) */
.ctx-colorhex { display: flex; align-items: center; gap: 8px; padding: 2px 0; }
.ctx-colorhex input[type="color"] { width: 34px; height: 30px; border: 1.5px solid var(--line); border-radius: 4px; background: none; padding: 2px; cursor: pointer; }
.ctx-hex-input { flex: 1; min-width: 0; font-family: var(--font-mono); font-size: 12.5px; padding: 6px 8px; border: 1.5px solid var(--line-soft); border-radius: 4px; text-transform: uppercase; }

/* ============================================
   NODO DE TIEMPO
   ============================================ */
/* Semitransparente y desenfocando lo de detrás. Un reloj no es un papel más
   pegado al tablero: es un cacharro que se deja ENCIMA, y opaco tapaba las
   notas sobre las que se posaba. El desenfoque no es adorno — sin él los
   números se leían sobre el texto de lo que hubiera debajo. */
.timer-body {
  display: flex; flex-direction: column;
  backdrop-filter: blur(9px) saturate(1.2);
  -webkit-backdrop-filter: blur(9px) saturate(1.2);
}
/* La barra de arriba, con color de verdad: es lo que separa el nombre del
   reloj y lo que le da al nodo una cabecera como la de los demás. */
.timer-bar {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 8px;
  padding: 6px 9px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.10);
}
.timer-title {
  flex: 1; min-width: 0;
  font-family: var(--font-display), system-ui, sans-serif;
  font-size: calc(12px * var(--node-scale, 1));
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  cursor: text;
}
.timer-title.vacio { opacity: 0.5; font-style: italic; font-weight: 500; }
.timer-title-input {
  flex: 1; min-width: 0;
  font-family: var(--font-display), system-ui, sans-serif;
  font-size: calc(12px * var(--node-scale, 1));
  background: rgba(255, 255, 255, 0.22); border: none; outline: none;
  border-radius: 4px; padding: 2px 6px;
}
.timer-modo {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 1px;
  font-family: var(--font-mono); font-size: 9.5px; font-weight: 700;
  letter-spacing: 0.05em; text-transform: uppercase;
  background: rgba(255, 255, 255, 0.16);
  border: 1px solid currentColor; border-radius: 99px;
  padding: 2px 3px 2px 8px; cursor: pointer;
  transition: background 120ms;
}
.timer-modo:hover { background: rgba(255, 255, 255, 0.34); }
.timer-modo .material-symbols-rounded { font-size: 14px; }
/* La tapa recoge el clic de fuera para cerrar la lista. Va dentro del nodo
   porque la tarjeta recorta lo que sobresale. */
.timer-modos-tapa { position: absolute; inset: 0; z-index: 3; }
.timer-modos {
  position: absolute; z-index: 4; right: 8px; top: 30px;
  min-width: 146px; padding: 4px;
  background: var(--paper); color: var(--ink);
  border: 1.5px solid var(--line); border-radius: 8px;
  box-shadow: var(--pop-hover);
  display: flex; flex-direction: column; gap: 2px;
}
.timer-modo-item {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 6px 8px; border: none; border-radius: 5px;
  background: none; color: inherit; cursor: pointer; text-align: left;
  font-family: var(--font-body); font-size: 12px;
}
.timer-modo-item:hover { background: rgba(0, 0, 0, 0.06); }
[data-theme="dark"] .timer-modo-item:hover { background: rgba(255, 255, 255, 0.08); }
.timer-modo-item.activo { font-weight: 700; }
.timer-modo-item .material-symbols-rounded { font-size: 15px; color: var(--olive-texto); }

.timer-cuerpo {
  flex: 1; min-height: 0;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 9px; padding: 10px 12px 12px;
}
.timer-fase {
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase;
  display: flex; gap: 6px; align-items: baseline;
}
.timer-rondas { font-weight: 500; letter-spacing: 0.04em; }
/* Los números en cifras de ancho fijo: sin eso el reloj “baila” a cada
   segundo, porque el 1 es más estrecho que el 8. */
.timer-reloj {
  font-family: var(--font-display), system-ui, sans-serif;
  font-variant-numeric: tabular-nums;
  font-weight: 800; letter-spacing: -0.02em; line-height: 1;
  font-size: calc(40px * var(--node-scale, 1));
}
/* El tiempo se escribe aquí, en el reloj. El subrayado punteado al pasar por
   encima es lo único que lo cuenta: un número grande no parece un campo. */
.timer-reloj.ajustable { cursor: text; }
.timer-reloj.ajustable:hover {
  text-decoration: underline dotted; text-underline-offset: 7px;
  text-decoration-thickness: 2px; opacity: 0.9;
}
.timer-reloj.editando { display: flex; align-items: baseline; gap: 1px; }
.timer-num {
  font: inherit; color: inherit; font-variant-numeric: tabular-nums;
  background: none; border: none; outline: none;
  border-bottom: 2px solid currentColor;
  padding: 0; margin: 0;
}
/* El móvil obliga a 16px a TODO campo de texto, para que el navegador no dé
   el zoom que da al escribir en letra pequeña. Esa regla lleva cinco clases
   de especificidad y le gana a cualquier cosa sensata de aquí: sin ganarle,
   las casillas del reloj salían a 16px pegadas a unos números de 40. Aquí no
   hay zoom que evitar, porque la letra ya es enorme. */
.timer-reloj .timer-num { font-size: calc(40px * var(--node-scale, 1)) !important; }
.timer-num:first-of-type { width: 3ch; text-align: right; }
.timer-num:last-of-type { width: 2.4ch; text-align: left; }
.timer-dosp { opacity: 0.5; }
.timer-barra {
  width: 82%; height: 6px; border-radius: 99px;
  border: 1.5px solid currentColor; opacity: 0.55; overflow: hidden;
}
.timer-barra > i { display: block; height: 100%; border-radius: 99px; transition: width 240ms linear; }
.timer-botones { display: flex; gap: 8px; }
.timer-btn {
  width: 34px; height: 34px; border-radius: 50%;
  border: 1.5px solid currentColor; background: none;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; opacity: 0.7; transition: opacity 120ms, transform 90ms;
}
.timer-btn:hover { opacity: 1; }
.timer-btn:active { transform: translateY(1px); }
.timer-btn.principal { width: 40px; height: 40px; opacity: 0.95; }
.timer-btn .material-symbols-rounded { font-size: 19px; }
/* El interruptor del encadenado. Es un interruptor y no un botón más porque
   no hace nada ahora: dice cómo se va a portar el nodo cuando acabe la fase,
   y eso se enseña encendido o apagado, no pulsado. */
.timer-auto {
  display: flex; align-items: center; gap: 7px;
  background: none; border: none; padding: 0; cursor: pointer;
  font-family: var(--font-body); font-size: 10.5px; font-weight: 600;
  opacity: 0.6; transition: opacity 120ms;
}
.timer-auto:hover, .timer-auto.on { opacity: 0.95; }
.timer-auto-carril {
  flex: 0 0 auto;
  width: 26px; height: 15px; border-radius: 99px;
  border: 1.5px solid currentColor; box-sizing: border-box;
  display: flex; align-items: center; padding: 1.5px;
  transition: background 140ms;
}
.timer-auto-carril > i {
  display: block; width: 9px; height: 9px; border-radius: 50%;
  transition: transform 140ms var(--e-out, ease);
}
.timer-auto.on .timer-auto-carril > i { transform: translateX(11px); }

/* ============================================
   NODO DE CÓDIGO
   ============================================ */
/* El azul oscuro con el degradado radial ES este nodo: por eso su fondo no se
   puede cambiar. Lo que sí se cambia es el título y su barra. El color va
   fijo y no por variables del tema, porque un bloque de código se ve igual de
   noche que de día — como en cualquier editor. */
.code-card .item-card {
  padding: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background:
    radial-gradient(120% 90% at 12% 0%, #2A3F6B 0%, rgba(42,63,107,0) 60%),
    radial-gradient(90% 70% at 100% 100%, #1B2E52 0%, rgba(27,46,82,0) 55%),
    #131C2E;
  border-color: #0C1220;
}
.code-bar {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 9px;
  padding: 7px 11px;
  border-bottom: 1px solid rgba(255,255,255,0.09);
  font-size: 11.5px;
}
.code-dots { display: flex; gap: 5px; flex: 0 0 auto; }
.code-dots i { width: 8px; height: 8px; border-radius: 50%; background: rgba(255,255,255,0.22); }
.code-title {
  font-family: var(--font-mono);
  font-weight: 700;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  cursor: text;
}
.code-title.vacio { opacity: 0.45; font-style: italic; font-weight: 500; }
.code-title-input {
  font-family: var(--font-mono); font-weight: 700; font-size: 11.5px;
  background: rgba(255,255,255,0.10); border: none; outline: none;
  border-radius: 4px; padding: 2px 6px; min-width: 0; flex: 1;
}
/* La insignia del lenguaje va en gris neutro y NO se tiñe con el color que se
   le ponga a la barra: es un dato, no decoración, y con una barra amarilla o
   verde se volvía ilegible. Lleva su propio fondo, oscuro sobre claro y claro
   sobre oscuro, sin depender del color elegido. */
.code-lang {
  margin-left: auto; flex: 0 0 auto;
  font-family: var(--font-mono); font-size: 10px; font-weight: 700;
  letter-spacing: 0.05em; text-transform: uppercase;
  background: #E7E9EE;
  color: #4A5566;
  border: 1px solid rgba(0,0,0,0.10);
  border-radius: 4px; padding: 2px 6px;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .code-lang {
    background: #2A3141; color: #A9B6CC; border-color: rgba(255,255,255,0.10);
  }
}
:root[data-theme="dark"] .code-lang {
  background: #2A3141; color: #A9B6CC; border-color: rgba(255,255,255,0.10);
}
/* El resaltado va detrás y el textarea encima, transparente: así se escribe
   con el cursor de siempre y a la vez se ven los colores. Las dos capas TIENEN
   que compartir tipografía, tamaño, interlineado y relleno al píxel, o el
   texto que se escribe baila sobre el de colores. */
.code-scroll { position: relative; flex: 1; min-height: 0; }
.code-pre, .code-area {
  margin: 0;
  padding: 12px 14px;
  font-family: var(--font-mono), 'JetBrains Mono', ui-monospace, monospace;
  font-size: calc(12.5px * var(--node-scale, 1));
  line-height: 1.55;
  tab-size: 2;
  white-space: pre;
  word-break: normal;
  border: 0;
}
.code-pre {
  position: absolute; inset: 0;
  /* Sin barra propia: a esta capa la desplaza el JS siguiendo a la de
     escribir, y una barra suya cambiaba el ancho util y descuadraba las dos. */
  overflow: hidden;
  color: #C9D6EE;
  background: none;
}
.code-pre code.hljs { background: none; padding: 0; font: inherit; color: inherit; display: block; }
.code-area {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  resize: none; outline: none;
  background: transparent;
  color: transparent;
  caret-color: #9FC46E;
  overflow: auto;
}
.code-area::selection { background: rgba(159,196,110,0.30); }
.code-area::placeholder { color: rgba(201,214,238,0.35); }
/* Los colores del resaltador, en la gama del nodo.
   Antes solo estaban cubiertas ocho clases y el resaltador emite muchas más,
   así que casi todo caía en el color base y el código se veía de dos colores.
   Aquí está la lista entera de highlight.js, repartida por familias: lo que
   manda (palabras clave) en rosa, los valores en naranja, el texto en verde,
   los nombres en azul, los tipos en turquesa y lo accesorio en gris. */
.code-card .hljs-keyword,
.code-card .hljs-selector-tag,
.code-card .hljs-literal,
.code-card .hljs-template-tag,
.code-card .hljs-doctag { color: #E88BC8; }

.code-card .hljs-string,
.code-card .hljs-meta .hljs-string,
.code-card .hljs-regexp,
.code-card .hljs-char.escape_,
.code-card .hljs-addition { color: #9FC46E; }

.code-card .hljs-number,
.code-card .hljs-symbol,
.code-card .hljs-bullet,
.code-card .hljs-quote,
.code-card .hljs-selector-attr,
.code-card .hljs-selector-pseudo { color: #E9B872; }

.code-card .hljs-comment { color: #6E7E9B; font-style: italic; }

.code-card .hljs-title,
.code-card .hljs-title.function_,
.code-card .hljs-title.function_.invoke__,
.code-card .hljs-name,
.code-card .hljs-section,
.code-card .hljs-selector-id { color: #78C6E8; }

.code-card .hljs-title.class_,
.code-card .hljs-title.class_.inherited__,
.code-card .hljs-built_in,
.code-card .hljs-type,
.code-card .hljs-selector-class { color: #6FD3C0; }

.code-card .hljs-attr,
.code-card .hljs-attribute,
.code-card .hljs-property,
.code-card .hljs-variable,
.code-card .hljs-template-variable,
.code-card .hljs-params,
.code-card .hljs-subst { color: #C7B6F0; }

.code-card .hljs-variable.language_,
.code-card .hljs-variable.constant_,
.code-card .hljs-operator,
.code-card .hljs-punctuation { color: #F0A868; }

.code-card .hljs-meta,
.code-card .hljs-meta .hljs-keyword,
.code-card .hljs-meta .hljs-prompt_,
.code-card .hljs-tag,
.code-card .hljs-link { color: #8FA6C8; }

.code-card .hljs-deletion { color: #E8706A; }
.code-card .hljs-emphasis { font-style: italic; }
.code-card .hljs-strong { font-weight: 700; }
.code-card .hljs-formula,
.code-card .hljs-code { color: #B9C8E2; }
/* Lista de lenguajes de la barra del nodo */
.ctx-lang-list { display: flex; flex-direction: column; gap: 1px; max-height: 300px; overflow-y: auto; }
.ctx-lang-item {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 6px 9px; border: none; background: none; cursor: pointer;
  font-size: 12.5px; color: var(--ink); border-radius: 5px; text-align: left;
}
.ctx-lang-item:hover { background: var(--bg-2); }
/* El elegido, con la pareja de colores puesta a mano y no con variables del
   tema. `--olive-l` es un verde CLARO que no cambia en modo oscuro, mientras
   `--ink` sí se vuelve casi blanco: el resultado era el nombre del lenguaje
   en blanco sobre verde claro, es decir, invisible justo en el que estabas
   usando. Aquí cada tema lleva su pareja. */
.ctx-lang-item.active { background: var(--olive-l); color: var(--ink); font-weight: 700; }
.ctx-lang-item.active .material-symbols-rounded { color: var(--olive-texto); }
.ctx-lang-item .material-symbols-rounded { font-size: 15px; color: var(--olive-texto); }

/* ============================================
   FILE NODE
   ============================================ */
/* La tarjeta de un archivo se pinta SIEMPRE clara: su color base es el blanco,
   elegido a propósito, no el papel del tema. Así que su texto tampoco puede
   seguir al tema — en modo oscuro `--ink` es casi blanco y el nombre del
   archivo desaparecía sobre el fondo blanco. Aquí se clavan los valores del
   tema claro para todo lo que va dentro de la tarjeta, y con eso vale para el
   nombre, el tamaño, la leyenda y los avisos de "sin vista previa". */
.file-card {
  --ink:       #1A1A1A;
  --ink-2:     #595459;
  --ink-3:     #8E8A8E;
  --paper:     #FAF9F6;
  --paper-2:   #F3F2EE;
  --line:      #595459;
  --line-soft: rgba(89,84,89,0.22);
  --bg-2:      #E2E1E1;
}
.file-card .item-card { background: var(--paper); }
.file-empty {
  width: 100%; height: 100%; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 6px;
  color: var(--ink-3); cursor: pointer; padding: 12px;
}
.file-empty:hover { color: var(--olive-texto); background: var(--olive-l); }
.file-empty .material-symbols-rounded { font-size: 30px; }

.file-compact {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; padding: 14px 12px; text-align: center;
}
.file-icon {
  width: 52px; height: 64px; border-radius: 4px; flex-shrink: 0;
  background: var(--paper); border: 1.5px solid var(--line);
  box-shadow: 1px 1px 0 var(--line);
  display: flex; align-items: flex-end; justify-content: center; position: relative;
  overflow: hidden;
}
/* colored bottom band carrying the type label */
.file-icon::after {
  content: ''; position: absolute; top: 0; right: 0; width: 16px; height: 16px;
  background: linear-gradient(225deg, var(--bg-2) 50%, transparent 50%);
}
.file-icon-label {
  width: 100%; padding: 3px 0; text-align: center;
  background: var(--file-accent, #595459); color: #fff;
  font-family: var(--font-display); font-weight: 800; font-size: 13px; letter-spacing: 0.02em;
}
.file-icon-sm { width: 20px; height: 26px; box-shadow: none; }
.file-icon-sm .file-icon-label { font-size: 8px; padding: 2px 0; }
.file-name { font-weight: 600; font-size: 12.5px; color: var(--ink); line-height: 1.3; word-break: break-word; max-width: 100%; }
.file-size { font-family: var(--font-mono); font-size: 11px; color: var(--ink-3); }

/* Uploading state */
.file-uploading { display: flex; align-items: center; justify-content: center; }
.file-uploading .file-icon { width: 90px; height: 70px; flex-direction: column; align-items: stretch; justify-content: center; gap: 8px; padding: 10px; }
.file-uploading .file-icon-label { background: none; color: var(--ink-3); font-family: var(--font-body); font-weight: 700; font-size: 11px; }
.file-progress { width: 100%; height: 5px; border-radius: 3px; background: var(--bg-2); overflow: hidden; }
.file-progress-bar { height: 100%; background: var(--olive); border-radius: 3px; transition: width 120ms linear; }

/* Preview state — fills with the first page (no gray margins); double-click opens the viewer */
.file-preview { flex: 1; min-height: 0; overflow: hidden; background: #fff; position: relative; }
/* La vista previa no se toca —es una miniatura, no una aplicación— salvo el
   vídeo y el audio, que existen precisamente para darles al play. */
.file-preview > * { pointer-events: none; }
.file-preview > video,
.file-preview > .file-audio-wrap,
.file-preview .file-media { pointer-events: auto; }
.file-preview > video { width: 100%; height: 100%; object-fit: contain; background: #000; display: block; }
.file-audio-wrap {
  width: 100%; height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  padding: 10px; box-sizing: border-box; background: var(--paper);
}
.file-audio-wrap .file-media { width: 100%; }
.file-viewer-body.kind-video, .file-viewer-body.kind-audio { align-items: center; justify-content: center; }
.file-viewer-body.kind-video video { max-width: 100%; max-height: 100%; box-shadow: 0 4px 18px rgba(0,0,0,0.4); border-radius: 2px; background: #000; }
.file-viewer-body.kind-audio audio { width: min(560px, 100%); }
.file-preview img { width: 100%; height: 100%; object-fit: cover; object-position: top center; display: block; }
.file-preview iframe { width: 100%; height: 100%; border: none; background: #fff; }
/* Un reproductor SÍ tiene que recibir los clics, o no hay forma de darle a
   "play" ni de mover la barra (el resto del contenido de la vista previa se
   deja "sordo" a propósito, para que el doble clic abra el visor). */
.file-preview .file-media { pointer-events: auto; }
.file-preview .file-video-wrap { position: relative; width: 100%; height: 100%; pointer-events: auto; }
.file-preview video.file-media { width: 100%; height: 100%; display: block; background: #000; object-fit: contain; }
/* Capa por la que se arrastra el nodo: cubre el vídeo menos los 46 px de
   abajo, que es donde Chromium pinta su barra de controles. Sin esto el
   reproductor se quedaba TODOS los clics y el nodo no se podía mover si no
   era rodeándolo con un recuadro de selección. */
.file-video-drag { position: absolute; left: 0; right: 0; top: 0; bottom: 46px; cursor: grab; }
.file-audio-wrap {
  pointer-events: auto;
  width: 100%; height: 100%; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 12px; padding: 14px;
}
.file-audio-wrap audio { width: 100%; max-width: 320px; }
.file-viewer-audio { display: flex; flex-direction: column; align-items: center; gap: 18px; margin: auto; }
.file-viewer-audio audio { width: min(460px, 80vw); }
.file-viewer-body video { max-width: 100%; max-height: 100%; margin: auto; display: block; background: #000; }
/* Office/text content is rendered at page width then scaled down to the node, like an image */
.file-page-scale { transform-origin: top left; }
.file-preview .file-page-scale { position: absolute; top: 0; left: 0; }
.file-text-preview { margin: 0; padding: 12px; font-family: var(--font-mono); font-size: 11.5px; line-height: 1.5; color: var(--ink); white-space: pre-wrap; word-break: break-word; }
.file-doc-html { padding: 18px 22px; background: #fff; color: #1a1a1a; font-family: var(--font-body); font-size: 13px; line-height: 1.55; }
.file-xlsx table { border-collapse: collapse; width: 100%; }
.file-xlsx td, .file-xlsx th { border: 1px solid #d0d0d0; padding: 4px 8px; font-size: 12px; }
.file-hoja { font-weight: 800; font-size: 12px; color: #217346; margin-bottom: 6px; letter-spacing: 0.02em; }
/* PowerPoint / Impress: una ficha por diapositiva con su texto */
.file-slides { display: flex; flex-direction: column; gap: 14px; }
.file-slide {
  position: relative; border: 1.5px solid #d8d5d8; border-radius: 4px;
  padding: 14px 16px 14px 42px; background: #fff; min-height: 64px;
}
.file-slide-num {
  position: absolute; left: 12px; top: 13px;
  width: 20px; height: 20px; border-radius: 3px;
  background: #D24726; color: #fff;
  font-family: var(--font-display); font-weight: 800; font-size: 11px;
  display: flex; align-items: center; justify-content: center;
}
.file-slide h2 { font-size: 15px; font-weight: 800; margin: 0 0 6px; color: #1a1a1a; }
.file-slide p { margin: 0 0 4px; font-size: 12.5px; }
.file-slide-vacia { color: #8E8A8E; font-style: italic; }
.file-doc-html h1 { font-size: 18px; font-weight: 800; margin: 0 0 8px; color: #3d5a80; }
.file-doc-html h2 { font-size: 15px; font-weight: 700; margin: 12px 0 6px; }
.file-doc-html p { margin: 0 0 8px; }
.file-doc-html ul, .file-doc-html ol { margin: 0 0 8px; padding-left: 20px; }
.file-preview-empty {
  width: 100%; height: 100%; min-height: 200px; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 8px; color: var(--ink-3);
}
.file-preview-empty .material-symbols-rounded { font-size: 40px; }
.file-info-row {
  flex-shrink: 0; display: flex; align-items: center; gap: 10px; justify-content: space-between;
  padding: 7px 12px; background: var(--paper-2); border-top: 1.5px solid var(--line-soft);
  font-size: 11.5px;
}
.file-info-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink-2); font-weight: 600; }
.file-info-size { font-family: var(--font-mono); color: var(--ink-3); flex-shrink: 0; }

/* Example/legacy nodes (title heading, color swatch, mood image) */
.title-card { width: 100%; height: 100%; display: flex; align-items: center; }
.title-text { font-family: var(--font-display); font-weight: 800; font-size: calc(34px * var(--node-scale, 1)); letter-spacing: -0.02em; color: var(--ink); line-height: 1.05; }
.swatch-card .item-card { padding: 12px; display: flex; flex-direction: column; gap: 8px; }
.swatch-title { font-weight: 700; font-size: 12px; color: var(--ink-2); }
.swatch-row { flex: 1; display: flex; gap: 6px; min-height: 0; }
.swatch-chip { flex: 1; border-radius: 3px; border: 1.5px solid var(--line-soft); display: flex; align-items: flex-end; justify-content: center; padding-bottom: 4px; }
.swatch-hex { font-family: var(--font-mono); font-size: 8.5px; color: rgba(255,255,255,0.92); text-shadow: 0 1px 2px rgba(0,0,0,0.55); }
.image-mood { display: flex; align-items: flex-end; }
.image-mood-caption { padding: 8px 10px; font-size: 12px; font-weight: 600; color: #fff; text-shadow: 0 1px 3px rgba(0,0,0,0.6); }

/* File viewer modal (read-only, paginated, dark backdrop) */
.file-viewer {
  background: var(--paper); border-radius: 4px; box-shadow: var(--pop-deep);
  width: min(900px, calc(100vw - 60px)); height: min(90vh, calc(100vh - 50px));
  display: flex; flex-direction: column; overflow: hidden;
  animation: scale-in 220ms var(--e-out);
}
.file-viewer-head { display: flex; align-items: center; gap: 10px; padding: 10px 16px; border-bottom: 1.5px solid var(--line); background: var(--paper-2); }
.file-viewer-name { flex: 1; min-width: 0; font-weight: 700; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-viewer-body { flex: 1; min-height: 0; overflow: auto; background: #525659; display: flex; flex-direction: column; align-items: center; padding: 20px; gap: 16px; }
.file-viewer-body.kind-pdf { padding: 0; }
.file-viewer-body.kind-pdf iframe { width: 100%; height: 100%; border: none; }
.file-viewer-body.kind-image img { max-width: 100%; height: auto; box-shadow: 0 4px 18px rgba(0,0,0,0.4); border-radius: 2px; }
.file-viewer-body .file-doc-page { width: min(820px, 100%); background: #fff; box-shadow: 0 4px 18px rgba(0,0,0,0.4); border-radius: 2px; padding: 48px 56px; }
/* Excel sheets are landscape/wide, not an A4 portrait page */
.file-viewer-body.kind-excel { padding: 16px; }
.file-viewer-body.kind-excel .file-doc-page { width: min(1200px, 100%); padding: 0; overflow-x: auto; }
.file-viewer-body.kind-excel .file-xlsx { padding: 0; }
.file-viewer-body.kind-excel .file-xlsx table { width: max-content; min-width: 100%; }
.file-viewer-body .file-text-preview { width: min(820px, 100%); background: #fff; box-shadow: 0 4px 18px rgba(0,0,0,0.4); border-radius: 2px; padding: 24px; min-height: 100%; }
.file-viewer-body .file-preview-empty { color: rgba(255,255,255,0.7); margin: auto; }

/* =====================================================
   KO-FI DONATION & SUPPORT SYSTEMS
   ===================================================== */

/* Topbar support button */
.kofi-topbar-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 18px;
  background: linear-gradient(135deg, #E6544F, #FF5E5B, #B83A36, #E6544F);
  background-size: 300% 100%;
  animation: kofi-gradient-shift 6s ease infinite;
  color: white !important;
  border-radius: 99px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 13.5px;
  transition: transform 140ms var(--e-out), box-shadow 140ms var(--e-out), border-color 140ms;
  box-shadow: 0 4px 16px rgba(230, 84, 79, 0.4), 0 0 8px rgba(255, 94, 91, 0.15);
  margin-right: 12px;
  border: 1.5px solid rgba(255, 255, 255, 0.25);
  position: relative;
  z-index: 10;
  cursor: pointer;
  text-decoration: none;
  /* Sombra en el texto para que resalte sobre el gradiente y el glow */
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
}
.kofi-topbar-btn .kofi-icon,
.kofi-topbar-btn span { position: relative; z-index: 2; }
.kofi-topbar-btn::before {
  content: '';
  position: absolute;
  top: -4px; left: -4px; right: -4px; bottom: -4px;
  border-radius: 99px;
  background: conic-gradient(from 0deg, #E6544F, #FF5E5B, #B83A36, #FF5E5B, #E6544F);
  filter: blur(5px);
  animation: lava-sway 12s ease-in-out infinite;
  z-index: -1;
  pointer-events: none;
  opacity: 0.25;
  transition: opacity 250ms ease, filter 250ms ease;
}
.kofi-topbar-btn::after {
  content: '';
  position: absolute;
  top: -3px; left: -3px; right: -3px; bottom: -3px;
  border-radius: 99px;
  background: radial-gradient(circle at 30% 30%, rgba(255, 255, 255, 0.3) 0%, rgba(255, 94, 91, 0.2) 60%, transparent 100%);
  filter: blur(2px);
  animation: crescent-glow 8s ease-in-out infinite;
  z-index: -1;
  pointer-events: none;
  opacity: 0.25;
  transition: opacity 250ms ease, filter 250ms ease;
}
.kofi-topbar-btn:hover {
  transform: translateY(-2px) scale(1.04);
  box-shadow: 0 8px 24px rgba(255, 94, 91, 0.65), 0 0 15px rgba(255, 215, 0, 0.45);
  border-color: rgba(255, 255, 255, 0.8);
}
.kofi-topbar-btn:hover::before {
  animation: lava-sway 3s ease-in-out infinite;
  opacity: 0.85;
  filter: blur(8px);
}
.kofi-topbar-btn:hover::after {
  animation: crescent-glow 2s ease-in-out infinite;
  opacity: 0.95;
  filter: blur(4px);
}
.kofi-topbar-btn .kofi-icon {
  font-size: 18px;
  animation: cup-bounce 2s ease-in-out infinite;
}
@keyframes cup-bounce {
  0%, 100% { transform: translateY(0) rotate(0); }
  50% { transform: translateY(-2px) rotate(-8deg); }
}
@keyframes kofi-gradient-shift {
  0% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}

/* Sidebar support card */
.kofi-sidebar-card {
  margin-top: 14px;
  padding: 12px;
  background: var(--paper-2);
  border: 1.5px solid var(--line);
  border-radius: 4px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  box-shadow: var(--pop-sm);
}
.kofi-card-title {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 13.5px;
  color: var(--wine-texto);
}
.kofi-card-title .material-symbols-rounded {
  font-size: 15px;
  animation: heart-pulse 1.6s ease-in-out infinite;
}
@keyframes heart-pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.15); }
}
.kofi-card-text {
  margin: 0;
  font-size: 11px;
  line-height: 1.4;
  color: var(--ink-2);
}
.kofi-card-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 6px 12px;
  background: linear-gradient(135deg, #FF5E5B, #E6544F, #D84B48, #FF5E5B);
  background-size: 300% 100%;
  animation: kofi-gradient-shift 8s ease infinite;
  color: white;
  border-radius: 2px;
  border: 1.5px solid rgba(255, 255, 255, 0.2);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 12px;
  transition: transform 120ms, box-shadow 120ms;
  box-shadow: 0 3px 10px rgba(230, 84, 79, 0.25);
  width: 100%;
  position: relative;
  z-index: 5;
}
.kofi-card-btn::before {
  content: '';
  position: absolute;
  top: -6px; left: -6px; right: -6px; bottom: -6px;
  border-radius: 2px;
  background: conic-gradient(from 0deg, #FFFFFF, #90B968, #595459, #E6544F, #FFFFFF);
  filter: blur(6px);
  animation: lava-sway 18s ease-in-out infinite;
  z-index: -1;
  pointer-events: none;
}
.kofi-card-btn::after {
  content: '';
  position: absolute;
  top: -4px; left: -4px; right: -4px; bottom: -4px;
  border-radius: 2px;
  background: radial-gradient(circle at 15% 40%, #FFFFFF 0%, rgba(255, 255, 255, 0.75) 30%, rgba(144, 185, 104, 0.25) 55%, transparent 75%);
  filter: blur(2px);
  animation: crescent-glow 14s ease-in-out infinite;
  z-index: -1;
  pointer-events: none;
}
.kofi-card-btn:hover {
  transform: translateY(-2px) scale(1.03);
  box-shadow: 0 5px 15px rgba(230, 84, 79, 0.4);
}
.kofi-card-btn:hover::before, .kofi-card-btn:hover::after {
  animation: none;
  opacity: 0.9;
}
.kofi-card-btn .material-symbols-rounded {
  font-size: 14px;
}

/* En modo oscuro el botón es más sólido y vibrante, pero el halo blanco se
   modera para que el texto "Support" siga siendo legible (antes lo lavaba). */
[data-theme="dark"] .kofi-topbar-btn {
  background: linear-gradient(135deg, #E6544F, #FF6B67, #C7423D, #E6544F);
  background-size: 300% 100%;
  animation: kofi-gradient-shift 6s ease infinite;
  border-color: rgba(255, 255, 255, 0.45);
  box-shadow: 0 4px 18px rgba(230, 84, 79, 0.55), 0 0 12px rgba(255, 107, 103, 0.35);
}
[data-theme="dark"] .kofi-topbar-btn::before, [data-theme="dark"] .kofi-card-btn::before {
  background: conic-gradient(from 0deg, #FF6B67, #E6544F, #B83A36, #FF6B67);
  filter: blur(9px);
  opacity: 0.5;
}
[data-theme="dark"] .kofi-topbar-btn::after, [data-theme="dark"] .kofi-card-btn::after {
  background: radial-gradient(circle at 30% 30%, rgba(255, 255, 255, 0.35) 0%, rgba(255, 107, 103, 0.25) 55%, transparent 100%);
  filter: blur(2px);
  opacity: 0.4;
}

@keyframes pulse-bell {
  0% {
    transform: scale(1);
    opacity: 0.85;
  }
  100% {
    transform: scale(1.18);
    opacity: 1;
    filter: drop-shadow(0 0 8px var(--wine));
  }
}

@keyframes support-glow {
  0%, 100% {
    box-shadow: 0 2.5px 6px rgba(230, 84, 79, 0.25), 0 0 4px rgba(230, 84, 79, 0.2);
  }
  50% {
    box-shadow: 0 2.5px 6px rgba(230, 84, 79, 0.25), 0 0 14px rgba(230, 84, 79, 0.65), 0 0 20px rgba(144, 185, 104, 0.35);
  }
}

/* Custom Context Menu */
.custom-context-menu {
  background: var(--paper);
  border: 1.5px solid var(--line);
  border-radius: 4px;
  box-shadow: var(--pop);
  padding: 4px;
  min-width: 170px;
  max-width: 250px;
  display: flex;
  flex-direction: column;
  color: var(--ink);
  font-family: var(--font-display);
}
.custom-context-menu-wrapper {
  display: flex;
  flex-direction: column;
}
.ctx-menu-header {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 8px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  color: var(--wine-texto);
  letter-spacing: 0.05em;
  font-family: var(--font-mono);
}
.ctx-menu-header .material-symbols-rounded {
  font-size: 13px !important;
}
.ctx-menu-suggestions {
  display: flex;
  flex-direction: column;
  margin-bottom: 2px;
  gap: 2px;
}
.ctx-menu-no-suggestions {
  padding: 6px 8px;
  font-size: 12px;
  color: var(--ink-3);
}
.ctx-menu-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: 2px;
  font-size: 12.5px;
  font-weight: 600;
  text-align: left;
  background: transparent;
  border: none;
  cursor: pointer;
  color: var(--ink);
  transition: background 100ms;
}
.ctx-menu-item:hover {
  background: var(--line-softer);
}
.ctx-menu-item .material-symbols-rounded {
  font-size: 15px;
  color: var(--ink-2);
}
.ctx-menu-item.suggestion-btn {
  color: var(--olive-texto);
  font-size: 13px;
  background: color-mix(in srgb, var(--olive) 12%, transparent);
  margin-bottom: 2px;
  border: 1px dashed var(--olive);
}
.ctx-menu-item.suggestion-btn:hover {
  background: color-mix(in srgb, var(--olive) 20%, transparent);
}
.ctx-menu-divider {
  height: 1.5px;
  background: var(--line-soft);
  margin: 4px 6px;
}
[data-theme="dark"] .custom-context-menu {
  background: #3A383A;
  border-color: var(--line);
}
[data-theme="dark"] .ctx-menu-item:hover {
  background: #2A282A;
}

/* ==========================================================================
   FRAME ITEM (MARCO DE AGRUPACIÓN)
   ========================================================================== */
.frame-card {
  border: 2px dashed var(--frame-border, var(--line));
  border-radius: 6px;
  background: var(--frame-bg, transparent);
  transition: border-color 140ms ease, background 140ms ease, box-shadow 140ms ease;
  overflow: hidden;
  pointer-events: none;
}

/* Selección: anillo por box-shadow en vez de reemplazar el border-color, para que
   el color elegido del marco siga viéndose cuando está seleccionado */
.frame-card:hover, .item.selected .frame-card {
  box-shadow: 0 0 0 2px var(--wine, #7B2D26);
}

.frame-header {
  background: var(--frame-header-bg, color-mix(in srgb, var(--line-soft, #E5E1DD) 25%, transparent));
}
/* En modo oscuro --line-soft es casi negro; usamos un gris claro translúcido
   para que la franja del título contraste con el lienzo sin deslumbrar
   (solo cuando el marco no tiene color propio) */
[data-theme="dark"] .frame-card.c-transparent .frame-header,
[data-theme="dark"] .frame-card:not([class*="c-"]) .frame-header {
  background: rgba(240, 238, 240, 0.13);
}

/* Colores de los Frames: borde a color pleno + fondo con tinte perceptible +
   franja del título tintada. Valores rgba fijos para que se vean igual sobre
   cualquier fondo de lienzo (los porcentajes bajos anteriores eran invisibles). */
.frame-card.c-white  { --frame-border: #B5B2B5; --frame-bg: rgba(255,255,255,0.55); --frame-header-bg: rgba(255,255,255,0.85); }
.frame-card.c-mist   { --frame-border: #9E9C9E; --frame-bg: rgba(190,188,190,0.32); --frame-header-bg: rgba(190,188,190,0.55); }
.frame-card.c-cream  { --frame-border: #E5D48F; --frame-bg: rgba(254,247,224,0.55); --frame-header-bg: rgba(247,225,150,0.6); }
.frame-card.c-sage   { --frame-border: #B9CE96; --frame-bg: rgba(232,240,218,0.55); --frame-header-bg: rgba(200,222,160,0.6); }
.frame-card.c-rose   { --frame-border: #E9A8A3; --frame-bg: rgba(251,223,221,0.55); --frame-header-bg: rgba(245,190,186,0.6); }
.frame-card.c-stone  { --frame-border: #B0AEB6; --frame-bg: rgba(220,220,225,0.4); --frame-header-bg: rgba(200,200,210,0.55); }
.frame-card.c-yellow { --frame-border: #E7C25A; --frame-bg: rgba(247,218,132,0.32); --frame-header-bg: rgba(247,218,132,0.55); }
.frame-card.c-orange { --frame-border: #E88B45; --frame-bg: rgba(245,166,107,0.28); --frame-header-bg: rgba(245,166,107,0.5); }
.frame-card.c-red    { --frame-border: #E6544F; --frame-bg: rgba(230,84,79,0.16); --frame-header-bg: rgba(230,84,79,0.3); }
.frame-card.c-pink   { --frame-border: #DB6FA6; --frame-bg: rgba(229,138,184,0.24); --frame-header-bg: rgba(229,138,184,0.42); }
.frame-card.c-purple { --frame-border: #9E6FC2; --frame-bg: rgba(176,132,208,0.22); --frame-header-bg: rgba(176,132,208,0.4); }
.frame-card.c-sky    { --frame-border: #6FAEDC; --frame-bg: rgba(138,193,232,0.26); --frame-header-bg: rgba(138,193,232,0.45); }
.frame-card.c-olive  { --frame-border: #6A8546; --frame-bg: rgba(106,133,70,0.18); --frame-header-bg: rgba(106,133,70,0.32); }
.frame-card.c-wine   { --frame-border: #993844; --frame-bg: rgba(153,56,68,0.18); --frame-header-bg: rgba(153,56,68,0.32); }
.frame-card.c-dark   { --frame-border: #595459; --frame-bg: rgba(89,84,89,0.2); --frame-header-bg: rgba(89,84,89,0.35); }
.frame-card.c-transparent { --frame-border: var(--line); --frame-bg: transparent; }

/* ==========================================================================
   BIG TITLE ITEM (TÍTULO GIGANTE TRANSPARENTE)
   ========================================================================== */
.bigtitle-card {
  border: 1px dashed transparent;
  border-radius: 4px;
  transition: border-color 140ms ease;
  box-sizing: border-box;
}

.item:hover .bigtitle-card, .item.selected .bigtitle-card {
  border-color: var(--line-soft, #E5E1DD);
}

.bigtitle-edit { font-family: var(--fuente-nodo, var(--font-display)); }

/* Tamaños H1–H4 del título (ContextSidebar.jsx). */
.niveles-titulo { display: flex; gap: 6px; margin-top: 4px; }
.niveles-titulo__boton { min-width: 40px; font-family: var(--font-display); font-weight: 800; }
.niveles-titulo__boton--h1 { font-size: 16px; }
.niveles-titulo__boton--h2 { font-size: 14px; }
.niveles-titulo__boton--h3 { font-size: 12.5px; }
.niveles-titulo__boton--h4 { font-size: 11px; }

/* Conexión con el servidor, en la barra de Inicio (PanelServidor.jsx). */
.panel-servidor {
  display: flex; flex-direction: column; gap: 8px; margin-top: 8px;
  padding: 12px 14px; border-radius: 12px;
  background: var(--bg-card); border: 1.5px solid var(--line-soft);
}
.panel-servidor__estado { display: flex; align-items: center; gap: 8px; font-size: 12.5px; font-weight: 600; color: var(--ink-2); }
.panel-servidor__estado .material-symbols-rounded { font-size: 18px; flex-shrink: 0; }
.panel-servidor__estado--al-dia .material-symbols-rounded { color: var(--olive-texto); }
.panel-servidor__estado--subiendo .material-symbols-rounded { animation: spin 1.5s linear infinite; }
.panel-servidor__estado--sin-red { color: var(--wine-texto); }
.panel-servidor__boton {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  padding: 7px 10px; border-radius: 6px; font-size: 12.5px; font-weight: 600;
  background: var(--olive-l); color: var(--ink);
}
.panel-servidor__boton:hover { background: var(--olive-2); }
.panel-servidor__boton .material-symbols-rounded { font-size: 17px; }
.panel-servidor__ayuda { margin: 0; font-size: 11px; line-height: 1.4; color: var(--ink-2); }
.panel-servidor__fila { display: flex; gap: 4px; margin-top: 4px; }
.panel-servidor__campo {
  flex: 1; min-width: 0; padding: 5px 7px; border-radius: 6px;
  border: 1.5px solid var(--line-soft); background: var(--paper); color: var(--ink);
  font-family: var(--font-mono); font-size: 10.5px;
}
.panel-servidor__copiar { display: grid; place-items: center; width: 30px; border-radius: 6px; background: var(--bg-2); color: var(--ink); }
.panel-servidor__copiar .material-symbols-rounded { font-size: 16px; }

/* Panel de tipografías (Fuentes.jsx). El nombre va con la letra de la
   interfaz; la muestra "Aa", con la tipografía de la fila (--fuente-nodo). */
.panel-fuente { width: 280px; }
.panel-fuente__busca {
  width: 100%; box-sizing: border-box; margin-bottom: 6px;
  padding: 6px 8px; border-radius: 6px;
  border: 1.5px solid var(--line-soft); background: var(--paper); color: var(--ink);
  font: inherit; font-size: 12.5px;
}
.panel-fuente__busca:focus { outline: none; border-color: var(--line); }
.panel-fuente__lista {
  display: flex; flex-direction: column; gap: 1px;
  max-height: 300px; overflow-y: auto; overscroll-behavior: contain;
}
.panel-fuente__item {
  /* Sin esto, en una columna con scroll las filas se encogen y se pisan. */
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 10px;
  width: 100%; min-height: 34px; padding: 4px 8px; border-radius: 6px;
  text-align: left; color: var(--ink);
}
.panel-fuente__item:hover { background: var(--bg-2); }
.panel-fuente__item--activa { background: var(--olive-l); }
.panel-fuente__item--activa .panel-fuente__nombre { font-weight: 700; }
.panel-fuente__nombre {
  flex: 1 1 auto; min-width: 0;
  font-family: var(--font-body); font-size: 13px; line-height: 1.3;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.panel-fuente__muestra {
  flex: 0 0 44px; text-align: right; overflow: hidden;
  font-family: var(--fuente-nodo, var(--font-body)); font-size: 20px; line-height: 1.2;
  color: var(--ink-2);
}
.panel-fuente__cargar {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  width: 100%; margin-top: 8px; padding: 7px 10px; border-radius: 6px;
  background: var(--olive); color: var(--olive-ink); font-size: 12.5px; font-weight: 700;
}
.panel-fuente__cargar .material-symbols-rounded { font-size: 17px; }
.panel-fuente__aviso { margin-top: 8px; font-size: 11.5px; line-height: 1.4; color: var(--ink-2); }

.bigtitle-edit:empty::before {
  content: attr(data-placeholder);
  color: var(--ink-3, #9A969A);
  font-weight: 400;
  font-style: italic;
  opacity: 0.6;
}

/* ==========================================================================
   MAP ITEM (GOOGLE MAPS)
   ========================================================================== */
.map-card .item-card {
  background: var(--paper);
  border: 1.5px solid var(--line);
  border-radius: 4px;
  box-shadow: var(--pop-sm);
  transition: box-shadow 140ms ease, border-color 140ms ease;
}

.item:hover .map-card .item-card, .item.selected .map-card .item-card {
  border-color: var(--wine, #7B2D26);
  box-shadow: var(--pop-md);
}

/* ==========================================================================
   EXTRA TOOLS POPUP (MENÚ MÁS) & INTERACTIVES
   ========================================================================== */
.extra-tools-popout {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: 8px;
  z-index: 401;
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 140px;
  border-radius: 8px;
  background: var(--menu-fondo);
  border: 1.5px solid var(--line);
  box-shadow: var(--pop-md);
  animation: ctx-slide-in 180ms var(--e-out);
}

[data-theme="dark"] .extra-tools-popout {
  background: #3A383A;
  border-color: var(--line);
  box-shadow: 0 8px 24px rgba(0,0,0,0.35);
}

.extra-tools-title {
  font-family: var(--font-display);
  font-size: 9.5px;
  font-weight: 800;
  color: var(--text-soft, #595459);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 4px;
  padding-left: 6px;
}

/* ── More como caracol ──
   La concha da media vuelta al pasar el ratón y una entera al abrir. La tira
   se descubre de derecha a izquierda (sale de la concha) y cada nodo entra
   con su retraso y su vaivén (--retraso, --ola), de modo que el conjunto se
   estira como una serpiente. Cerrando, se recoge hacia la concha. */
.mas-boton .mas-concha { transition: transform 700ms var(--muelle); }
.mas-boton:hover .mas-concha { transform: rotate(-40deg); }
.mas-boton.abierto .mas-concha { transform: rotate(-360deg); }
.mas-serpiente {
  z-index: 401;
  display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: stretch; gap: 0;
  padding: 6px;
  border: 1.5px solid var(--line); border-radius: 14px 8px 8px 14px;
  background: var(--paper);
  box-shadow: var(--pop);
  transform-origin: calc(100% - var(--pico)) 0;
  animation: mas-serpiente-sale 560ms cubic-bezier(0.22, 1, 0.36, 1) both;
}
/* El pico que la une a la concha. */
.mas-serpiente::before {
  content: ''; position: absolute; top: -7px; right: calc(var(--pico) - 7px);
  width: 12px; height: 12px;
  background: var(--paper);
  border-left: 1.5px solid var(--line); border-top: 1.5px solid var(--line);
  transform: rotate(45deg);
}
@keyframes mas-serpiente-sale {
  0%   { clip-path: inset(-12px 0 0 calc(100% - var(--pico) * 2) round 14px); translate: 0 -6px; }
  55%  { translate: 0 3px; }
  80%  { translate: 0 -1px; }
  100% { clip-path: inset(-12px -12px -12px -12px round 14px); translate: 0 0; }
}
.mas-serpiente.cierra { animation: mas-serpiente-vuelve 260ms cubic-bezier(0.55, 0, 0.8, 0.4) both; pointer-events: none; }
@keyframes mas-serpiente-vuelve {
  0%   { clip-path: inset(-12px -12px -12px -12px round 14px); opacity: 1; }
  100% { clip-path: inset(-12px 0 0 calc(100% - var(--pico) * 2) round 14px); opacity: 0.4; }
}
.mas-grupo { display: flex; flex-direction: column; gap: 2px; padding: 0 6px; }
.mas-grupo + .mas-grupo { border-left: 1.5px solid var(--line-soft); }
.mas-grupo-nombre {
  padding: 1px 4px 0;
  font-family: var(--font-mono); font-size: 9px; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink-3);
  animation: mas-nodo-entra 420ms var(--muelle) both;
  animation-delay: 200ms;
}
/* flex-wrap: en una ventana estrecha un grupo entero no cabía y la tira se salía
   por la izquierda («TRUCTURE»); así el grupo se parte en dos filas. */
.mas-grupo-nodos { display: flex; flex-wrap: wrap; gap: 2px; }
.mas-nodo { animation: mas-nodo-entra 520ms var(--muelle) both; animation-delay: var(--retraso, 0ms); }
@keyframes mas-nodo-entra {
  from { opacity: 0; translate: 28px var(--ola, 0px); scale: 0.4; }
  to   { opacity: 1; translate: 0 0; scale: 1; }
}
.mas-serpiente.cierra .mas-nodo { animation: none; }
[data-theme="dark"] .mas-serpiente { background: #3A383A; }
[data-theme="dark"] .mas-serpiente::before { background: #3A383A; }

.extra-tools-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px 10px;
  background: transparent;
  border: none;
  border-radius: 6px;
  text-align: left;
  cursor: pointer;
  transition: all 100ms ease;
}

.extra-tools-btn:hover {
  background: var(--bg-2, #F0EDE9);
}

[data-theme="dark"] .extra-tools-btn:hover {
  background: #4A484A;
}

.extra-tools-icon {
  width: 24px;
  height: 24px;
  border-radius: 4px;
  display: grid;
  place-items: center;
  transition: transform 100ms ease;
}

.extra-tools-btn:hover .extra-tools-icon {
  transform: scale(1.08);
}

.extra-tools-label {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--ink);
}

/* ==========================================================================
   FRAME CLICK TRANSPARENCY
   ========================================================================== */
.item-frame {
  pointer-events: none !important;
}
.item-frame .frame-header,
.item-frame .frame-header *,
.item-frame .handle,
.item-frame .connect-handle {
  pointer-events: auto !important;
}

/* ==========================================================================
   BOTÓN ACTIVO DE LAS BARRAS: el color de acento rebajado, con la tinta del
   acento (las variables cambian solas con el tema).
   ========================================================================== */
.ctx-btn.active {
  background: var(--olive-l) !important;
  color: var(--olive-texto) !important;
}
.ctx-btn.active .material-symbols-rounded,
.ctx-btn.active .ctx-letter {
  color: var(--olive-texto) !important;
}

/* ==========================================================================
   FEEDBACK BUTTON (GITHUB DISCUSSIONS LINK)
   ========================================================================== */
.feedback-topbar-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  background: var(--paper);
  border: 1.5px solid var(--line);
  color: var(--ink-2) !important;
  border-radius: 99px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 12.5px;
  transition: transform 120ms var(--e-out), background 120ms, border-color 120ms;
  margin-right: 12px;
  cursor: pointer;
  text-decoration: none;
  z-index: 10;
}
.feedback-topbar-btn:hover {
  background: var(--bg-2);
  border-color: var(--wine, #7B2D26);
  color: var(--wine-texto) !important;
  transform: translateY(-1px);
}
[data-theme="dark"] .feedback-topbar-btn {
  background: #3A383A;
  border-color: var(--line);
  color: #F0EEF0 !important;
}
[data-theme="dark"] .feedback-topbar-btn:hover {
  background: #2A282A;
  color: #FF8A5B !important;
}

/* ==========================================================================
   BARRA SUPERIOR EN PANTALLAS PEQUENAS

   La barra de NODOS no se encoge. Antes se le quitaban los rotulos por debajo
   de 1440px y se le achicaban los iconos por debajo de 1920px, asi que la misma
   herramienta tenia tres aspectos distintos segun el monitor. Ahora mantiene en
   todas partes el tamano que tenia en 2K, y el sitio sale de otro lado: la ruta
   es una pastilla fija (ocupa igual con dos niveles que con diez) y lo que se
   reduce es lo accesorio de la derecha. Si aun asi no cabe, la barra de nodos
   se desplaza con la rueda en vez de cortarse.
   ========================================================================== */

/* 1920 de ancho es la pantalla mas comun del mundo, y aqui se estaba tratando
   como si fuera pequena: entraba en la misma compresion que un portatil de
   1440 y salia con los botones a 36 px y los huecos a 7. Al lado de un 2K
   parecia otra aplicacion, mas apretada y peor terminada.

   Medido a 1920 con la barra de nodos abierta: con los valores de 2K enteros
   (hueco 12, boton 40) el rail se pasa 6 px; con 11 y 39 cabe exacto, cero
   desbordamiento. Un pixel de diferencia con el 2K, invisible al ojo. Asi que
   1080 se queda practicamente igual que 2K y la compresion de verdad empieza
   por debajo, que es donde de verdad falta sitio. */
@media (max-width: 1920px) {
  .topbar {
    gap: 11px;
    padding: 8px 12px;
  }
  .icon-btn, .volume-ctrl {
    width: 39px;
    height: 39px;
  }
  .icon-btn .material-symbols-rounded {
    font-size: 20px;
  }
  .kofi-topbar-btn, .feedback-topbar-btn {
    margin-right: 6px;
    padding: 7px 13px;
    font-size: 12.5px;
  }

  /* Y la barra de nodos, que es donde de verdad faltaba sitio.

     El detalle que se escapa si se mide en ingles: las etiquetas en espanol son
     mas largas. "Documento" contra "Document", "Tablero" contra "Board",
     "Dibujar" contra "Draw". Medido a 1920 con la aplicacion en espanol, la
     barra se pasaba 40 px: "Dibujar" salia cortado y "Mas" no llegaba a verse.
     En ingles cabia justo, asi que el fallo era invisible desde ahi.

     Se recorta el aire de cada herramienta y no el tamano de los iconos: dos
     pixeles por lado en quince herramientas son treinta, y no se notan. Encoger
     los iconos si se habria notado, y es lo que hacia que 1080 pareciera una
     version apretada de la aplicacion. */
  .tool { padding: 4px 5px; }
  .tool-divider { margin: 0 2px; }
}

/* Por debajo de 1920 ya no cabe holgado: aqui empieza la compresion que antes
   se aplicaba tambien a 1080. */
@media (max-width: 1899px) {
  .topbar {
    gap: 7px;
    padding: 6px 10px;
  }
  .icon-btn, .volume-ctrl {
    width: 36px;
    height: 36px;
  }
  .icon-btn .material-symbols-rounded {
    font-size: 19px;
  }
  .kofi-topbar-btn, .feedback-topbar-btn {
    margin-right: 6px;
    padding: 6px 12px;
    font-size: 12px;
  }
}

/* Feedback y Apoyar pasan a ser iconos redondos: es lo primero que sobra */
@media (max-width: 1680px) {
  .feedback-topbar-btn span:not(.material-symbols-rounded),
  .kofi-topbar-btn span:not(.material-symbols-rounded) {
    display: none;
  }
  .feedback-topbar-btn, .kofi-topbar-btn {
    width: 38px;
    height: 38px;
    padding: 0;
    justify-content: center;
    border-radius: 50%;
    margin-right: 4px;
  }
  .feedback-topbar-btn::before, .feedback-topbar-btn::after,
  .kofi-topbar-btn::before, .kofi-topbar-btn::after {
    border-radius: 50%;
  }
  .migas { max-width: min(460px, 38vw); }
}

@media (max-width: 1440px) {
  .migas { max-width: min(380px, 34vw); }
}

@media (max-width: 1200px) {
  /* El deslizador ya no se esconde: flotando no ocupa ancho. */
  .volume-ctrl {
    margin-right: 0;
  }
  .migas { --migas-ancho-miga: 130px; min-width: 120px; max-width: min(300px, 30vw); }
}

.ms-card-dropdown-item:hover {
  background: var(--line-soft, #E5E1DD) !important;
}

/* Animación global de giro (botón/indicador de sincronización con Drive) */
@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

/* Iconos de proyecto con Material Symbols (los nombres tipo snake_case se
   renderizan como icono; los emojis antiguos se siguen mostrando como texto) */
.ms-recent-emoji .material-symbols-rounded,
.ms-project-emoji .material-symbols-rounded,
.emoji-pick .material-symbols-rounded {
  font-size: inherit;
  line-height: 1;
  vertical-align: middle;
}

/* Iconos de proyecto Fluent Emoji 3D (PNG) — escalan con el tamaño del texto */
.project-icon-img {
  width: 1.15em;
  height: 1.15em;
  object-fit: contain;
  vertical-align: middle;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.25));
  pointer-events: none;
}
.emoji-pick .project-icon-img { width: 20px; height: 20px; }

/* ==========================================================================
   MODO MÓVIL / VENTANA ESTRECHA
   --------------------------------------------------------------------------
   touch.js pone <html data-mobile="1"> cuando el puntero es táctil o la
   ventana baja de 860px, y lo recalcula al redimensionar o girar. Todo lo de
   abajo cuelga de ese atributo, así que la app se reorganiza sola al cambiar
   el tamaño de la ventana sin recargar.

   La idea: la barra de herramientas superior (13 botones que no caben en un
   móvil) pasa a ser un RAÍL VERTICAL en el borde derecho; para retroceder de
   nivel aparece una flecha ← grande arriba a la izquierda; y todo lo que
   colgaba de la barra superior se pliega en un panel "⋯".
   ========================================================================== */

/* Controles que solo existen en móvil: ocultos por defecto. .topbar-tail usa
   display:contents para que en escritorio la barra quede exactamente igual
   que antes de existir este bloque.

   .crumb-back ya NO está aquí: al sustituir la cadena de migas por una sola
   pastilla, la flecha de subir un nivel hace falta también en escritorio. */
.tools-fab,
.topbar-more,
.topbar-tail-scrim,
.ms-side-toggle,
.ms-side-scrim { display: none; }
.topbar-tail { display: contents; }

html[data-mobile="1"] {
  /* Evita el "rebote" y el tirar-para-recargar mientras se panea el lienzo */
  overscroll-behavior: none;
}
html[data-mobile="1"] body {
  overscroll-behavior: none;
  /* Quita el retardo de 300ms y el zoom por doble toque de la propia página */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
/* 100% de alto en móvil incluye la barra de URL, que aparece y desaparece y
   deja la parte de abajo recortada. Cascada de menos a más fiable: vh clásico
   → medida real que escribe touch.js (para navegadores sin dvh) → dvh, que es
   lo correcto donde exista y gana por ir el último. */
html[data-mobile="1"],
html[data-mobile="1"] body,
html[data-mobile="1"] #root {
  height: 100vh;
  height: var(--app-h, 100vh);
  height: 100dvh;
}

/* CAUSA RAÍZ del zoom que se quedaba pegado: por debajo de 16px, el navegador
   móvil AMPLÍA LA PÁGINA ENTERA al enfocar un campo, para que se lea el
   cursor. Ese zoom es del navegador, no de la app: ni los botones − / + ni
   recargar lo deshacen, y Brave además lo recuerda para el sitio. Basta con no
   bajar de 16px en los campos de la interfaz para que nunca se dispare.
   Los textos DENTRO del lienzo van aparte: los escala el zoom del propio
   lienzo, y ahí lo resuelve el ajuste automático al entrar a editar. */
html[data-mobile="1"] input:not([type="range"]):not([type="checkbox"]):not([type="radio"]):not([type="color"]),
html[data-mobile="1"] textarea,
html[data-mobile="1"] select {
  font-size: 16px;
}
html[data-mobile="1"] .canvas-content input:not([type="range"]),
html[data-mobile="1"] .canvas-content textarea,
html[data-mobile="1"] .canvas-content select {
  font-size: inherit;
}
/* Menos el nodo de código: tiene dos capas que tienen que medir lo mismo al
   píxel (la de escribir encima, la de colores debajo), y con el tamaño heredado
   la de escribir crecía a 16px y el cursor se iba separando del texto. */
html[data-mobile="1"] .canvas-content textarea.code-area {
  font-size: calc(12.5px * var(--node-scale, 1));
}

/* ── Barra superior ──────────────────────────────────────────────────── */
html[data-mobile="1"] .topbar {
  gap: 4px;
  padding: 5px 6px;
  padding-left: max(6px, env(safe-area-inset-left));
  padding-right: max(6px, env(safe-area-inset-right));
  flex-wrap: nowrap;
}
/* Lo que solo existe en el teléfono (deshacer y rehacer arriba, Topbar.jsx). */
.solo-movil { display: none; }
html[data-mobile="1"] .topbar .brand { flex: 0 0 auto; }
html[data-mobile="1"] .topbar .brand-mark { width: 26px; height: 26px; }
html[data-mobile="1"] .topbar > .topbar-spacer { display: none; }

html[data-mobile="1"] .crumb-back {
  display: grid; place-items: center;
  flex: 0 0 auto;
  width: 38px; height: 38px;
  border-radius: 10px;
  border: 1.5px solid var(--line);
  background: var(--paper);
  color: var(--ink);
  box-shadow: var(--pop-sm);
}
html[data-mobile="1"] .crumb-back:active { transform: scale(0.94); }
html[data-mobile="1"] .crumb-back .material-symbols-rounded { font-size: 21px; }

/* Con el dedo las migas se agrandan un poco y ocupan el ancho que sobra; el
   desplegable del "…" funciona igual que en el PC. */
html[data-mobile="1"] .migas { --migas-ancho-miga: 40vw; flex: 1 1 auto; min-width: 0; max-width: none; }
html[data-mobile="1"] .migas__miga { font-size: 14px; padding: 7px 8px; }
html[data-mobile="1"] .migas__menu { min-width: 220px; max-width: 78vw; }
html[data-mobile="1"] .migas__menu-item { padding-top: 10px; padding-bottom: 10px; font-size: 14px; }

/* ── Panel "⋯" con las acciones que no caben ─────────────────────────── */
html[data-mobile="1"] .topbar-more {
  display: grid; place-items: center;
  flex: 0 0 auto;
  width: 38px; height: 38px;
  border-radius: 10px;
  border: 1.5px solid var(--line);
  background: var(--paper);
  color: var(--ink);
  box-shadow: var(--pop-sm);
}
html[data-mobile="1"] .topbar-more .material-symbols-rounded { font-size: 21px; }

html[data-mobile="1"] .topbar-tail { display: none; }
html[data-mobile="1"] .topbar-tail.open {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 10px;
  position: fixed;
  top: 54px;
  right: 6px;
  left: auto;
  width: min(320px, calc(100vw - 12px));
  max-height: calc(100dvh - 66px);
  overflow-y: auto;
  padding: 12px;
  background: var(--paper);
  border: 1.5px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--pop-deep);
  z-index: 320;
  animation: scale-in 140ms var(--e-out);
}
html[data-mobile="1"] .topbar-tail.open > .topbar-spacer {
  flex: 0 0 auto !important;
  justify-content: flex-start !important;
  gap: 10px;
}
html[data-mobile="1"] .topbar-tail.open .topbar-actions {
  flex-wrap: wrap;
  gap: 10px;
}
/* Dentro del panel sí hay sitio: devolvemos el texto a Feedback y Apoyar */
html[data-mobile="1"] .topbar-tail.open .feedback-topbar-btn,
html[data-mobile="1"] .topbar-tail.open .kofi-topbar-btn {
  width: auto; height: 38px;
  padding: 0 14px;
  border-radius: 10px;
}
html[data-mobile="1"] .topbar-tail.open .feedback-topbar-btn span:not(.material-symbols-rounded),
html[data-mobile="1"] .topbar-tail.open .kofi-topbar-btn span:not(.material-symbols-rounded) {
  display: inline;
}
html[data-mobile="1"] .topbar-tail.open .icon-btn { width: 44px; height: 44px; }
/* En el movil el deslizador no puede depender del raton: no hay raton. Aqui se
   deshace lo flotante y vuelve a ir en linea, dentro del cajon que se abre con
   el boton de los tres puntos. */
html[data-mobile="1"] .volume-ctrl {
  position: static;
  display: flex;
  align-items: center;
  gap: 6px;
  width: auto;
  height: auto;
  padding: 0 10px 0 0;
}
html[data-mobile="1"] .volume-ctrl::after { display: none; }
html[data-mobile="1"] .volume-ctrl .icon-btn-mute { width: 44px; height: 44px; }
html[data-mobile="1"] .topbar-tail.open .volume-slider {
  position: static;
  display: block;
  width: 90px;
  height: 4px;
  padding: 0;
  margin: 0;
  background: var(--line-soft);
  border: none;
  border-radius: 99px;
  box-shadow: none;
  opacity: 1;
  visibility: visible;
  transform: none;
}
html[data-mobile="1"] .volume-slider::-webkit-slider-runnable-track { background: transparent; }
html[data-mobile="1"] .volume-slider::-webkit-slider-thumb { margin-top: 0; }
html[data-mobile="1"] .topbar-more + .topbar-tail-scrim,
html[data-mobile="1"] .topbar-tail-scrim { display: block; position: fixed; inset: 0; z-index: 310; }

/* ── Raíl vertical de herramientas (borde derecho) ───────────────────── */
/* En movil la barra es un rail vertical fijo, asi que el contenedor no debe
   ocupar sitio en la fila y el deslizador no aplica: el rail se desplaza
   solo, con el dedo. */
html[data-mobile="1"] .tools-wrap { display: contents; }
html[data-mobile="1"] .tools-slider { display: none; }
html[data-mobile="1"] .tools {
  position: fixed;
  /* Anclado ABAJO y del alto de su contenido. Antes iba de arriba a abajo, y
     en un móvil alargado eso dejaba un panel medio vacío de cientos de píxeles.
     Pegado abajo, además, las herramientas caen donde llega el pulgar. En
     pantallas cortas el max-height lo vuelve desplazable. */
  top: auto;
  right: max(6px, env(safe-area-inset-right));
  bottom: calc(78px + env(safe-area-inset-bottom));
  /* Tope de altura: el raíl crece hacia arriba desde donde llega el pulgar, y
     en horizontal la pantalla es tan baja que acababa montándose sobre la barra
     de búsqueda. La cuenta reserva lo de abajo (78 de separación) y lo de arriba
     (la barra de búsqueda con su aire), más lo que se quede el sistema por los
     dos lados. Si no caben todas las herramientas el raíl se desplaza, que para
     eso lleva overflow. */
  max-height: calc(100dvh - 140px - env(safe-area-inset-top) - env(safe-area-inset-bottom));
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 6px 5px;
  border-radius: 14px;
  background: var(--paper);
  box-shadow: var(--pop-deep);
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: none;
  z-index: 60;
  animation: none;
}
html[data-mobile="1"] .tools::-webkit-scrollbar { width: 0; height: 0; }
html[data-mobile="1"] .tools.rail-closed { display: none; }
html[data-mobile="1"] .tools .tool { padding: 2px; }
html[data-mobile="1"] .tools .tool:hover { transform: none; background: none; }
html[data-mobile="1"] .tools .tool .tool-icon { width: 38px; height: 38px; border-radius: 10px; }
html[data-mobile="1"] .tools .tool .material-symbols-rounded { font-size: 21px; }
html[data-mobile="1"] .tools .tool-divider {
  width: 26px; height: 1.5px; margin: 3px 0; flex: 0 0 auto;
}
/* El menú de extras (calendario, comentario, archivo, mapa) es hijo del raíl,
   que lleva overflow para poder desplazarse: en posición absoluta quedaba
   recortado por ese overflow y el botón "…" parecía no hacer nada. Con
   position:fixed sale del recorte y se abre hacia la izquierda del raíl. */
html[data-mobile="1"] .extra-tools-popout {
  position: fixed;
  top: auto;
  left: auto;
  right: 72px;
  bottom: 80px;
  margin: 0;
  max-height: 60dvh;
  overflow-y: auto;
  z-index: 420;
}
html[data-mobile="1"] .extra-tools-btn { min-height: 42px; }

html[data-mobile="1"] .tools-fab {
  display: grid; place-items: center;
  position: fixed;
  right: max(10px, env(safe-area-inset-right));
  bottom: calc(14px + env(safe-area-inset-bottom));
  width: 54px; height: 54px;
  border-radius: 50%;
  background: var(--olive);
  color: var(--olive-ink);
  border: 1.5px solid var(--line);
  box-shadow: 0 6px 20px rgba(0,0,0,0.28);
  z-index: 66;
}
html[data-mobile="1"] .tools-fab:active { transform: scale(0.93); }
html[data-mobile="1"] .tools-fab .material-symbols-rounded { font-size: 26px; }

/* ── Franja inferior del lienzo ──────────────────────────────────────
   En escritorio hay cuatro cosas repartidas por los lados: zoom (abajo a la
   derecha), selector de fondo (a su izquierda), pastillas de estado (abajo a
   la izquierda) y la barra de formato del nodo. Al estrechar la pantalla se
   amontonan todas en la misma esquina. En vez de reubicarlas una a una las
   ordenamos en FILAS fijas de abajo hacia arriba, que es lo único que
   garantiza que no se pisen aunque cambie el ancho:

     fila A (abajo):  zoom · fondo ......................... botón flotante
     fila B:          pastillas de estado
     fila C:          barra de formato del nodo seleccionado

   El hueco de la derecha (76px) lo reservamos para el raíl y el botón. */

/* Fila A */
html[data-mobile="1"] .zoom-ctrls {
  left: max(8px, env(safe-area-inset-left));
  right: auto;
  bottom: calc(14px + env(safe-area-inset-bottom));
  border-radius: 10px;
}
html[data-mobile="1"] .zoom-ctrls button { padding: 9px 12px; font-size: 14px; }
/* Fuera el menos y el más: en un teléfono se acerca y se aleja pellizcando, que
   es más rápido y más fino que dar toques de diez en diez. Queda el porcentaje,
   que además sigue sirviendo de botón para volver al 100%. */
html[data-mobile="1"] .zoom-ctrls button:not(.zoom-level) { display: none; }
html[data-mobile="1"] .zoom-ctrls .zoom-level { border-right: none; }
/* Lleva la posición en estilo inline (right:160px), así que hace falta
   !important para sacarlo de en medio de las pastillas. */
/* El desplegable se abre hacia la IZQUIERDA (right:0 en su estilo), y en el
   móvil el botón está pegado al borde izquierdo: la paleta se salía de la
   pantalla y se veía cortada por la mitad. Aquí se abre hacia la derecha, que
   es donde hay sitio. */
html[data-mobile="1"] .canvas-bg-selector .ctx-popout {
  left: 0 !important;
  right: auto !important;
}
html[data-mobile="1"] .canvas-bg-selector {
  left: 156px !important;
  right: auto !important;
  bottom: calc(17px + env(safe-area-inset-bottom)) !important;
}

/* Fila B */
html[data-mobile="1"] .status-bar {
  left: max(8px, env(safe-area-inset-left));
  right: 76px;
  bottom: calc(60px + env(safe-area-inset-bottom));
  gap: 5px;
  flex-wrap: nowrap;
  pointer-events: none; /* que no roben toques al lienzo entre pastilla y pastilla */
}
html[data-mobile="1"] .status-bar > * { pointer-events: auto; }
/* "Guardado" y el número de nodos son informativos; en una pantalla de
   teléfono solo tapan el lienzo. Dejamos la que hace algo (online/offline) y
   la del nivel de anidación, que sí orienta dentro de los tableros. */
html[data-mobile="1"] .status-bar .status-pill:not(.privacy-status-pill):not(.accent) {
  display: none;
}
/* El raíl flota sobre el lienzo por la derecha: el buscador tiene que
   terminar antes o queda medio tapado (y parecía que se salía del marco). */
/* ── El buscador, plegado hasta que se necesita ──
   En un teléfono esta barra se comía todo el ancho de arriba a todas horas para
   algo que se usa de vez en cuando. Plegada es solo la lupa; se toca y se abre,
   se toca fuera o la lupa otra vez y se cierra. En el escritorio no se pliega:
   allí sobra sitio, y tenerla a la vista es lo que hace que se use. */
.mini-search-lupa {
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 auto;
  background: none; border: 0; padding: 0; margin: 0;
  cursor: pointer; color: inherit;
}
html[data-mobile="1"] .mini-search.plegada {
  right: auto;
  width: 46px;
  padding: 5px;
  gap: 0;
  justify-content: center;
}
html[data-mobile="1"] .mini-search.plegada input,
html[data-mobile="1"] .mini-search.plegada .mini-search-global,
html[data-mobile="1"] .mini-search.plegada > button:not(.mini-search-lupa) {
  display: none;
}
/* La lupa ocupa la cajita entera: antes solo respondía su centro (25 px de
   46×37) y tocar el borde no hacía nada. */
html[data-mobile="1"] .mini-search.plegada { padding: 0; height: 37px; }
html[data-mobile="1"] .mini-search.plegada .mini-search-lupa { padding: 4px; width: 100%; height: 100%; }

html[data-mobile="1"] .mini-search {
  width: auto;
  left: max(8px, env(safe-area-inset-left));
  right: 76px;
  transform: none;
  /* Por DEBAJO de la barra de estado del teléfono, no detrás de ella.
     Android dibuja la aplicación de borde a borde, así que con top:8px la barra
     de búsqueda quedaba tapada por el reloj y la batería: se veía, pero el dedo
     no llegaba, porque quien recibe el toque ahí arriba es el sistema. Lo mismo
     valdrá el día que alguien la abra en un iPhone con muesca. */
  top: calc(8px + env(safe-area-inset-top));
}
/* El aviso de "arrastra para darle tamaño" salía como un cartelón en mitad de
   la pantalla, tapando justo el sitio donde ibas a poner el nodo. Abajo y
   pequeño: se lee igual y no estorba. */
html[data-mobile="1"] .place-hint {
  top: auto;
  bottom: calc(96px + env(safe-area-inset-bottom));
  left: 8px; right: 76px;
  transform: none;
  justify-content: center;
  font-size: 11.5px;
  padding: 6px 10px;
  gap: 7px;
  border: 0;
  opacity: 0.94;
}
/* En horizontal sobra ancho y falta alto: se queda centrado abajo, sin llegar
   ni al zoom de la izquierda ni al botón de añadir de la derecha. */
html[data-mobile="1"][data-orient="landscape"] .place-hint {
  bottom: calc(8px + env(safe-area-inset-bottom));
  left: 50%; right: auto;
  transform: translateX(-50%);
  max-width: min(70vw, 420px);
}

/* La barra de formato/acciones del nodo seleccionado era una columna estrecha
   pegada a la izquierda; en vertical estorba, así que pasa a ser una tira
   horizontal desplazable encima de los controles inferiores. */
html[data-mobile="1"] .ctx-side,
html[data-mobile="1"] .ctx-side.text-format,
html[data-mobile="1"] .ctx-side.ctx-side-day {
  position: fixed;
  top: auto;
  left: max(8px, env(safe-area-inset-left));
  right: max(76px, env(safe-area-inset-right));
  /* fila C: por encima de las pastillas de estado (fila B, abajo 60) */
  bottom: calc(98px + env(safe-area-inset-bottom));
  width: auto;
  max-width: none;
  flex-direction: row;
  align-items: center;
  gap: 4px;
  padding: 6px;
  border-radius: 12px;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  z-index: 120;
}
html[data-mobile="1"] .ctx-side::-webkit-scrollbar { width: 0; height: 0; }
html[data-mobile="1"] .ctx-side .ctx-close {
  width: 36px; height: 36px; flex: 0 0 auto; margin: 0 2px 0 0;
}
html[data-mobile="1"] .ctx-side .ctx-btn { flex: 0 0 auto; min-width: 50px; }
html[data-mobile="1"] .ctx-side .ctx-sep {
  width: 1.5px; height: 28px; margin: 0 2px; flex: 0 0 auto;
}

/* Los desplegables de esa barra (grosor, color, presión…), justo encima de
   ella y a lo ancho.
   En vertical no tenían ninguna regla propia, así que se quedaban con la de
   escritorio —`top: 96px; left: 100px`— y aparecían arriba a la izquierda,
   tapando el buscador y lejísimos del botón que los abría. Aquí abajo la barra
   ya no está donde el escritorio la pone, y el desplegable tiene que seguirla.

   `fixed` y no `absolute` a propósito: la barra recorta lo que se salga de
   ella (`overflow-x: auto`), y un hijo `absolute` quedaría cortado por arriba.
   Un `fixed` se cuelga del viewport y se libra de ese recorte. */
html[data-mobile="1"][data-orient="portrait"] .ctx-popout {
  position: fixed;
  top: auto;
  left: max(8px, env(safe-area-inset-left));
  right: max(76px, env(safe-area-inset-right));
  bottom: calc(170px + env(safe-area-inset-bottom));  /* barra: 98 de abajo + 64 de alto + 8 de aire */
  width: auto;
  max-height: 46dvh;
  overflow-y: auto;
  z-index: 130;              /* la barra está en 120 */
}

/* ── Modales y menús a tamaño de pulgar ──────────────────────────────── */
html[data-mobile="1"] .modal {
  width: min(440px, calc(100vw - 20px));
  max-height: 86dvh;
  overflow-y: auto;
  border-radius: 12px;
}
html[data-mobile="1"] .doc-modal {
  width: 100vw;
  max-width: none;
  height: 100dvh;
  max-height: none;
  border-radius: 0;
}
/* En el móvil la barra ocupa varias filas. Se aprieta y se quitan los nombres
   de categoría: ahí lo que escasea es el alto de pantalla, y con siete rótulos
   la barra se comía un tercio del sitio para escribir. */
html[data-mobile="1"] .doc-ribbon { padding: 3px 6px 0; }
html[data-mobile="1"] .doc-group { padding: 0 5px; }
html[data-mobile="1"] .doc-group-name { display: none; }
html[data-mobile="1"] .doc-ribbon button { width: 30px; height: 30px; }
html[data-mobile="1"] .doc-group-btns { padding-bottom: 3px; }
/* Ajustes y demás ventanas grandes llevan el ancho en estilo inline
   (width: 680px), que en una pantalla de 360px se sale por los dos lados: hace
   falta !important para poder encogerlas. */
html[data-mobile="1"] .doc-modal-window {
  width: calc(100vw - 16px) !important;
  max-width: none !important;
  max-height: 88dvh !important;
  padding: 16px !important;
  overflow-y: auto;
  border-radius: 12px !important;
}
html[data-mobile="1"] .context-menu {
  min-width: 210px;
  max-height: 70dvh;
  overflow-y: auto;
}
html[data-mobile="1"] .context-menu button,
html[data-mobile="1"] .context-menu .ctx-item { min-height: 40px; }

/* ── Pantalla de inicio ──────────────────────────────────────────────── */
html[data-mobile="1"] .ms-side-toggle {
  display: grid; place-items: center;
  flex: 0 0 auto;
  width: 40px; height: 40px;
  border-radius: 10px;
  border: 1.5px solid var(--line);
  background: var(--paper);
  color: var(--ink);
  box-shadow: var(--pop-sm);
}
html[data-mobile="1"] .ms-side-toggle .material-symbols-rounded { font-size: 22px; }

html[data-mobile="1"] .ms-side {
  display: flex;
  position: fixed;
  top: 0; bottom: 0; left: 0;
  width: min(300px, 84vw);
  z-index: 300;
  transform: translateX(-102%);
  transition: transform 220ms var(--e-out);
  box-shadow: var(--pop-deep);
  padding-top: max(16px, env(safe-area-inset-top));
}
html[data-mobile="1"] .miro-home.side-open .ms-side { transform: none; }
html[data-mobile="1"] .ms-side-scrim {
  display: block;
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.45);
  z-index: 299;
  animation: fade-in 160ms var(--e-out);
}
html[data-mobile="1"] .ms-main { padding: 12px 14px 90px; }
/* Los 7 controles de la derecha ocupan 316px: no caben junto al buscador en un
   móvil de 375px, así que bajan a su propia fila. */
html[data-mobile="1"] .ms-top { gap: 8px; margin-bottom: 16px; flex-wrap: wrap; }
html[data-mobile="1"] .ms-side-toggle { order: 0; }
html[data-mobile="1"] .ms-search { order: 1; flex: 1 1 auto; min-width: 0; padding: 9px 11px; }
html[data-mobile="1"] .ms-search kbd { display: none; }
html[data-mobile="1"] .ms-top-actions {
  order: 2;
  flex: 1 1 100%;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 6px;
}
html[data-mobile="1"] .ms-top-actions .icon-btn { width: 40px; height: 40px; margin-right: 0 !important; }
html[data-mobile="1"] .ms-top-actions .lang-switch { height: 40px; width: 52px; }
html[data-mobile="1"] .project-grid {
  grid-template-columns: 1fr;
  padding: 0 14px 80px;
  gap: 12px;
}
html[data-mobile="1"] .home-hero,
html[data-mobile="1"] .home-toolbar,
html[data-mobile="1"] .section-header { padding-left: 14px; padding-right: 14px; }
html[data-mobile="1"] .ms-hero { grid-template-columns: 1fr; }
html[data-mobile="1"] .ms-hero-art { display: none; }

/* Línea guía al reordenar tareas de un to-do: sin ella se arrastraba a ciegas,
   sin saber si la tarea iba a quedar por encima o por debajo de la de al lado. */
.todo-row { position: relative; }
.todo-row.drop-before::before,
.todo-row.drop-after::after {
  content: '';
  position: absolute;
  left: 2px; right: 2px;
  height: 3px;
  border-radius: 2px;
  background: var(--olive);
  box-shadow: 0 0 0 1.5px var(--paper);
  z-index: 5;
  pointer-events: none;
}
.todo-row.drop-before::before { top: -2px; }
.todo-row.drop-after::after { bottom: -2px; }

/* Nodo sobre el que caerá la flecha que se está arrastrando. En escritorio esto
   lo dice el :hover encendiendo los puntos de anclaje; con el dedo no hay hover,
   así que la flecha se soltaba a ciegas y quedaba suelta sin saber por qué. */
.item.link-target > .item-card,
.item.link-target > * {
  outline: 2.5px solid var(--olive);
  outline-offset: 3px;
  border-radius: 3px;
}
.item.link-target .anchor { opacity: 1 !important; transform: scale(1.15) !important; }

/* Mientras se tira de una flecha, todos los nodos enseñan dónde se puede
   enganchar (equivalente táctil de pasar el ratón por encima). */
.canvas-wrap.linking .item .anchor,
.canvas-wrap.conn-drag .item .anchor {
  opacity: 0.75;
  transform: scale(1);
}

/* Versión del código cargado, junto al título de Ajustes. Sirve para
   distinguir "el arreglo no funciona" de "el navegador está sirviendo una
   copia vieja de su caché", que desde un móvil no se puede saber de otro modo. */
.odi-build-tag {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--bg);
  border: 1.5px solid var(--line-soft);
  color: var(--ink-3);
  white-space: nowrap;
  /* En el teléfono no cabe entera al lado del título: baja a su línea y, si
     ni así cabe, se corta con puntos en vez de empujar la X fuera. */
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
}
.odi-touch-diag {
  border: 1.5px solid var(--line-soft);
  border-radius: 8px;
  padding: 10px 12px;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.odi-touch-diag-title { font-size: 12px; font-weight: 700; color: var(--ink-2); }
.odi-touch-diag code {
  font-family: var(--font-mono);
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--ink);
  word-break: break-word;
}
.odi-touch-diag-hint { font-size: 11.5px; color: var(--ink-3); line-height: 1.4; }

/* En un móvil REAL el navegador decide en el compositor —antes de ejecutar
   nada de nuestro JS— si un gesto es un desplazamiento. Si el CSS no se lo
   prohíbe, se queda el gesto, y a partir de ahí los touchmove llegan ya sin
   poder cancelarse: preventDefault deja de tener efecto y el nodo no se mueve.
   El emulador del PC no hace esa optimización, y por eso arrastrar funcionaba
   allí y no en el teléfono. Esto le dice que dentro del lienzo no hay nada que
   desplazar y que pregunte siempre a la app.
   Se marca también en los nodos y en las capas intermedias: que el valor del
   antepasado alcance al descendiente depende de dónde considere el navegador
   que hay un contenedor desplazable, y aquí no queremos depender de eso. El
   desplazamiento interno de una nota larga lo hace touch.js a mano. */
html[data-touch="1"] .canvas-wrap,
html[data-touch="1"] .canvas-surface,
html[data-touch="1"] .canvas-content,
html[data-touch="1"] .canvas-content .item {
  touch-action: none;
}

/* ── Manipular nodos con el dedo ──────────────────────────────────────
   Esto cuelga de data-touch (hay pantalla táctil), no de data-mobile: una
   tableta o un portátil táctil grandes conservan la disposición de escritorio
   pero necesitan igualmente objetivos del tamaño de un dedo. */

/* Sin ratón no existe :hover, así que el punto del que se tira para crear un
   conector NO aparecía jamás: unir dos nodos era imposible en un móvil. Con el
   dedo el gesto equivalente a "apuntar" es seleccionar. */
html[data-touch="1"] .item.selected > .anchors > .connect-handle,
html[data-touch="1"] .col-child-wrap.selected > .anchors > .connect-handle {
  opacity: 1;
  transform: scale(calc(1 * var(--handle-scale, 1)));
}

/* La zona sensible crece hasta un tamaño de dedo sin que cambie lo que se ve:
   el tirador sigue siendo igual de discreto, pero ya no hay que acertarle a
   10px. Los márgenes son distintos para que las esquinas no se coman el punto
   de conexión del centro del lado derecho. */
html[data-touch="1"] .handle::before {
  top: -12px; left: -12px; right: -12px; bottom: -12px;
}
html[data-touch="1"] .anchor::before,
html[data-touch="1"] .connect-handle::before {
  content: '';
  position: absolute;
  top: -8px; left: -8px; right: -8px; bottom: -8px;
  pointer-events: auto;
}

/* Un tirador invisible seguía cazando el dedo.
   Los puntos de conexión están a opacity 0 mientras el nodo no está elegido
   —sin ratón no hay :hover que los encienda— pero conservaban
   `pointer-events: auto`. Resultado: cuatro trampas de casi 40px que no se ven
   en cada nodo, y un arrastre que unas veces movía el nodo y otras empezaba
   una flecha, sin nada en pantalla que explicara la diferencia. Si no se ve,
   no se toca. */
html[data-touch="1"] .item:not(.selected) > .anchors > .connect-handle,
html[data-touch="1"] .col-child-wrap:not(.selected) > .anchors > .connect-handle {
  pointer-events: none;
}

/* La lámina de arrastre, por encima de los tiradores.
   Los de tamaño están en z-index 10 y la lámina en 9, así que hasta ahora
   ganaban ellos: la lámina existía y aun así el dedo caía en un tirador. Por
   encima, el interior del nodo es siempre para moverlo y a los tiradores les
   queda su mitad de fuera, que es la que sobresale del borde y la que se ve. */
html[data-touch="1"] .item-drag-shield { z-index: 12; }

/* ── Orientación horizontal: el raíl derecho se queda, pero la barra
      superior se encoge para no comerse el poco alto disponible. ─────── */
html[data-mobile="1"][data-orient="landscape"] .topbar { padding-top: 3px; padding-bottom: 3px; }
/* En horizontal el alto escasea: el raíl vuelve a ocuparlo todo y se desplaza. */
html[data-mobile="1"][data-orient="landscape"] .tools {
  top: 50px;
  bottom: 68px;
  max-height: none;
}
html[data-mobile="1"][data-orient="landscape"] .tools .tool .tool-icon { width: 34px; height: 34px; }

/* En horizontal solo quedan ~315px de alto: las tres filas de antes ocupaban
   casi la mitad y la barra del nodo aparecía flotando en medio de la pantalla.
   Aquí sobra ANCHO y falta ALTO, así que se reparten al revés: zoom y fondo se
   apilan en una columna pegada a la izquierda, y la barra del nodo se queda en
   una sola tira baja, sin etiquetas de texto. */
html[data-mobile="1"][data-orient="landscape"] .zoom-ctrls {
  bottom: calc(8px + env(safe-area-inset-bottom));
}
html[data-mobile="1"][data-orient="landscape"] .canvas-bg-selector {
  left: max(8px, env(safe-area-inset-left)) !important;
  bottom: calc(52px + env(safe-area-inset-bottom)) !important;
}
/* Las pastillas de estado son puramente informativas: en horizontal el alto es
   demasiado escaso para gastarlo en ellas.
   Pero el botón de conexiones vive en esa misma barra y NO es informativo: es
   la única puerta a la vista de conexiones, así que escondiendo la barra entera
   se perdía. Se esconde lo informativo y él se queda, abajo a la derecha, al
   lado del botón de añadir. */
html[data-mobile="1"][data-orient="landscape"] .status-bar {
  display: flex;
  left: auto;
  right: 76px;
  bottom: calc(8px + env(safe-area-inset-bottom));
  pointer-events: none;
}
html[data-mobile="1"][data-orient="landscape"] .status-bar > *:not(.odi-graph-btn) { display: none; }
html[data-mobile="1"][data-orient="landscape"] .status-bar .odi-graph-btn { pointer-events: auto; }

html[data-mobile="1"][data-orient="landscape"] .ctx-side,
html[data-mobile="1"][data-orient="landscape"] .ctx-side.text-format,
html[data-mobile="1"][data-orient="landscape"] .ctx-side.ctx-side-day {
  left: 156px;
  right: 76px;
  bottom: calc(8px + env(safe-area-inset-bottom));
  padding: 4px 6px;
  gap: 2px;
}
/* Solo iconos: con el texto debajo la tira mide 64px y aquí eso es un quinto
   de la pantalla. */
html[data-mobile="1"][data-orient="landscape"] .ctx-side .ctx-btn {
  min-width: 42px;
  padding: 6px 4px;
}
html[data-mobile="1"][data-orient="landscape"] .ctx-side .ctx-btn > span:not(.material-symbols-rounded) {
  display: none;
}
html[data-mobile="1"][data-orient="landscape"] .mini-search { top: calc(6px + env(safe-area-inset-top)); }
/* Los desplegables de la barra del nodo (paleta, emoji…) se abren hacia arriba
   para no salirse por abajo. */
html[data-mobile="1"][data-orient="landscape"] .ctx-side .ctx-popout {
  bottom: calc(100% + 6px);
  top: auto;
  max-height: 200px;
  overflow-y: auto;
}

/* ==========================================================================
   BUSCADOR GLOBAL (Ctrl+K)
   ========================================================================== */
.odi-sp-backdrop {
  position: fixed; inset: 0; z-index: 9500;
  background: color-mix(in srgb, var(--ink) 45%, transparent);
  backdrop-filter: blur(3px);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 10vh 16px 16px;
  animation: fade-in 120ms var(--e-out);
}
.odi-sp {
  width: min(680px, 100%);
  max-height: 70vh;
  display: flex; flex-direction: column;
  background: var(--paper);
  border: 1.5px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--pop-deep);
  overflow: hidden;
  animation: scale-in 140ms var(--e-out);
}
.odi-sp-field {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 14px;
  border-bottom: 1.5px solid var(--line-soft);
  flex: 0 0 auto;
}
.odi-sp-field > .material-symbols-rounded { color: var(--ink-3); font-size: 20px; }
.odi-sp-field input {
  flex: 1; min-width: 0;
  font-size: 16px;              /* 16px o el móvil amplía la página al enfocar */
  font-weight: 600;
  border: none; outline: none; background: transparent; color: var(--ink);
}
.odi-sp-close {
  display: grid; place-items: center;
  width: 32px; height: 32px; border-radius: 8px;
  color: var(--ink-3); flex: 0 0 auto;
}
.odi-sp-close:hover { background: var(--bg); color: var(--ink); }

.odi-sp-list { overflow-y: auto; flex: 1 1 auto; padding: 6px; }
.odi-sp-empty { padding: 22px 16px; color: var(--ink-3); font-size: 13px; line-height: 1.5; text-align: center; }

.odi-sp-hit {
  display: flex; align-items: flex-start; gap: 10px;
  width: 100%; text-align: left;
  padding: 10px 12px;
  border-radius: 9px;
  background: none; border: none; cursor: pointer;
}
.odi-sp-hit.active { background: var(--bg); }
.odi-sp-icon {
  font-size: 19px; color: var(--ink-2);
  flex: 0 0 auto; margin-top: 1px;
}
.odi-sp-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.odi-sp-snippet {
  font-size: 13.5px; font-weight: 600; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.odi-sp-path {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
  font-size: 11.5px; color: var(--ink-3); font-weight: 600;
}
.odi-sp-sep { opacity: 0.5; }

.odi-sp-foot {
  display: flex; align-items: center; gap: 14px;
  padding: 8px 14px;
  border-top: 1.5px solid var(--line-soft);
  font-size: 11.5px; color: var(--ink-3);
  flex: 0 0 auto;
}
.odi-sp-foot kbd {
  font-family: var(--font-mono); font-size: 10.5px;
  padding: 1px 5px; margin-right: 3px;
  background: var(--bg); border: 1px solid var(--line-soft); border-radius: 4px;
}
.odi-sp-count { margin-left: auto; }

/* Nodo al que ha saltado el buscador: un destello para no perderlo de vista */
.item.jump-target > * { outline: 3px solid var(--olive); outline-offset: 4px; border-radius: 3px; }
.item.jump-target { animation: odi-jump-pulse 1.6s ease-out 2; }
@keyframes odi-jump-pulse {
  0%, 100% { filter: none; }
  50% { filter: drop-shadow(0 0 12px var(--olive)); }
}

/* En móvil ocupa casi toda la pantalla: los resultados llevan ruta larga */
html[data-mobile="1"] .odi-sp-backdrop { padding: 8px; align-items: stretch; }
html[data-mobile="1"] .odi-sp { max-height: none; height: 100%; width: 100%; }
html[data-mobile="1"] .odi-sp-hit { padding: 12px; }
html[data-mobile="1"] .odi-sp-foot { display: none; }

/* Botón del buscador del lienzo que abre el buscador global */
.mini-search-global {
  display: inline-flex; align-items: center; gap: 5px;
  flex: 0 0 auto;
  padding: 3px 7px;
  border-radius: 6px;
  border: 1.5px solid var(--line-soft);
  background: var(--bg);
  color: var(--ink-2);
  transition: background 100ms, color 100ms;
}
.mini-search-global:hover { background: var(--paper); color: var(--ink); }
.mini-search-kbd { font-family: var(--font-mono); font-size: 10px; font-weight: 700; letter-spacing: -0.02em; }
/* Con el dedo no hay atajo de teclado que recordar */
html[data-mobile="1"] .mini-search-kbd { display: none; }
html[data-mobile="1"] .mini-search-global { padding: 6px; }

/* ==========================================================================
   ENLACES ENTRE NODOS Y BACKLINKS
   ========================================================================== */
a.odi-link {
  color: var(--olive-texto);
  text-decoration: none;
  border-bottom: 1.5px solid color-mix(in srgb, var(--olive) 45%, transparent);
  cursor: pointer;
  padding: 0 1px;
  border-radius: 2px;
  transition: background 100ms, border-color 100ms;
}
a.odi-link:hover {
  background: color-mix(in srgb, var(--olive) 14%, transparent);
  border-bottom-color: var(--olive);
}
[data-theme="dark"] a.odi-link { color: #A8CC7E; }

.odi-backlinks { min-width: 230px; max-width: 320px; max-height: 300px; overflow-y: auto; }
.odi-backlink {
  display: flex; flex-direction: column; gap: 2px;
  width: 100%; text-align: left;
  padding: 7px 9px;
  border-radius: 7px;
  background: none; border: none; cursor: pointer;
}
.odi-backlink:hover { background: var(--bg); }
.odi-backlink-text { font-size: 12.5px; font-weight: 700; color: var(--ink); }
.odi-backlink-path { font-size: 11px; color: var(--ink-3); font-weight: 600; }



/* ── Color de los enlaces entre nodos ──────────────────────────────────
   Morado a propósito: el verde es el color de "activo/seleccionado" en toda la
   app (herramienta activa, nodo destino, línea de guía), y un enlace en verde
   se confundía con una selección. El morado no lo usa nada más. */
:root { --odi-link: #7C5CBF; --odi-link-soft: #E9E2F7; }
[data-theme="dark"] { --odi-link: #B49BEA; --odi-link-soft: #3A3350; }

a.odi-link {
  color: var(--odi-link);
  border-bottom-color: color-mix(in srgb, var(--odi-link) 45%, transparent);
}
a.odi-link:hover {
  background: var(--odi-link-soft);
  border-bottom-color: var(--odi-link);
}
[data-theme="dark"] a.odi-link { color: var(--odi-link); }
/* Dentro de una leyenda el enlace usaba el color de los enlaces web */
.node-caption a.odi-link { color: var(--odi-link); text-decoration: none; }

/* La leyenda de la imagen: franja propia debajo, nunca encima de la foto.
   La leyenda se sacó del marco en el JSX (dentro quedaba recortada por su
   overflow:hidden), y aquí el marco cede la altura que ocupa la franja. */
.image-card .item-card { position: relative; }
.image-card .item-card:has(> .image-caption) > .image-frame {
  height: calc(100% - 34px) !important;
}
.image-card .image-caption {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 34px;
  display: flex;
  align-items: center;
  width: auto;
  box-sizing: border-box;
  padding: 4px 10px;
  background: var(--paper);
  border-top: 1.5px solid var(--line-soft);
  border-radius: 0;
  backdrop-filter: none;
  font-size: 11.5px;
  overflow: hidden;
}


/* ==========================================================================
   VISTA DE CONEXIONES
   ========================================================================== */
/* Botón: junto al contador de nodos, abajo a la izquierda, con el mismo
   aspecto de pastilla que sus vecinos para que no cante. */
.odi-graph-btn {
  display: flex; align-items: center; gap: 6px;
  padding: 5px 10px;
  border-radius: 999px;
  background: var(--paper);
  border: 1.5px solid var(--line);
  box-shadow: var(--pop-sm);
  color: var(--ink-2);
  font-size: 11.5px; font-weight: 600;
  cursor: pointer;
  transition: color 120ms, border-color 120ms;
}
.odi-graph-btn:hover { color: var(--odi-link); border-color: var(--odi-link); }
.odi-graph-btn .material-symbols-rounded { font-size: 15px; }
html[data-mobile="1"] .odi-graph-btn span:not(.material-symbols-rounded) { display: none; }

.odi-graph-backdrop {
  position: fixed; inset: 0; z-index: 9400;
  background: rgba(8, 7, 14, 0.72);
  backdrop-filter: blur(6px);
  display: grid; place-items: center;
  padding: 0;
  animation: fade-in 160ms var(--e-out);
}
/* A pantalla completa: un grafo necesita sitio, y en un recuadro pequeño los
   grupos se amontonan y no se distingue nada. */
.odi-graph {
  width: 100vw; height: 100vh;
  display: flex; flex-direction: column;
  background: #14121F;
  border: none; border-radius: 0;
  overflow: hidden;
  animation: fade-in 200ms var(--e-out);
}
.odi-graph-head {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 18px;
  border-bottom: 1px solid rgba(255,255,255,0.09);
  font-size: 13.5px;
  color: #EDEAF6;
  flex: 0 0 auto;
  background: rgba(255,255,255,0.02);
}
.odi-graph-head > .material-symbols-rounded { color: #B49BEA; font-size: 21px; }
.odi-graph-count { color: rgba(237,234,246,0.5); font-size: 11.5px; font-weight: 600; }
.odi-graph-legend { margin-left: auto; display: flex; align-items: center; gap: 8px; font-size: 11px; color: rgba(237,234,246,0.5); font-weight: 600; }
.odi-graph-legend i { width: 15px; height: 2.5px; border-radius: 2px; display: inline-block; }
.odi-legend-nest { background: rgba(237,234,246,0.4); }
.odi-legend-link { background: #B49BEA; }
/* Escala de capas. Las bolitas son redondas para no confundirlas con las rayas
   de arriba, que representan relaciones y no nodos. */
.odi-legend-capas {
  display: flex; align-items: center; gap: 8px;
  padding-left: 9px; margin-left: 2px;
  border-left: 1px solid rgba(255,255,255,0.12);
  flex-wrap: wrap;
}
.odi-legend-capa { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; }
.odi-graph-legend .odi-legend-capa b,
.odi-graph-foot .odi-legend-capa b {
  width: 9px; height: 9px; border-radius: 50%; display: inline-block; flex: 0 0 auto;
}
.odi-legend-board { background: transparent; box-shadow: inset 0 0 0 1.6px rgba(255,255,255,0.65); }
.odi-graph-foot .odi-legend-capa { color: rgba(237,234,246,0.55); font-size: 11.5px; font-weight: 600; }
.odi-graph-close, .odi-graph-zoom {
  display: grid; place-items: center; width: 32px; height: 32px;
  border-radius: 8px; color: rgba(237,234,246,0.65);
}
.odi-graph-close:hover, .odi-graph-zoom:hover { background: rgba(255,255,255,0.09); color: #fff; }

.odi-graph-canvas {
  flex: 1 1 auto; position: relative; overflow: hidden;
  background:
    radial-gradient(circle at 50% 45%, #241F38 0%, #14121F 62%),
    #14121F;
  cursor: grab;
}
.odi-graph-canvas:active { cursor: grabbing; }
.odi-graph-empty { display: grid; place-items: center; height: 100%; color: rgba(237,234,246,0.45); font-size: 13px; padding: 20px; text-align: center; }

.odi-edge { stroke-width: 1.1; }
.odi-edge.is-nest { stroke: #6E6A85; }
.odi-edge.is-link { stroke: #B49BEA; stroke-width: 1.7; }

.odi-gnode { cursor: pointer; }
/* El halo se consigue con el filtro de desenfoque del SVG; la transición del
   relleno hace que encenderse al pasar el ratón no sea un salto brusco. */
/* El color lo pone la vista según la capa de anidamiento del nodo, así que aquí
   solo queda la transición y el resalte al pasar por encima. El señalado se
   marca con un aro blanco en vez de cambiándole el color: si se lo cambiara,
   dejaría de verse a qué capa pertenece justo cuando lo estás mirando. */
.odi-gcircle { fill: #8E86B8; transition: r 140ms ease; }
.odi-gcircle.is-hover { stroke: #FFFFFF; stroke-width: 2; }
/* El brillo de los grafos grandes. No es un desenfoque: es un circulo
   grande y tenue detras de cada bola. Un desenfoque de SVG obliga al
   navegador a pintar cada bola en un lienzo aparte, y con cientos de ellas
   moviendose eso es lo que hacia que la vista fuera a trompicones. */
.odi-ghalo { opacity: 0.18; pointer-events: none; }
.odi-gring { fill: none; stroke: rgba(255,255,255,0.55); stroke-width: 1.4; pointer-events: none; }
.odi-glabel { font-weight: 700; fill: rgba(237,234,246,0.92); font-family: var(--font-display); pointer-events: none; paint-order: stroke; stroke: #14121F; stroke-width: 3px; }

.odi-graph-foot {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 18px;
  border-top: 1px solid rgba(255,255,255,0.09);
  font-size: 12px; color: #EDEAF6;
  flex: 0 0 auto; min-height: 40px;
  background: rgba(255,255,255,0.02);
}
.odi-graph-path { color: rgba(237,234,246,0.5); font-size: 11.5px; font-weight: 600; }
.odi-graph-deg { margin-left: auto; color: #B49BEA; font-weight: 700; font-size: 11.5px; }
.odi-graph-hint { color: rgba(237,234,246,0.45); font-size: 11.5px; }

/* Explicación del atajo señalado. Posición FIJA y fuera de la lista: colgarla
   de la fila con ::after no servía, porque la lista de atajos tiene scroll y
   el globo quedaba recortado por su contenedor — se veía el cursor de ayuda
   pero nunca el texto. */
.odi-sh-row { cursor: help; }
.odi-sh-tip {
  position: fixed;
  z-index: 10050;
  min-width: 240px;
  max-width: 380px;
  padding: 10px 12px;
  background: var(--ink);
  color: var(--bg);
  border-radius: 9px;
  font-size: 11.5px;
  font-weight: 500;
  line-height: 1.5;
  box-shadow: 0 8px 26px rgba(0,0,0,0.34);
  pointer-events: none;
  animation: fade-in 110ms var(--e-out);
}

/* El cursor cuenta lo que se puede hacer: sobre un nodo, agarrarlo. */
.odi-gnode { cursor: grab; }
.odi-gnode:active { cursor: grabbing; }

/* ══════════════════════════════════════════════════════════════════
   Nodo de dibujo a mano alzada
   ══════════════════════════════════════════════════════════════════ */

/* El nodo en el lienzo: no es una tarjeta, es tinta sobre el fondo. */
.draw-card { position: relative; pointer-events: none; }
.draw-card svg { pointer-events: none; }
.draw-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px; width: 100%; height: 100%;
  border: 1.5px dashed var(--line-soft); border-radius: 6px;
  color: var(--text-soft); font-size: 11px; font-weight: 600; text-align: center;
  background: color-mix(in srgb, var(--paper) 55%, transparent);
}
.draw-empty .material-symbols-rounded { font-size: 26px; opacity: 0.65; }

/* La capa del modo dibujo: cubre el lienzo entero, por debajo de la barra
   contextual (z-index 70) para que sus botones sigan siendo pulsables. */
.draw-layer {
  position: absolute; inset: 0;
  z-index: 60;
  touch-action: none;              /* el dedo dibuja, no desplaza la página */
  overscroll-behavior: contain;
  user-select: none; -webkit-user-select: none;
}
.draw-dim {
  position: absolute; inset: 0;
  background: rgba(255, 255, 255, 0.72);
  animation: draw-veil-in 160ms var(--e-out);
}
[data-theme="dark"] .draw-dim { background: rgba(20, 19, 20, 0.68); }
@keyframes draw-veil-in { from { opacity: 0; } to { opacity: 1; } }

.draw-strokes { position: absolute; top: 0; left: 0; pointer-events: none; }
.draw-live { position: absolute; top: 0; left: 0; pointer-events: none; }

/* El cursor lo pone el componente; esto solo evita el parpadeo del texto. */
.draw-layer * { -webkit-user-drag: none; }

/* Guardar destaca sobre el resto de la barra: es el final del camino.
   Los dos temas se pintan a mano: --olive-l no cambia en oscuro, así que
   heredarlo dejaba un botón verde pálido con el texto casi invisible. */
.ctx-btn-primary { background: var(--olive); color: var(--olive-ink); }
.ctx-btn-primary .material-symbols-rounded { color: #FFFFFF; }
.ctx-btn-primary:hover { background: color-mix(in srgb, var(--olive) 85%, var(--ink)); }

/* Avisos y confirmaciones: una cajita del tamaño de su contenido.
   Antes reutilizaban la clase del editor de documentos, que ocupa la pantalla
   entera por diseño, y una pregunta de una línea salía estirada de arriba
   abajo. Solo crece si el mensaje es largo, y entonces se desplaza por dentro. */
.odi-dialog {
  max-width: 92vw;
  max-height: 80vh;
  overflow-y: auto;
  animation: fade-in 140ms var(--e-out);
}

/* ══════════════════════════════════════════════════════════════════
   Sesión en vivo: los cursores de las otras personas
   ══════════════════════════════════════════════════════════════════ */

/* Van dentro de la capa que se mueve con el lienzo, así que su posición son
   coordenadas del lienzo y no de la pantalla: si alguien señala una nota,
   señala esa nota aunque cada uno tenga la vista en otro sitio. */
.odi-cursor {
  position: absolute;
  pointer-events: none;
  z-index: 9500;
  /* El puntero no se agranda ni se encoge con el zoom: a la mitad de zoom
     seguiría siendo un puntero del tamaño de un puntero. */
  transform: scale(calc(1 / var(--zoom, 1)));
  transform-origin: 0 0;
  transition: left 90ms linear, top 90ms linear;
  will-change: left, top;
}
.odi-cursor-nombre {
  position: absolute;
  left: 15px; top: 16px;
  padding: 2px 7px;
  border-radius: 10px;
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
  box-shadow: 0 1px 4px rgba(0,0,0,0.25);
  font-family: var(--font-body);
}

/* ── El grafo de conexiones en un celular ──
   La cabecera era una sola fila con título, cuenta, leyenda y dos botones. En
   vertical no cabe: la leyenda empujaba y el botón de cerrar quedaba fuera de
   la pantalla, así que no había forma de salir del grafo. La leyenda se
   esconde de la cabecera (ya está entera abajo, en el pie) y los botones se
   quedan siempre a la vista. */
html[data-mobile="1"] .odi-graph-head {
  gap: 8px;
  padding: 10px 12px;
  font-size: 12.5px;
}
html[data-mobile="1"] .odi-graph-head > .odi-graph-legend { display: none; }
html[data-mobile="1"] .odi-graph-head > strong {
  flex: 0 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
html[data-mobile="1"] .odi-graph-count {
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 11px;
}
/* Que no los encoja nadie: son la única salida del grafo. */
html[data-mobile="1"] .odi-graph-close,
html[data-mobile="1"] .odi-graph-zoom {
  flex: 0 0 auto;
  width: 38px; height: 38px;   /* dedo, no ratón */
}
/* El pie con la leyenda sí puede ocupar varias líneas. */
html[data-mobile="1"] .odi-graph-foot {
  flex-wrap: wrap;
  row-gap: 6px;
}

/* ── Calidad de vida con el dedo ── */

/* La lámina que se lleva el arrastre del nodo elegido. Invisible a propósito:
   lo que se ve debajo es el nodo de siempre. Va por debajo de los tiradores de
   tamaño, para que redimensionar siga ganando en las esquinas. */
.item-drag-shield {
  position: absolute; inset: 0;
  z-index: 9;
  cursor: grab;
  touch-action: none;
  background: transparent;
}

/* Los tiradores de tamaño, del tamaño de un dedo y no de un puntero.
   La zona sensible ya era grande, pero el cuadradito de 10 px casi no se veía
   en una pantalla de teléfono y no invitaba a agarrarlo. */
html[data-touch="1"] .handle {
  width: 18px; height: 18px;
  border-width: 2px;
  border-radius: 4px;
  box-shadow: 0 1px 4px rgba(0,0,0,0.3);
}
html[data-touch="1"] .handles { inset: -10px; }
html[data-touch="1"] .handle::before {
  top: -14px; left: -14px; right: -14px; bottom: -14px;
}

/* Unirse a una sesión, en la barra de arriba del inicio.

   Con texto y no solo icono: es la puerta de entrada para quien llega con un
   código en la mano, y un icono suelto no se lee como "entra aquí".

   Relleno y no transparente: al lado de siete botones de icono, un contorno
   fino se leía como un adorno más y la gente pasaba de largo. Y el punto que
   late dice de qué va sin tener que explicarlo — es lo mismo que se ve en
   cualquier sitio para decir "esto es en directo". */
.ms-join-top {
  display: flex; align-items: center; gap: 8px;
  margin-right: 12px;
  padding: 8px 15px 8px 13px;
  border-radius: 8px;
  border: 1.5px solid var(--line);
  background: var(--olive);
  color: var(--olive-ink);
  font-size: 12.5px; font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: var(--pop-sm);
  transition: transform 140ms var(--e-out), box-shadow 140ms var(--e-out), background 120ms;
}
.ms-join-top .material-symbols-rounded { font-size: 19px; color: #FFFFFF; }
.ms-join-top:hover { background: color-mix(in srgb, var(--olive) 85%, var(--ink)); transform: translate(-1px, -2px); box-shadow: var(--pop-hover); }
.ms-join-top:active { transform: translate(1px, 1px); box-shadow: 0 0 0 0 var(--line); }

/* El punto que late: "hay sesiones esperando". */
.ms-join-top::after {
  content: '';
  width: 7px; height: 7px; border-radius: 50%;
  background: #EAF5DE;
  box-shadow: 0 0 0 0 rgba(234, 245, 222, 0.7);
  animation: latido-sesion 2s ease-out infinite;
  flex: 0 0 auto;
}
@keyframes latido-sesion {
  0%   { box-shadow: 0 0 0 0 rgba(234, 245, 222, 0.7); }
  70%  { box-shadow: 0 0 0 7px rgba(234, 245, 222, 0); }
  100% { box-shadow: 0 0 0 0 rgba(234, 245, 222, 0); }
}
/* En una ventana estrecha se queda solo el icono, para no empujar al resto.
   Desde 1250 px y no 1100: por debajo ya no cabía la fila (y menos con la
   chincheta al final). */
@media (max-width: 1250px) {
  .ms-join-top span:not(.material-symbols-rounded) { display: none; }
  .ms-join-top::after { display: none; }
  .ms-join-top { padding: 8px 10px; }
}
/* Y más estrecha aún (la ventana normal no baja de 1024), botones algo más
   pequeños y juntos: si no, la fila se salía por la derecha. */
@media (max-width: 1130px) {
  .ms-top { gap: 8px; }
  .ms-top-actions { gap: 5px; }
  .ms-top-actions .icon-btn, .ms-top .boton-fijar { width: 34px; height: 34px; }
  .ms-top-actions .icon-btn[style] { margin-right: 0 !important; }
  .ms-join-top { margin-right: 4px; }
}
}

/* ── Los botones de cada proyecto, en modo lista ──
   Están colocados en la esquina de la PORTADA, que en modo cuadrícula es la
   franja ancha de arriba y funciona bien. En lista la portada se encoge a una
   miniatura de 84 px a la izquierda, así que los tres botones aterrizaban
   encima de ella, tapándola y pisándose entre sí.
   En lista se anclan al final de la FILA, que es donde se esperan. */
.ms-grid-list .ms-project-card { position: relative; }
.ms-grid-list .ms-card-actions {
  top: 50%;
  /* Hueco a la derecha para la nube, que va la ultima. */
  right: 52px;
  transform: translateY(-50%);
  /* Fuera de la portada: la referencia pasa a ser la fila entera. */
  position: absolute;
}
/* La portada deja de ser el marco de referencia solo en este modo. */
.ms-grid-list .ms-project-cover { position: static; }
/* Con el dedo no hay "pasar por encima", así que se ven siempre. */
html[data-touch="1"] .ms-grid-list .ms-card-actions { opacity: 1; }
/* Y en la cuadrícula también, y que se puedan pulsar: con opacidad 0 y sin
   eventos, en el teléfono editar, favorito y papelera solo salían con una
   pulsación larga que nadie adivina. */
html[data-touch="1"] .ms-card-actions { opacity: 1; pointer-events: auto; }

/* ── Online / Compartir, en la barra de arriba ──
   Antes era una pastilla gris en la fila de abajo, entre "Guardado" y el
   número de nodos: parecía un dato más y nadie caía en que se podía pulsar.
   Es la puerta a compartir y a las sesiones en vivo, así que va arriba con el
   resto de acciones y con el peso de un botón de verdad. */
.odi-share-pill {
  display: flex; align-items: center; gap: 6px;
  margin-right: 8px;
  padding: 7px 12px;
  border-radius: 8px;
  border: 1.5px solid var(--line);
  font-size: 12px; font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: var(--pop-sm);
  transition: transform 140ms var(--e-out), box-shadow 140ms var(--e-out), background 120ms;
}
.odi-share-pill .material-symbols-rounded { font-size: 17px; }
.odi-share-pill:hover { transform: translate(-1px, -2px); box-shadow: var(--pop-hover); }
.odi-share-pill:active { transform: translate(1px, 1px); box-shadow: 0 0 0 0 var(--line); }

/* Sin publicar: invita a hacerlo, sin gritar. */
.odi-share-pill.offline { background: var(--paper); color: var(--ink-2); }
.odi-share-pill.offline:hover { background: var(--bg-2); color: var(--ink); }

/* Publicado y con conexión: verde de marca, relleno. */
.odi-share-pill.online {
  background: var(--olive); color: var(--olive-ink);
}
.odi-share-pill.online .material-symbols-rounded { color: #FFFFFF; }
.odi-share-pill.online:hover { background: color-mix(in srgb, var(--olive) 85%, var(--ink)); }

/* Estás DENTRO de la sesión de otra persona: ámbar, el mismo que marca los
   proyectos prestados en el menú.
   Antes esto salía gris de "sin publicar", que es lo que menos se parece a lo
   que pasa: un invitado no está desconectado, está en el lienzo de alguien y
   lo que escribe lo está viendo esa persona. Verde tampoco vale — ese es el
   del anfitrión, el dueño de lo que hay en pantalla. */
.odi-share-pill.invitado {
  background: var(--yellow, #F7DA84);
  color: #1A1A1A;
  border-color: var(--line);
}
.odi-share-pill.invitado .material-symbols-rounded { color: #1A1A1A; }
.odi-share-pill.invitado:hover { background: #F3CE63; }

/* Publicado pero Drive no responde: hay que mirarlo, no ignorarlo. */
.odi-share-pill.caido {
  background: color-mix(in srgb, var(--wine) 14%, transparent);
  color: var(--wine-texto);
  border-color: var(--wine, #E6544F);
}

/* En una ventana estrecha se queda el icono solo. */
@media (max-width: 1250px) {
  .odi-share-pill span:not(.material-symbols-rounded) { display: none; }
  .odi-share-pill { padding: 7px 9px; }
}

/* ── Un proyecto al que te invitaron ──
   Ámbar en todo el borde, para que no se confunda con los tuyos: vive en el
   equipo de otra persona y deja de estar cuando esa persona cierra la sesión.
   Si pareciera propio, su desaparición sería un susto en vez de algo esperado. */
.ms-project-card.es-invitado {
  border-color: var(--yellow, #F7DA84);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--yellow, #F7DA84) 45%, transparent), var(--pop-sm);
}
.ms-invitado-chip {
  position: absolute; left: 8px; top: 8px; z-index: 3;
  display: flex; align-items: center; gap: 4px;
  padding: 3px 8px 3px 6px;
  border-radius: 999px;
  background: var(--yellow, #F7DA84);
  border: 1.5px solid var(--line);
  color: #1A1A1A;
  font-size: 10.5px; font-weight: 800;
  box-shadow: 1px 1px 0 var(--line);
}
.ms-invitado-chip .material-symbols-rounded { font-size: 13px; }

/* ============================================
   CARPETAS DE PROYECTOS (pantalla de inicio)
   ============================================
   Una carpeta se pinta como una tarjeta de proyecto más —mismo tamaño, mismo
   sitio en la rejilla— porque en esa pantalla se usan igual: se abren con un
   clic. Lo único que la distingue es la portada, que en vez de un color y un
   emoji enseña los colores de lo que guarda dentro. */
.ms-folder-card .ms-folder-cover {
  background: var(--bg);
  border-bottom: 1.5px solid var(--line);
  display: grid; place-items: center;
}
.ms-folder-peek {
  display: grid; grid-template-columns: 1fr 1fr; gap: 5px;
  width: 62%; max-width: 120px;
}
.ms-folder-peek > i {
  display: block; height: 26px; border-radius: 3px;
  border: 1.5px solid rgba(0, 0, 0, 0.10);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}
/* Con un solo proyecto dentro, su color ocupa la portada entera en vez de
   quedarse en un cuadradito arriba a la izquierda. */
.ms-folder-peek > i:only-child { grid-column: span 2; height: 58px; }
.ms-folder-vacia { font-size: 40px; color: var(--ink-3); opacity: 0.55; }
/* Con color propio: la portada se tiñe (suave, para que los colores de dentro
   se sigan viendo) y el icono de carpeta lleva el color entero. */
.ms-folder-card.con-color .ms-folder-cover { background: color-mix(in srgb, var(--carpeta-color) 26%, var(--bg)); }
.ms-folder-card.con-color .ms-folder-icono { color: var(--carpeta-color); font-variation-settings: 'FILL' 1; }
.ms-folder-card.con-color .ms-folder-vacia { color: var(--carpeta-color); opacity: 0.85; }
/* El selector de color, encima de la portada: dentro de la tarjeta para no
   salirse de la rejilla en la última fila. */
.ms-folder-pintar {
  position: absolute; inset: 6px; z-index: 5; overflow: auto; cursor: default;
  padding: 10px; display: flex; flex-direction: column; gap: 8px;
  background: var(--paper); border: 1.5px solid var(--line); border-radius: 8px;
  box-shadow: var(--pop);
  animation: fijar-opacidad-entra 220ms var(--muelle) both;
}
.ms-folder-pintar-tit { font-size: 11.5px; font-weight: 700; color: var(--ink-2); }
.ms-folder-pintar-listo {
  align-self: flex-end; padding: 4px 12px; border-radius: 6px;
  border: 1.5px solid var(--line); background: var(--olive); color: var(--olive-ink);
  font-size: 12px; font-weight: 700; cursor: pointer;
}

/* El botón de crear carpeta, en la fila del título. */
.ms-carpeta-btn {
  display: inline-flex; align-items: center; gap: 6px;
  margin-left: auto; margin-right: 8px;
  padding: 5px 10px;
  font-size: 12px; font-weight: 700;
  background: var(--paper); color: var(--ink);
  border: 1.5px solid var(--line); border-radius: 2px;
  cursor: pointer; transition: background 100ms;
}
.ms-carpeta-btn:hover { background: var(--bg); }
.ms-carpeta-btn .material-symbols-rounded { font-size: 16px; }

/* Migas de pan al entrar en una carpeta. */
.ms-carpeta-migas { display: inline-flex; align-items: center; gap: 8px; }
.ms-carpeta-migas button {
  display: grid; place-items: center;
  width: 26px; height: 26px;
  border: 1.5px solid var(--line); border-radius: 2px;
  background: var(--paper); cursor: pointer; transition: background 100ms;
}
.ms-carpeta-migas button:hover { background: var(--bg); }
.ms-carpeta-migas .material-symbols-rounded { font-size: 18px; }

/* En qué carpeta vive un proyecto, cuando se ve fuera de ella. */
.ms-carpeta-chip {
  display: inline-flex; align-items: center; gap: 3px;
  max-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  padding: 1px 6px; border-radius: 99px;
  background: var(--bg); border: 1px solid var(--line-soft);
  color: var(--ink-3);
}
.ms-carpeta-chip .material-symbols-rounded { font-size: 13px; }

/* La lista de la ventana de mover. */
.ms-carpeta-lista {
  display: flex; flex-direction: column; gap: 3px;
  max-height: 220px; overflow-y: auto;
  margin-bottom: 14px;
  padding: 4px; border: 1.5px solid var(--line); border-radius: 2px;
  background: var(--paper-2);
}
.ms-carpeta-op {
  display: flex; align-items: center; gap: 8px;
  width: 100%; text-align: left;
  padding: 8px 10px; border: none; border-radius: 2px;
  background: transparent; color: var(--ink);
  font-family: var(--font-body); font-size: 13px; cursor: pointer;
  transition: background 100ms;
}
.ms-carpeta-op:hover { background: var(--bg); }
.ms-carpeta-op.active { background: var(--olive); color: var(--olive-ink); font-weight: 700; }
.ms-carpeta-op .material-symbols-rounded { font-size: 18px; flex-shrink: 0; }
.ms-carpeta-op .tic { margin-left: auto; }
.ms-carpeta-nueva-fila { display: flex; gap: 8px; }
.ms-carpeta-nueva-fila input { flex: 1; min-width: 0; }
.ms-carpeta-nueva-fila .btn { flex-shrink: 0; }
.ms-carpeta-aviso {
  color: var(--wine-texto); font-size: 12px; font-weight: 600;
  margin: -4px 0 8px !important;
}

/* Arrastrar un proyecto a una carpeta. Mientras se arrastra, las carpetas se
   marcan un poco para que se vea que son las que reciben; la que tiene el
   proyecto encima se marca del todo. Sin esa senal no se sabe si vas a
   soltarlo dentro o al lado. */
body.arrastrando-proyecto .ms-folder-card { outline: 2px dashed var(--line); outline-offset: 3px; }
.ms-folder-card.soltando {
  outline: 2.5px solid var(--olive) !important; outline-offset: 3px;
  transform: translate(-1px, -3px);
}
.ms-folder-card.soltando .ms-folder-cover { background: var(--olive-l); }
/* La flecha de volver tambien recibe: soltar ahi saca el proyecto. */
body.arrastrando-proyecto .ms-carpeta-migas button { outline: 2px dashed var(--line); outline-offset: 2px; }

/* La lista de "anadir proyectos". */
.ms-anadir-nombre { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ms-anadir-donde {
  display: inline-flex; align-items: center; gap: 3px; flex-shrink: 0;
  font-size: 11px; color: var(--ink-3);
}
.ms-anadir-donde .material-symbols-rounded { font-size: 13px; }

/* El cuadrado de sacar de la carpeta. Va en la rejilla, del tamaño de una
   tarjeta, pero con el borde de puntos que dice "aquí se suelta, esto no se
   abre": la flecha de volver ya recibía, pero eso no lo adivina nadie. */
.ms-sacar-card {
  border: 2px dashed var(--line-soft) !important;
  background: transparent;
  box-shadow: none;
  display: grid; place-items: center;
  color: var(--ink-3);
  cursor: default;
  transition: border-color 120ms, background 120ms, color 120ms;
}
.ms-sacar-card:hover { transform: none; box-shadow: none; }
.ms-sacar-cuerpo { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 14px; text-align: center; }
.ms-sacar-cuerpo .material-symbols-rounded { font-size: 30px; opacity: 0.75; }
.ms-sacar-tit { font-family: var(--font-display); font-weight: 700; font-size: 13px; }
.ms-sacar-pie { font-size: 11px; opacity: 0.75; }
/* Mientras se arrastra algo se marca, y del todo cuando lo tiene encima. */
body.arrastrando-proyecto .ms-sacar-card { border-color: var(--wine) !important; color: var(--wine-texto); }
.ms-sacar-card.soltando {
  border-color: var(--wine) !important;
  background: var(--wine-l, rgba(230, 84, 79, 0.12));
  color: var(--wine-texto);
}


/* ── Grupos y candado ──
   El candado se ve en la esquina del nodo elegido, del tamaño de los
   tiradores (--handle-libre: mide lo mismo en pantalla a cualquier zoom). */
.item.bloqueado { cursor: default; }
.nodo-candado {
  position: absolute; top: 0; right: 0; z-index: 6;
  width: 22px; height: 22px; display: grid; place-items: center;
  transform: translate(50%, -50%) scale(var(--handle-libre, 1));
  border: 1.5px solid var(--line); border-radius: 50%;
  background: var(--paper); color: var(--ink);
  box-shadow: var(--pop-sm);
  pointer-events: none;
  animation: candado-entra 260ms var(--muelle) both;
}
.nodo-candado .material-symbols-rounded { font-size: 13px; font-variation-settings: 'FILL' 1; }
@keyframes candado-entra { from { transform: translate(50%, -50%) scale(0); } to { transform: translate(50%, -50%) scale(var(--handle-libre, 1)); } }
/* El borde de un grupo elegido. */
.grupo-marco {
  position: absolute; z-index: 99; pointer-events: none;
  border: 1.5px dashed var(--olive); border-radius: 6px;
  animation: grupo-entra 220ms var(--muelle) both;
}
@keyframes grupo-entra { from { opacity: 0; transform: scale(0.98); } to { opacity: 1; transform: none; } }
/* La barrita encima de una selección de varios. */
.seleccion-barra {
  position: absolute; z-index: 45; transform: translateX(-50%);
  display: flex; align-items: center; gap: 4px; padding: 4px;
  background: var(--paper); color: var(--ink);
  border: 1.5px solid var(--line); border-radius: 10px;
  box-shadow: var(--pop);
  animation: seleccion-entra 220ms var(--muelle) both;
}
@keyframes seleccion-entra { from { opacity: 0; transform: translate(-50%, 6px) scale(0.96); } to { opacity: 1; transform: translateX(-50%); } }
.seleccion-cuenta { padding: 0 8px; font-size: 11.5px; font-weight: 700; color: var(--ink-2); white-space: nowrap; }
.seleccion-barra button {
  display: flex; align-items: center; gap: 5px;
  padding: 5px 10px; border-radius: 7px; border: 1.5px solid transparent;
  background: transparent; color: var(--ink);
  font-size: 12px; font-weight: 700; cursor: pointer; white-space: nowrap;
  transition: background 120ms, border-color 120ms;
}
.seleccion-barra button:hover { background: var(--paper-2); border-color: var(--line-soft); }
.seleccion-barra button.activo { background: var(--olive); color: var(--olive-ink); border-color: var(--line); }
.seleccion-barra button .material-symbols-rounded { font-size: 17px; }

/* Botones de alinear, dentro de la barrita de la selección (Canvas.jsx), en
   la misma fila: la barrita va encima de lo elegido, y un desplegable debajo
   lo taparía justo cuando se quiere ver cómo queda. */
.alinea-panel { display: flex; align-items: center; gap: 2px; padding-left: 4px; border-left: 1.5px solid var(--line-soft); }
.alinea-panel__grupo { display: flex; gap: 2px; }
.alinea-panel__grupo + .alinea-panel__grupo { margin-left: 4px; padding-left: 6px; border-left: 1.5px solid var(--line-soft); }
.seleccion-barra .alinea-panel__boton { justify-content: center; width: 30px; height: 30px; padding: 0; }
.seleccion-barra .alinea-panel__boton:disabled { opacity: 0.35; cursor: default; }
.seleccion-barra .alinea-panel__boton:disabled:hover { background: transparent; border-color: transparent; }

/* ── Las plantillas, abajo a la derecha del lienzo ── */
.plantillas-esquina { position: absolute; bottom: 16px; z-index: 41; display: flex; flex-direction: column; align-items: flex-end; gap: 8px; }
.icon-btn.plantillas-boton {
  width: auto; height: 32px; padding: 0 11px 0 9px; gap: 6px;
  display: flex; align-items: center; border-radius: 2px;
  font-size: 12.5px; font-weight: 700; color: var(--ink);
}
.icon-btn.plantillas-boton .material-symbols-rounded { font-size: 18px; }
.icon-btn.plantillas-boton.abierto { background: var(--olive); color: var(--olive-ink); }
.plantillas-panel {
  width: 320px; padding: 8px;
  background: var(--paper); color: var(--ink);
  border: 1.5px solid var(--line); border-radius: 10px;
  box-shadow: var(--pop);
  display: flex; flex-direction: column; gap: 4px;
  transform-origin: bottom right;
  animation: plantillas-entra 260ms var(--muelle) both;
}
@keyframes plantillas-entra { from { opacity: 0; transform: translateY(8px) scale(0.94); } to { opacity: 1; transform: none; } }
.plantillas-tit { padding: 4px 6px 6px; font-size: 11px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-3); }
.plantilla {
  display: flex; align-items: center; gap: 10px; text-align: left;
  padding: 8px; border-radius: 8px; border: 1.5px solid transparent;
  background: transparent; color: var(--ink); cursor: pointer;
  transition: background 120ms, border-color 120ms, transform 160ms var(--muelle);
}
.plantilla:hover { background: var(--paper-2); border-color: var(--line-soft); transform: translateX(-2px); }
.plantilla-icono {
  width: 34px; height: 34px; flex-shrink: 0; display: grid; place-items: center;
  border: 1.5px solid var(--line); border-radius: 8px;
  background: var(--olive); color: var(--olive-ink); font-size: 19px;
}
.plantilla-textos { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.plantilla-textos b { font-size: 13px; }
.plantilla-textos small { font-size: 11.5px; color: var(--ink-2); line-height: 1.3; }
/* En el teléfono la fila de abajo no tiene sitio para el texto. */
html[data-mobile="1"] .plantillas-boton span:not(.material-symbols-rounded) { display: none; }
html[data-mobile="1"] .plantillas-panel { width: min(320px, calc(100vw - 24px)); }
/* Y en la fila de abajo del teléfono (ver «Franja inferior del lienzo»), detrás
   del botón del fondo. Con el right fijo de escritorio (205 px) caía encima de
   ese botón en una pantalla de 375. El panel se abre desde el borde izquierdo,
   que es donde cabe. */
html[data-mobile="1"] .plantillas-esquina {
  left: 196px !important;
  right: auto !important;
  bottom: calc(14px + env(safe-area-inset-bottom)) !important;
  align-items: flex-start;
}
html[data-mobile="1"] .plantillas-panel {
  position: fixed;
  left: max(12px, env(safe-area-inset-left));
  bottom: calc(66px + env(safe-area-inset-bottom));
}


/* ── El panel de color propio (ColorPicker.jsx, PanelColorLibre) ──
   La propuesta C: la rueda y el cuadro a la izquierda, códigos y paletas a la
   derecha. Va en el body con posición fija, pegado al panel del arcoíris. */
.panel-color {
  position: fixed; z-index: 960;
  width: 440px; max-width: calc(100vw - 16px);
  display: flex; gap: 14px; padding: 12px;
  background: var(--paper); color: var(--ink);
  border: 1.5px solid var(--line); border-radius: 10px;
  box-shadow: var(--pop);
  font-size: 12px;
  transform-origin: left center;
  animation: panel-color-entra 240ms var(--muelle) both;
}
@keyframes panel-color-entra { from { opacity: 0; transform: translateX(-6px) scale(0.96); } to { opacity: 1; transform: none; } }
.panel-color-izq { display: flex; flex-direction: column; align-items: center; gap: 10px; flex-shrink: 0; }
.panel-color-der { display: flex; flex-direction: column; gap: 7px; flex: 1; min-width: 0; }

.panel-color-rueda { position: relative; touch-action: none; cursor: crosshair; flex-shrink: 0; }
.panel-color-aro {
  position: absolute; inset: 0; border-radius: 50%;
  background: conic-gradient(#F00, #FF0, #0F0, #0FF, #00F, #F0F, #F00);
}
/* Los dos bordes del aro, el de fuera y el de dentro, con la tinta de la app. */
.panel-color-rueda::before {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  border: 1.5px solid var(--line); pointer-events: none; z-index: 1;
}
.panel-color-aro-borde { position: absolute; border-radius: 50%; border: 1.5px solid var(--line); pointer-events: none; }
.panel-color-cuadro {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  border: 1.5px solid var(--line); border-radius: 4px; outline: none;
}
.panel-color-cuadro:focus-visible, .panel-color-mira.aro:focus-visible { box-shadow: 0 0 0 3px var(--olive-2); }
.panel-color-mira {
  position: absolute; width: 14px; height: 14px; margin: -7px 0 0 -7px;
  border: 2.5px solid #FFFFFF; border-radius: 50%;
  box-shadow: 0 0 0 1.5px #1A1A1A, inset 0 0 0 1px rgba(0,0,0,0.25);
  pointer-events: none; z-index: 2;
}
.panel-color-mira.aro { width: 16px; height: 16px; margin: -8px 0 0 -8px; outline: none; }

.panel-color-bajo-rueda { display: flex; align-items: center; gap: 6px; align-self: stretch; }
.panel-color-recientes { display: flex; gap: 4px; flex-wrap: wrap; }

.panel-color-casilla {
  width: 18px; height: 18px; padding: 0; flex-shrink: 0; cursor: pointer;
  border: 1.5px solid var(--line); border-radius: 4px;
  transition: transform 160ms var(--muelle);
}
.panel-color-casilla:hover { transform: translateY(-1px) scale(1.12); }
.panel-color-casilla.activa { box-shadow: 0 0 0 2px var(--paper), 0 0 0 3.5px var(--ink); }

.panel-color-icono {
  width: 28px; height: 28px; flex-shrink: 0; padding: 0; cursor: pointer;
  display: grid; place-items: center;
  background: #FFFFFF; color: #1A1A1A;
  border: 1.5px solid var(--line); border-radius: 5px;
}
.panel-color-icono .material-symbols-rounded { font-size: 16px; }
.panel-color-icono:hover { background: #F3F2EE; }
.panel-color-icono.activo { background: var(--olive); color: var(--olive-ink); }

.panel-color-arriba { display: flex; align-items: stretch; height: 30px; }
.panel-color-antes, .panel-color-ahora {
  flex: 1; display: grid; place-items: center;
  border: 1.5px solid var(--line); font-size: 11px; font-weight: 700; padding: 0;
}
.panel-color-antes { border-radius: 5px 0 0 5px; border-right: none; cursor: pointer; }
.panel-color-ahora { border-radius: 0 5px 5px 0; }
.panel-color-listo {
  margin-left: 8px; padding: 0 12px; cursor: pointer;
  background: var(--olive); color: var(--olive-ink); font-weight: 700; font-size: 12px;
  border: 1.5px solid var(--line); border-radius: 5px;
}

.panel-color-fila { display: flex; align-items: center; gap: 6px; }
.panel-color-etiqueta { width: 30px; flex-shrink: 0; font-size: 10.5px; font-weight: 700; letter-spacing: 0.04em; color: var(--ink-2); }
.panel-color-campo {
  flex: 1; min-width: 0; height: 28px; padding: 0 8px;
  font-family: var(--font-mono, ui-monospace, monospace); font-size: 12px;
  background: var(--paper-2); color: var(--ink);
  border: 1.5px solid var(--line); border-radius: 5px; outline: none;
}
.panel-color-campo:focus { border-color: var(--olive); box-shadow: 0 0 0 2px var(--olive-l); }

.panel-color-tit { margin-top: 4px; font-size: 10.5px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-3); }
.panel-color-paletas { display: flex; flex-direction: column; gap: 6px; max-height: 128px; overflow-y: auto; padding-right: 2px; }
.panel-color-vacio { font-size: 11.5px; color: var(--ink-2); line-height: 1.4; }
.panel-color-paleta { display: flex; align-items: center; gap: 6px; }
.panel-color-nombre {
  width: 64px; flex-shrink: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 11.5px; color: var(--ink-2); cursor: text;
}
.panel-color-nombre-campo {
  width: 64px; flex-shrink: 0; height: 22px; padding: 0 4px; font-size: 11.5px;
  background: var(--paper-2); color: var(--ink); border: 1.5px solid var(--olive); border-radius: 4px; outline: none;
}
.panel-color-paleta-casillas { display: flex; gap: 4px; flex-wrap: wrap; flex: 1; min-width: 0; }
.panel-color-mas, .panel-color-borra {
  width: 18px; height: 18px; padding: 0; flex-shrink: 0; cursor: pointer;
  display: grid; place-items: center;
  background: transparent; color: var(--ink-3);
  border: 1.5px dashed var(--line-soft); border-radius: 4px;
}
.panel-color-mas .material-symbols-rounded, .panel-color-borra .material-symbols-rounded { font-size: 14px; }
.panel-color-mas:hover { color: var(--ink); border-color: var(--line); }
.panel-color-borra { border: none; opacity: 0; transition: opacity 120ms; }
.panel-color-paleta:hover .panel-color-borra, .panel-color-borra:focus-visible { opacity: 1; }
.panel-color-borra:hover { color: var(--wine-texto); }
.panel-color-borra.seguro { opacity: 1; color: var(--wine-ink); background: var(--wine); border-radius: 4px; }

.panel-color-botones { display: flex; gap: 6px; margin-top: 2px; }
.panel-color-boton {
  flex: 1; height: 30px; padding: 0 8px; cursor: pointer;
  display: flex; align-items: center; justify-content: center; gap: 5px;
  background: #FFFFFF; color: #1A1A1A; font-size: 12px; font-weight: 700; white-space: nowrap;
  border: 1.5px solid var(--line); border-radius: 5px;
}
.panel-color-boton .material-symbols-rounded { font-size: 16px; }
.panel-color-boton.verde { background: var(--olive); color: var(--olive-ink); }
.panel-color-boton:hover { filter: brightness(0.96); }

/* El arcoíris con su panel abierto. */
.selector-color-libre.abierto { box-shadow: 0 0 0 2px var(--paper), 0 0 0 3.5px var(--olive); }

/* El cuentagotas sin EyeDropper: se toca una imagen del lienzo. */
body.odi-cuentagotas, body.odi-cuentagotas * { cursor: crosshair !important; }

/* En la ventana estrecha, apilado: la rueda arriba. */
@media (max-width: 520px) {
  .panel-color:not(.en-hoja) { flex-direction: column; align-items: stretch; width: auto; }
}
/* En el teléfono va dentro de la hoja de abajo, que ya tiene su fondo y su borde. */
.panel-color.en-hoja {
  position: static; width: auto; max-width: none;
  flex-direction: column; align-items: stretch;
  padding: 0; border: none; box-shadow: none; background: transparent; animation: none;
}
.panel-color.en-hoja .panel-color-casilla { width: 28px; height: 28px; }
.panel-color.en-hoja .panel-color-icono { width: 36px; height: 36px; }
.panel-color.en-hoja .panel-color-campo { height: 36px; }
.panel-color.en-hoja .panel-color-paletas { max-height: none; }
.panel-color.en-hoja .panel-color-mas { width: 28px; height: 28px; }
.panel-color.en-hoja .panel-color-borra { opacity: 1; width: 28px; height: 28px; }


/* ── Ajustes: el tamaño de toda la aplicación (Ventana.jsx, AjusteEscala) ── */
.ajuste-escala { display: flex; flex-direction: column; gap: 8px; }
.ajuste-escala-fila { display: flex; align-items: center; gap: 10px; }
.ajuste-escala-barra { flex: 1; accent-color: var(--olive); cursor: pointer; }
.ajuste-escala-icono { color: var(--ink-2); flex-shrink: 0; }
.ajuste-escala-icono.pequena { font-size: 15px; }
.ajuste-escala-icono.grande { font-size: 24px; }
.ajuste-escala-valor {
  min-width: 54px; text-align: right;
  font-family: var(--font-mono, ui-monospace, monospace); font-size: 13px; font-weight: 700;
  color: var(--ink);
}
.ajuste-escala-rapidos { display: flex; gap: 6px; flex-wrap: wrap; }
.ajuste-escala-rapido {
  padding: 5px 10px; cursor: pointer;
  background: #FFFFFF; color: #1A1A1A; font-size: 12px; font-weight: 700;
  border: 1.5px solid var(--line-soft); border-radius: 6px;
}
.ajuste-escala-rapido:hover { border-color: var(--line); }
.ajuste-escala-rapido.activo { background: var(--olive); color: var(--olive-ink); border-color: var(--olive); }
.ajuste-escala-nota { margin: 0; font-size: 12px; line-height: 1.5; color: var(--text-soft, #595459); }


/* ── La terminal del nodo de código (items.jsx, CodeItem; ejecuta-codigo.js) ── */
.code-run {
  flex: 0 0 auto; width: 22px; height: 22px; padding: 0; cursor: pointer;
  display: grid; place-items: center;
  background: var(--olive); color: var(--olive-ink);
  border: 1.5px solid rgba(0,0,0,0.35); border-radius: 50%;
  transition: transform 160ms var(--muelle);
}
.code-run .material-symbols-rounded { font-size: 16px; }
.code-run:hover { transform: scale(1.12); }
.code-run:active { transform: scale(0.92); }
.code-run.corriendo { background: var(--wine); }
/* Con el dedo, al menos 30 px de pantalla: alejado al 70 %, los 22 px del nodo
   se quedaban en 15 y no había quien le diera. --handle-libre es 1/zoom. */
html[data-mobile="1"] .code-run {
  width: max(22px, calc(30px * var(--handle-libre, 1)));
  height: max(22px, calc(30px * var(--handle-libre, 1)));
}
html[data-mobile="1"] .code-run .material-symbols-rounded { font-size: max(16px, calc(20px * var(--handle-libre, 1))); }
/* El ▶ y la terminal se pueden usar sin elegir antes el nodo (el resto de la
   tarjeta no recibe clics hasta elegirlo, ver «Node-first editing»). */
.item:not(.selected):not(.editing) .code-run,
.item:not(.selected):not(.editing) .code-terminal,
.item:not(.selected):not(.editing) .code-terminal * { pointer-events: auto; }

.code-terminal {
  flex: 0 1 auto; max-height: 48%; min-height: 64px;
  display: flex; flex-direction: column;
  background: #0A0F1A; color: #DDE6F5;
  border-top: 1px solid rgba(255,255,255,0.12);
  animation: code-terminal-entra 220ms var(--muelle) both;
}
@keyframes code-terminal-entra { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.code-terminal-barra {
  flex: 0 0 auto; display: flex; align-items: center; gap: 7px;
  padding: 4px 6px 4px 10px;
  border-bottom: 1px solid rgba(255,255,255,0.07);
  font-size: 10.5px;
}
.code-terminal-icono { font-size: 15px; opacity: 0.7; }
.code-terminal-tit { font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; opacity: 0.8; }
.code-terminal-estado { margin-left: auto; font-family: var(--font-mono); opacity: 0.75; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.code-terminal-estado.corriendo { color: #F5C26B; opacity: 1; }
.code-terminal-estado.hecho { color: #9AD27A; }
.code-terminal-estado.fallo, .code-terminal-estado.tiempo { color: #FF8A80; opacity: 1; }
.code-terminal-btn {
  width: 22px; height: 22px; padding: 0; flex: 0 0 auto; cursor: pointer;
  display: grid; place-items: center;
  background: transparent; color: #DDE6F5; opacity: 0.7;
  border: none; border-radius: 4px;
}
.code-terminal-btn .material-symbols-rounded { font-size: 15px; }
.code-terminal-btn:hover { opacity: 1; background: rgba(255,255,255,0.10); }
.code-terminal-salida {
  flex: 1 1 auto; min-height: 0; overflow: auto;
  padding: 6px 10px 8px;
  font-family: var(--font-mono), 'JetBrains Mono', ui-monospace, monospace;
  font-size: calc(11.5px * var(--node-scale, 1));
  line-height: 1.45;
  user-select: text; cursor: text;
}
.code-linea { white-space: pre-wrap; word-break: break-word; }
.code-linea.info { color: #9CC4FF; }
.code-linea.warn { color: #F5C26B; }
.code-linea.error { color: #FF8A80; }
.code-linea.resultado { color: #9AD27A; }
.code-linea.vacia { opacity: 0.5; font-style: italic; }


/* ── 1.2: el muelle en el resto de la aplicación ──
   Lo dijo el usuario: la 1.2 es de animaciones «tipo iPhone». La carpeta, la
   ruleta, la galería y el caracol de More ya estrenaron --muelle (una curva
   que se pasa un poco y vuelve); aquí va al resto de lo que más se ve. Lo que
   aparece crece un pelo de más y se asienta; lo que se pulsa se hunde rápido
   y rebota al soltarlo.
   Con «backwards» y no «both»: al acabar, cada cosa vuelve a SU transform
   (las que se colocan con uno no se quedan pegadas al final de la animación). */
@keyframes muelle-aparece { from { opacity: 0; transform: scale(0.92) translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes muelle-lado { from { opacity: 0; transform: translateX(-10px) scale(0.97); } to { opacity: 1; transform: none; } }
@keyframes nodo-aparece { from { opacity: 0; transform: scale(0.88) translateY(8px); } to { opacity: 1; transform: none; } }

/* Ventanas y menús. */
.modal { animation: muelle-aparece 320ms var(--muelle) backwards; }
.doc-modal-window { animation: muelle-aparece 340ms var(--muelle) backwards; }
.context-menu { transform-origin: top left; animation: muelle-aparece 240ms var(--muelle) backwards; }
/* La barra del nodo y sus paneles, desde la izquierda, que es de donde salen. */
.ctx-side { animation: muelle-lado 300ms var(--muelle) backwards; }
.ctx-popout { transform-origin: left top; animation: muelle-lado 280ms var(--muelle) backwards; }

/* Un nodo nuevo cae en su sitio con un pequeño rebote. */
.item.new-item .item-card { animation: nodo-aparece 380ms var(--muelle) backwards; }

/* Pulsar: abajo rápido (70 ms, sin rebote) y vuelta con muelle. */
.press { transition: transform 300ms var(--muelle); }
.press:active { transform: scale(0.94); transition-duration: 70ms; transition-timing-function: var(--e-out); }
.icon-btn { transition: transform 260ms var(--muelle), box-shadow 160ms var(--e-out); }
.icon-btn:active { transform: translate(1px, 1px) scale(0.96); box-shadow: 0 0 0 0 var(--line); transition-duration: 70ms; transition-timing-function: var(--e-out); }
.tool { transition: transform 260ms var(--muelle), background 100ms; }
.tool:active { transform: scale(0.94); transition-duration: 70ms; transition-timing-function: var(--e-out); }

/* Las tarjetas de inicio y todo lo que «se levanta» al pasar el ratón. */
.ms-project-card, .ms-recent-card, .lift { transition: transform 280ms var(--muelle), box-shadow 180ms var(--e-out); }

/* Quien pide menos movimiento en el sistema no lo tiene. */
@media (prefers-reduced-motion: reduce) {
  .modal, .doc-modal-window, .context-menu, .ctx-side, .ctx-popout,
  .item.new-item .item-card, .panel-color, .plantillas-panel, .code-terminal { animation-duration: 1ms !important; }
  .press, .icon-btn, .tool, .ms-project-card, .ms-recent-card, .lift { transition-duration: 1ms !important; }
  /* La ruleta gira igual (es lo que hace), pero sin lo demás que se mueve. */
  .ruleta-centro-gira, .ruleta-premio, .ruleta-porcion.nueva { animation: none !important; }
}


/* ── Un solo selector: el panel grande dentro del panel lateral ── */
.ctx-popout:has(.selector-color-caja.entero) { width: auto; }
.panel-color.incrustado {
  position: static; width: 440px; max-width: none;
  padding: 0; border: none; box-shadow: none; background: transparent;
  animation: none;
}
/* El historial, en su apartado. */
.panel-color-historial { display: flex; gap: 4px; flex-wrap: wrap; min-height: 22px; align-items: center; padding: 2px; }
/* Las casillas de las paletas se recortaban: la lista se desplaza y su borde
   cortaba el aro de la elegida (que va por fuera de la casilla). Con un poco de
   aire dentro, el aro cabe. */
.panel-color-paletas { padding: 4px 4px 4px 3px; margin: -4px -4px -4px -3px; }
.panel-color-paleta-casillas { padding: 2px 0; }
.panel-color-paleta.fija .panel-color-nombre { font-weight: 700; color: var(--ink); }
/* «Sin color»: blanca con una raya roja, como en cualquier programa de diseño. */
.panel-color-casilla.sin-color {
  background: linear-gradient(135deg, #FFFFFF 44%, #E6544F 44%, #E6544F 56%, #FFFFFF 56%);
}
/* El nombre de una paleta mientras se escribe, con su OK. */
.panel-color-nombre-caja { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
.panel-color-nombre-caja .panel-color-nombre-campo { width: 84px; }
.panel-color-ok {
  height: 22px; padding: 0 7px; flex-shrink: 0; cursor: pointer;
  background: var(--olive); color: var(--olive-ink); font-size: 11px; font-weight: 700;
  border: 1.5px solid var(--line); border-radius: 4px;
}
.panel-color-gotero-texto { font-size: 11.5px; font-weight: 700; color: var(--ink-2); }

/* El ▶ de un bloque que no es JavaScript: gris, y al pulsarlo la terminal
   explica cómo ejecutarlo. */
.code-run.otro-lenguaje { background: #5A6475; }

/* ══ La barra de nodos a un lado o abajo (Ajustes → Barra de nodos) ══
   Lo pidió el usuario: arriba (lo de siempre), a la izquierda, a la derecha o
   abajo. La posición vive en <html data-barra>, la pone index.html antes de
   pintar nada (sin destello) y la cambia Ajustes. Solo en el escritorio: en el
   teléfono la barra tiene su propio sitio.
   La barra (.tools-wrap) sigue dentro de .topbar, pero en estos modos se saca
   con position: fixed; --alto-topbar lo mide Topbar.jsx. A los lados acaba
   encima de la fila de abajo (estado, zoom, plantillas) para no taparla, y
   abajo se queda en el hueco del medio de esa fila. */
html:not([data-mobile="1"])[data-barra="left"] .topbar .tools-wrap,
html:not([data-mobile="1"])[data-barra="right"] .topbar .tools-wrap {
  position: fixed;
  top: calc(var(--alto-topbar, 62px) + 12px);
  bottom: 66px;
  z-index: 60;
  max-height: none;
}
html:not([data-mobile="1"])[data-barra="left"] .topbar .tools-wrap { left: 12px; }
html:not([data-mobile="1"])[data-barra="right"] .topbar .tools-wrap { right: 12px; }
html:not([data-mobile="1"])[data-barra="left"] .topbar .tools,
html:not([data-mobile="1"])[data-barra="right"] .topbar .tools {
  flex-direction: column;
  align-items: stretch;
  overflow-x: hidden;
  overflow-y: auto;
  min-height: 0;
  flex: 0 1 auto;
  scrollbar-width: thin;
  scrollbar-color: var(--line-soft) transparent;
}
html:not([data-mobile="1"])[data-barra="left"] .topbar .tool-divider,
html:not([data-mobile="1"])[data-barra="right"] .topbar .tool-divider {
  width: auto; height: 1.5px; margin: 3px 4px;
}
/* El deslizador es para desplazarse a lo ancho: de lado sobra (rueda o barra). */
html:not([data-mobile="1"])[data-barra="left"] .topbar .tools-slider,
html:not([data-mobile="1"])[data-barra="right"] .topbar .tools-slider { display: none; }

html:not([data-mobile="1"])[data-barra="bottom"] .topbar .tools-wrap {
  position: fixed;
  left: 50%;
  bottom: 12px;
  transform: translateX(-50%);
  z-index: 60;
  /* El hueco entre la barra de estado (izquierda) y el zoom y las plantillas
     (derecha). Si no caben todos los nodos, se desplaza como arriba. */
  max-width: calc(100vw - 720px);
  min-width: 260px;
}

/* Lo que estaba en ese lado se aparta. */
html:not([data-mobile="1"])[data-barra="left"] .ctx-side,
html:not([data-mobile="1"])[data-barra="left"] .ctx-side.text-format,
html:not([data-mobile="1"])[data-barra="left"] .ctx-side.ctx-side-day { left: 100px; }
html:not([data-mobile="1"])[data-barra="right"] .fijar-lienzo { right: 100px; }

/* La tira del caracol sale hacia donde hay sitio (Topbar.jsx la coloca); el
   pico que la une a la concha solo cuadra con la barra arriba. */
html:not([data-mobile="1"])[data-barra="left"] .mas-serpiente::before,
html:not([data-mobile="1"])[data-barra="right"] .mas-serpiente::before,
html:not([data-mobile="1"])[data-barra="bottom"] .mas-serpiente::before { display: none; }
html:not([data-mobile="1"])[data-barra="left"] .mas-serpiente { transform-origin: 0 0; }
html:not([data-mobile="1"])[data-barra="bottom"] .mas-serpiente { transform-origin: calc(100% - var(--pico)) 100%; }

/* El dibujito de cada sitio en Ajustes. */
.barra-sitios { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.barra-sitio {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 10px 6px 8px; border: 1.5px solid var(--line); border-radius: 8px;
  background: var(--paper); box-shadow: var(--pop-sm); cursor: pointer;
  font-size: 12px; font-weight: 700; color: var(--ink);
}
.barra-sitio.activo { background: var(--olive); color: var(--olive-ink); }
.barra-sitio-dibujo {
  position: relative; width: 58px; height: 40px; box-sizing: border-box;
  border: 1.5px solid currentColor; border-radius: 4px; opacity: 0.9;
}
.barra-sitio-dibujo::after { content: ''; position: absolute; background: currentColor; border-radius: 1px; }
.barra-sitio-dibujo.arriba::after { left: 4px; right: 4px; top: 4px; height: 5px; }
.barra-sitio-dibujo.izquierda::after { top: 4px; bottom: 4px; left: 4px; width: 5px; }
.barra-sitio-dibujo.derecha::after { top: 4px; bottom: 4px; right: 4px; width: 5px; }
.barra-sitio-dibujo.abajo::after { left: 14px; right: 14px; bottom: 4px; height: 5px; }

/* ══ El teléfono, rehecho (17/10, la propuesta A) ══
   Lo pidió el usuario: la versión de teléfono se le hacía incómoda. Se miró
   cómo lo hacen Freeform y Notas en el iPhone y Samsung Notes, y se eligió:
   · las herramientas ABAJO, donde llega el pulgar: Nota, Tareas, Imagen,
     Lápiz y «Más», que abre una hoja con todos los nodos (Topbar.jsx,
     HojaNodos). Fuera el raíl de la derecha y su botón flotante;
   · con un nodo elegido, esa misma fila es la barra del nodo (con :has, sin
     tocar el JS de cada barra);
   · deshacer y rehacer arriba, a la vista;
   · nada que se toque por debajo de 44 px. */
html[data-mobile="1"] .solo-movil {
  display: grid; place-items: center; flex: 0 0 auto;
  width: 44px; height: 44px; padding: 0;
  border: none; background: none; color: var(--ink);
}
html[data-mobile="1"] .solo-movil:disabled { opacity: 0.35; }
html[data-mobile="1"] .solo-movil .material-symbols-rounded { font-size: 24px; }
html[data-mobile="1"] .crumb-back,
html[data-mobile="1"] .topbar-more { width: 44px; height: 44px; }
html[data-mobile="1"] .migas__miga { min-height: 44px; }

/* La barra de abajo. */
html[data-mobile="1"] .tools,
html[data-mobile="1"] .tools.rail-closed {
  display: flex;
  position: fixed;
  top: auto; left: 0; right: 0; bottom: 0;
  max-height: none;
  flex-direction: row;
  justify-content: space-around;
  align-items: flex-start;
  gap: 2px;
  padding: 8px max(6px, env(safe-area-inset-right)) calc(10px + env(safe-area-inset-bottom)) max(6px, env(safe-area-inset-left));
  border: none;
  border-top: 1.5px solid var(--line);
  border-radius: 0;
  background: var(--paper);
  box-shadow: 0 -4px 14px rgba(0, 0, 0, 0.06);
  overflow: visible;
  z-index: 110;
}
html[data-mobile="1"] .tools > .tool:not([data-tool="note"]):not([data-tool="todo"]):not([data-tool="image"]):not([data-tool="draw"]):not(.mas-boton),
html[data-mobile="1"] .tools > .tool-divider { display: none; }
html[data-mobile="1"] .tools .tool { flex: 1 1 0; max-width: 84px; min-height: 44px; padding: 2px 0; gap: 4px; }
html[data-mobile="1"] .tools .tool .tool-icon { width: 48px; height: 48px; border-radius: 12px; }
html[data-mobile="1"] .tools .tool .material-symbols-rounded { font-size: 24px; }
html[data-mobile="1"] .tools .tool .tool-label { display: block; font-size: 11.5px; }
/* «Más», oscuro: es la puerta a todo lo demás, no un nodo. */
html[data-mobile="1"] .tools .mas-boton .tool-icon { background: #1A1A1A !important; color: #FFFFFF !important; }
html[data-mobile="1"] .tools-fab { display: none !important; }
/* Con un nodo elegido, su barra ocupa este sitio. */
html[data-mobile="1"] body:has(.ctx-side) .tools { display: none; }

/* La barra del nodo elegido: la fila de abajo, de lado a lado. --teclado lo
   pone touch.js: con el teclado abierto, la barra se queda encima de él
   (formato encima del teclado, como en Notas). */
html[data-mobile="1"] .ctx-side,
html[data-mobile="1"] .ctx-side.text-format,
html[data-mobile="1"] .ctx-side.ctx-side-day,
html[data-mobile="1"][data-orient="landscape"] .ctx-side,
html[data-mobile="1"][data-orient="landscape"] .ctx-side.text-format,
html[data-mobile="1"][data-orient="landscape"] .ctx-side.ctx-side-day {
  left: 0; right: 0;
  bottom: var(--teclado, 0px);
  padding: 8px max(8px, env(safe-area-inset-right)) calc(8px + env(safe-area-inset-bottom)) max(8px, env(safe-area-inset-left));
  border: none;
  border-top: 1.5px solid var(--line);
  border-radius: 0;
  box-shadow: 0 -4px 14px rgba(0, 0, 0, 0.06);
  gap: 6px;
}
html[data-mobile="1"] .ctx-side .ctx-btn { min-width: 56px; min-height: 52px; }
html[data-mobile="1"] .ctx-side .ctx-close { width: 44px; height: 44px; }
html[data-mobile="1"][data-orient="portrait"] .ctx-popout {
  left: max(8px, env(safe-area-inset-left));
  right: max(8px, env(safe-area-inset-right));
  bottom: calc(84px + var(--teclado, 0px) + env(safe-area-inset-bottom));
}
/* Mientras se dibuja, la barra se aparta (como la de Marcación de Apple). */
html[data-mobile="1"].pintando .ctx-side { opacity: 0.15; pointer-events: none; transition: opacity 160ms; }

/* La fila de encima: zoom a la izquierda, fondo y plantillas detrás, y las
   conexiones a la derecha. El resto de la barra de estado (guardado, cuántos
   nodos) no cabe en un teléfono y no se echa de menos. */
html[data-mobile="1"] .zoom-ctrls { bottom: calc(96px + env(safe-area-inset-bottom)); }
html[data-mobile="1"] .canvas-bg-selector { left: 68px !important; bottom: calc(99px + env(safe-area-inset-bottom)) !important; }
html[data-mobile="1"] .plantillas-esquina { left: 108px !important; bottom: calc(96px + env(safe-area-inset-bottom)) !important; }
html[data-mobile="1"] .plantillas-panel { bottom: calc(148px + env(safe-area-inset-bottom)); }
html[data-mobile="1"] .status-bar {
  left: auto;
  right: max(8px, env(safe-area-inset-right));
  bottom: calc(96px + env(safe-area-inset-bottom));
}
html[data-mobile="1"] .status-bar > *:not(.odi-graph-btn) { display: none; }
html[data-mobile="1"] .status-bar .odi-graph-btn { pointer-events: auto; min-height: 36px; }
html[data-mobile="1"] .place-hint { bottom: calc(150px + env(safe-area-inset-bottom)); right: 8px; }

/* En horizontal falta alto: la barra de abajo sin nombres y más baja. */
html[data-mobile="1"][data-orient="landscape"] .tools .tool .tool-label { display: none; }
html[data-mobile="1"][data-orient="landscape"] .tools { top: auto; bottom: 0; padding-top: 6px; padding-bottom: calc(6px + env(safe-area-inset-bottom)); }
html[data-mobile="1"][data-orient="landscape"] .tools .tool .tool-icon { width: 44px; height: 44px; }
html[data-mobile="1"][data-orient="landscape"] .zoom-ctrls,
html[data-mobile="1"][data-orient="landscape"] .status-bar { bottom: calc(66px + env(safe-area-inset-bottom)); }
html[data-mobile="1"][data-orient="landscape"] .canvas-bg-selector { left: 68px !important; bottom: calc(69px + env(safe-area-inset-bottom)) !important; }
html[data-mobile="1"][data-orient="landscape"] .status-bar { right: max(8px, env(safe-area-inset-right)); }
html[data-mobile="1"][data-orient="landscape"] .plantillas-esquina { bottom: calc(66px + env(safe-area-inset-bottom)) !important; }

/* La hoja «Añadir» (Topbar.jsx, HojaNodos). */
.hoja-nodos-fondo {
  position: fixed; inset: 0; z-index: 500;
  display: flex; align-items: flex-end;
  background: rgba(20, 18, 26, 0.38);
  animation: hoja-fondo 180ms ease-out;
}
.hoja-nodos {
  width: 100%; max-height: 82dvh;
  display: flex; flex-direction: column;
  background: var(--paper);
  border-top: 1.5px solid var(--line);
  border-radius: 18px 18px 0 0;
  box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.2);
  padding-bottom: env(safe-area-inset-bottom);
  animation: hoja-sube 280ms var(--muelle, cubic-bezier(0.34, 1.4, 0.64, 1));
  transition: transform 200ms var(--e-out);
}
.hoja-tirador { display: flex; justify-content: center; padding: 10px 0 6px; touch-action: none; cursor: grab; }
.hoja-tirador span { width: 40px; height: 5px; border-radius: 3px; background: var(--line-soft); }
.hoja-nodos-cabeza { display: flex; align-items: center; gap: 10px; padding: 0 14px 8px 18px; }
.hoja-nodos-cabeza b { flex: 1; font-family: var(--font-display); font-weight: 800; font-size: 19px; }
.hoja-cerrar {
  width: 44px; height: 44px; flex: 0 0 auto; display: grid; place-items: center;
  border: 1.5px solid var(--line); border-radius: 22px; background: var(--paper); color: var(--ink);
}
.hoja-cerrar .material-symbols-rounded { font-size: 22px; }
.hoja-nodos-cuerpo { overflow-y: auto; overscroll-behavior: contain; padding: 4px 14px 18px; display: flex; flex-direction: column; gap: 16px; }
.hoja-nodos-nombre { margin: 0 0 8px 4px; font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); }
.hoja-nodos-rejilla { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px 6px; }
.hoja-nodo {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  min-height: 78px; padding: 4px 0;
  border: none; background: none; color: var(--ink);
}
.hoja-nodo-icono {
  width: 52px; height: 52px; display: grid; place-items: center;
  border: 1.5px solid var(--line); border-radius: 14px; box-shadow: var(--pop-sm);
  background: var(--icono-bg, var(--paper)); color: var(--icono-fg, var(--ink));
}
.hoja-nodo-icono .material-symbols-rounded { font-size: 25px; }
.hoja-nodo-nombre { font-size: 12px; font-weight: 700; text-align: center; line-height: 1.15; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.hoja-nodo.active .hoja-nodo-icono { outline: 2.5px solid var(--olive); outline-offset: 2px; }
[data-theme="dark"] .hoja-nodos { background: #2F2D2F; }
[data-theme="dark"] .hoja-cerrar { background: #3A383A; }
@keyframes hoja-sube { from { transform: translateY(100%); } to { transform: none; } }
@keyframes hoja-fondo { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .hoja-nodos, .hoja-nodos-fondo { animation: none; }
}

/* ==========================================================================
   Ventana estrecha: los botones de la derecha, al panel «⋯»
   ==========================================================================
   De 860 a 1100 px (por debajo ya es el modo teléfono) los trece botones de
   la derecha dejaban a la barra de nodos con nodo y medio a la vista. Aquí van
   al mismo panel «⋯» que en el teléfono (estas reglas son copia de las suyas,
   con otro selector). Solo con la barra de nodos arriba: a un lado o abajo,
   la barra de arriba tiene sitio de sobra. */
@media (max-width: 1100px) {
  html:not([data-mobile="1"]):not([data-barra]) .topbar-more {
    display: grid; place-items: center;
    flex: 0 0 auto;
    width: 38px; height: 38px;
    border-radius: 10px;
    border: 1.5px solid var(--line);
    background: var(--paper);
    color: var(--ink);
    box-shadow: var(--pop-sm);
  }
  html:not([data-mobile="1"]):not([data-barra]) .topbar-more .material-symbols-rounded { font-size: 21px; }

  html:not([data-mobile="1"]):not([data-barra]) .topbar-tail { display: none; }
  html:not([data-mobile="1"]):not([data-barra]) .topbar-tail.open {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
    position: fixed;
    top: calc(var(--alto-topbar, 54px) + 6px);
    right: 6px;
    left: auto;
    width: min(320px, calc(100vw - 12px));
    max-height: calc(100dvh - var(--alto-topbar, 54px) - 18px);
    overflow-y: auto;
    padding: 12px;
    background: var(--paper);
    border: 1.5px solid var(--line);
    border-radius: 14px;
    box-shadow: var(--pop-deep);
    z-index: 320;
    animation: scale-in 140ms var(--e-out);
  }
  html:not([data-mobile="1"]):not([data-barra]) .topbar-tail.open > .topbar-spacer {
    flex: 0 0 auto !important;
    justify-content: flex-start !important;
    gap: 10px;
  }
  html:not([data-mobile="1"]):not([data-barra]) .topbar-tail.open .topbar-actions {
    flex-wrap: wrap;
    gap: 10px;
  }
  /* Dentro del panel sí hay sitio: devolvemos el texto a Feedback y Apoyar */
  html:not([data-mobile="1"]):not([data-barra]) .topbar-tail.open .feedback-topbar-btn,
  html:not([data-mobile="1"]):not([data-barra]) .topbar-tail.open .kofi-topbar-btn {
    width: auto; height: 38px;
    padding: 0 14px;
    border-radius: 10px;
  }
  html:not([data-mobile="1"]):not([data-barra]) .topbar-tail.open .feedback-topbar-btn span:not(.material-symbols-rounded),
  html:not([data-mobile="1"]):not([data-barra]) .topbar-tail.open .kofi-topbar-btn span:not(.material-symbols-rounded) {
    display: inline;
  }
  html:not([data-mobile="1"]):not([data-barra]) .topbar-tail.open .icon-btn { width: 44px; height: 44px; }
  /* En el movil el deslizador no puede depender del raton: no hay raton. Aqui se
     deshace lo flotante y vuelve a ir en linea, dentro del cajon que se abre con
     el boton de los tres puntos. */
  html:not([data-mobile="1"]):not([data-barra]) .volume-ctrl {
    position: static;
    display: flex;
    align-items: center;
    gap: 6px;
    width: auto;
    height: auto;
    padding: 0 10px 0 0;
  }
  html:not([data-mobile="1"]):not([data-barra]) .volume-ctrl::after { display: none; }
  html:not([data-mobile="1"]):not([data-barra]) .volume-ctrl .icon-btn-mute { width: 44px; height: 44px; }
  html:not([data-mobile="1"]):not([data-barra]) .topbar-tail.open .volume-slider {
    position: static;
    display: block;
    width: 90px;
    height: 4px;
    padding: 0;
    margin: 0;
    background: var(--line-soft);
    border: none;
    border-radius: 99px;
    box-shadow: none;
    opacity: 1;
    visibility: visible;
    transform: none;
  }
  html:not([data-mobile="1"]):not([data-barra]) .volume-slider::-webkit-slider-runnable-track { background: transparent; }
  html:not([data-mobile="1"]):not([data-barra]) .volume-slider::-webkit-slider-thumb { margin-top: 0; }
  html:not([data-mobile="1"]):not([data-barra]) .topbar-more + .topbar-tail-scrim,
  html:not([data-mobile="1"]):not([data-barra]) .topbar-tail-scrim { display: block; position: fixed; inset: 0; z-index: 310; }
  html:not([data-mobile="1"]):not([data-barra]) .topbar-more { width: 38px; height: 38px; margin-left: 6px; }
}
