/* ============================================================================
   Anime Studio - main.css
   Reset moderno + tipografia base + libreria de CONTROLES COMUNES.

   Todo lo que hay aqui es reutilizable por cualquier pantalla (editor y home)
   y por cualquier panel. Los modulos de UI (menubar.js, layersPanel.js,
   colorPanel.js, timelineUI.js, dialogs.js, contextmenu.js, home.js...)
   deben construir su DOM con estas clases en lugar de inventar estilos.

   Indice:
     1.  Reset y base
     2.  Scrollbars
     3.  Iconos SVG
     4.  Foco accesible
     5.  .btn y variantes
     6.  .field / .input / .select / textarea
     7.  .checkbox / .switch
     8.  .slider (input[type=range] en WebKit/Blink, Gecko y Trident)
     9.  .seg (segmented control)
     10. .chip / .badge / .divider
     11. .panel / .panel-head / .panel-body (plegable)
     12. .tooltip
     13. .toast
     14. .dialog
     15. .menu / .menu-item / .menu-sep / submenus
     16. .spinner / .progress
     17. .empty-state
     18. Utilidades
     19. Puntero grueso y movimiento reducido
     20. Lienzo del editor (#canvas-host)
   ========================================================================== */

/* ---------------------------------------------------------------------------
   1. RESET Y BASE
   ------------------------------------------------------------------------ */
*,
*::before,
*::after {
  box-sizing: border-box;
}

* {
  margin: 0;
  padding: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
  font-size: calc(100% * var(--ui-scale, 1));
}

body {
  min-height: 100%;
  background: var(--s-0);
  color: var(--fg);
  font-family: var(--font-ui);
  font-size: var(--fs-md);
  line-height: var(--lh-normal);
  font-weight: var(--fw-regular);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overscroll-behavior: none;
}

img,
svg,
video {
  display: block;
  max-width: 100%;
}

/* El lienzo queda FUERA de ese reset a proposito: el renderer (§16) fija su
   bitmap por atributo y su tamano CSS en pixeles exactos del host. Un
   max-width:100% solo recortaria el ancho -la altura la sigue fijando el
   renderer- y el dibujo saldria deformado en cuanto #canvas-host tuviera
   borde o relleno. */
canvas {
  display: block;
}

img,
video {
  height: auto;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  border-radius: 0;
}

button {
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

button:disabled,
input:disabled,
select:disabled,
textarea:disabled {
  cursor: not-allowed;
}

a {
  color: var(--accent);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

ul,
ol {
  list-style: none;
}

table {
  border-collapse: collapse;
  border-spacing: 0;
}

h1, h2, h3, h4, h5, h6 {
  font-weight: var(--fw-semibold);
  line-height: var(--lh-tight);
  font-size: inherit;
}

hr {
  border: 0;
  border-top: 1px solid var(--bd);
}

code,
kbd,
samp,
pre,
.mono {
  font-family: var(--font-mono);
  font-size: 0.92em;
  font-variant-numeric: tabular-nums;
}

kbd {
  display: inline-block;
  min-width: 18px;
  padding: 1px var(--sp-2);
  background: var(--s-3);
  border: 1px solid var(--bd);
  border-bottom-width: 2px;
  border-radius: var(--r-sm);
  color: var(--fg-dim);
  font-size: var(--fs-xs);
  line-height: 1.4;
  text-align: center;
  white-space: nowrap;
}

[hidden] {
  display: none !important;
}

::selection {
  background: var(--accent-soft-hover);
  color: var(--fg);
}

/* ---------------------------------------------------------------------------
   2. SCROLLBARS (WebKit/Blink + Gecko)
   ------------------------------------------------------------------------ */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--sb-thumb) var(--sb-track);
}

*::-webkit-scrollbar {
  width: var(--sb-size);
  height: var(--sb-size);
}

*::-webkit-scrollbar-track {
  background: var(--sb-track);
}

*::-webkit-scrollbar-thumb {
  background: var(--sb-thumb);
  border: 2px solid transparent;
  background-clip: padding-box;
  border-radius: var(--r-full);
}

*::-webkit-scrollbar-thumb:hover {
  background: var(--sb-thumb-hover);
  background-clip: padding-box;
}

*::-webkit-scrollbar-corner {
  background: transparent;
}

/* ---------------------------------------------------------------------------
   3. ICONOS SVG
   Los iconos estaticos usan el sprite `<use href="#i-xxx">` inyectado en el
   HTML. `ui/icons.js` puede sustituirlos, pero el marcado ya es valido solo.
   ------------------------------------------------------------------------ */
.icon {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: none;
}

.icon-xs { width: 12px; height: 12px; stroke-width: 1.8; }
.icon-sm { width: 15px; height: 15px; stroke-width: 1.7; }
.icon-lg { width: 22px; height: 22px; stroke-width: 1.5; }
.icon-xl { width: 28px; height: 28px; stroke-width: 1.4; }

/* Iconos macizos (play, pause, primer/ultimo frame...). */
.icon-fill {
  fill: currentColor;
  stroke: none;
}

.icon-sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* ---------------------------------------------------------------------------
   4. FOCO ACCESIBLE
   Anillo visible solo con teclado; nunca se elimina el indicador.
   ------------------------------------------------------------------------ */
:focus {
  outline: none;
}

:focus-visible {
  outline: var(--focus-w) solid var(--accent-ring);
  outline-offset: 1px;
  border-radius: var(--r-sm);
}

.input:focus-visible,
.select:focus-visible,
.textarea:focus-visible {
  outline-offset: -1px;
}

/* ---------------------------------------------------------------------------
   5. BOTONES
   ------------------------------------------------------------------------ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
  height: var(--ctrl-h-cur);
  min-width: var(--ctrl-h-cur);
  padding: 0 var(--ctrl-px);
  background: var(--s-3);
  color: var(--fg);
  /* Sin marco visible: el relleno ya dice que es un control. Un borde por
     boton, en una barra con veinte, es ruido puro. Se conserva el borde
     TRANSPARENTE para que el ancho no salte al aparecer en hover o foco. */
  border: 1px solid transparent;
  border-radius: var(--r-md);
  font-size: var(--fs-md);
  font-weight: var(--fw-medium);
  line-height: 1;
  white-space: nowrap;
  user-select: none;
  -webkit-user-select: none;
  transition: background var(--t-fast), border-color var(--t-fast),
              color var(--t-fast), box-shadow var(--t-fast);
}

.btn:hover:not(:disabled):not([aria-disabled="true"]) {
  background: var(--s-4);
  border-color: var(--bd-strong);
}

.btn:active:not(:disabled):not([aria-disabled="true"]) {
  background: var(--s-2);
  border-color: var(--bd-strong);
}

.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: var(--op-disabled);
  pointer-events: none;
}

.btn-sm {
  height: var(--ctrl-h-sm-cur);
  min-width: var(--ctrl-h-sm-cur);
  padding: 0 var(--sp-4);
  font-size: var(--fs-sm);
}

.btn-lg {
  height: var(--ctrl-h-lg);
  padding: 0 var(--sp-6);
  font-size: var(--fs-lg);
}

.btn-block {
  display: flex;
  width: 100%;
}

/* Fantasma: sin relleno hasta que se interactua. */
.btn-ghost {
  background: transparent;
  border-color: transparent;
  color: var(--fg-dim);
}

.btn-ghost:hover:not(:disabled):not([aria-disabled="true"]) {
  background: var(--s-3);
  border-color: transparent;
  color: var(--fg);
}

.btn-ghost:active:not(:disabled):not([aria-disabled="true"]) {
  background: var(--s-4);
}

/* Primario. */
.btn-primary {
  /* Unico sitio donde se usa el degradado de marca en un control: la accion
     principal de la pantalla. Si lo llevaran varios, dejaria de guiar. */
  background: var(--accent-grad);
  border-color: transparent;
  color: var(--accent-fg);
  font-weight: var(--fw-semibold);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}

.btn-primary:hover:not(:disabled):not([aria-disabled="true"]) {
  background: var(--accent-grad);
  border-color: transparent;
  filter: brightness(1.1);
}

.btn-primary:active:not(:disabled):not([aria-disabled="true"]) {
  background: var(--accent-active);
  border-color: var(--accent-active);
}

/* Destructivo. */
.btn-danger {
  background: var(--err);
  border-color: var(--err);
  color: #fff;
  font-weight: var(--fw-semibold);
}

.btn-danger:hover:not(:disabled):not([aria-disabled="true"]) {
  filter: brightness(1.12);
  border-color: var(--err);
}

.btn-danger:active:not(:disabled):not([aria-disabled="true"]) {
  filter: brightness(0.9);
}

.btn-danger-ghost {
  background: transparent;
  border-color: transparent;
  color: var(--err);
}

.btn-danger-ghost:hover:not(:disabled):not([aria-disabled="true"]) {
  background: var(--err-soft);
  color: var(--err);
}

/* Solo icono: cuadrado. */
.btn-icon {
  width: var(--ctrl-h-cur);
  padding: 0;
  gap: 0;
}

.btn-icon.btn-sm {
  width: var(--ctrl-h-sm-cur);
}

.btn-icon.btn-lg {
  width: var(--ctrl-h-lg);
}

/* Estado activo / conmutado (herramienta seleccionada, toggle encendido). */
.btn.is-active,
.btn[aria-pressed="true"],
.btn[aria-checked="true"],
.btn[aria-expanded="true"] {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent-ring);
}

.btn.is-active:hover,
.btn[aria-pressed="true"]:hover {
  background: var(--accent-soft-hover);
}

.btn-ghost[aria-expanded="true"] {
  border-color: transparent;
}

/* Grupo de botones pegados. */
.btn-group {
  display: inline-flex;
  align-items: center;
}

.btn-group > .btn {
  border-radius: 0;
  margin-left: -1px;
}

.btn-group > .btn:first-child {
  border-radius: var(--r-md) 0 0 var(--r-md);
  margin-left: 0;
}

.btn-group > .btn:last-child {
  border-radius: 0 var(--r-md) var(--r-md) 0;
}

.btn-group > .btn:only-child {
  border-radius: var(--r-md);
}

.btn-group > .btn:hover,
.btn-group > .btn.is-active {
  position: relative;
  z-index: 1;
}

/* ---------------------------------------------------------------------------
   6. CAMPOS DE FORMULARIO
   ------------------------------------------------------------------------ */
.field {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  min-width: 0;
}

.field-row {
  flex-direction: row;
  align-items: center;
  gap: var(--sp-4);
}

.field-row > .field-label {
  flex: 0 0 auto;
  width: 88px;
}

.field-row > .input,
.field-row > .select,
.field-row > .slider {
  flex: 1 1 auto;
  min-width: 0;
}

.field-label {
  color: var(--fg-dim);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  line-height: 1.3;
  user-select: none;
  -webkit-user-select: none;
}

.field-hint {
  color: var(--fg-mute);
  font-size: var(--fs-xs);
  line-height: 1.35;
}

.field-error {
  color: var(--err);
  font-size: var(--fs-xs);
}

.field.is-invalid .input,
.field.is-invalid .select {
  border-color: var(--err);
}

.input,
.textarea,
.select {
  display: block;
  width: 100%;
  height: var(--ctrl-h-cur);
  padding: 0 var(--sp-4);
  background: var(--s-0);
  color: var(--fg);
  border: 1px solid var(--bd);
  border-radius: var(--r-md);
  font-size: var(--fs-md);
  transition: border-color var(--t-fast), background var(--t-fast);
}

.input::placeholder,
.textarea::placeholder {
  color: var(--fg-mute);
}

.input:hover:not(:disabled),
.textarea:hover:not(:disabled),
.select:hover:not(:disabled) {
  border-color: var(--bd-strong);
}

.input:focus,
.textarea:focus,
.select:focus {
  border-color: var(--accent);
  background: var(--s-0);
}

.input:disabled,
.textarea:disabled,
.select:disabled {
  opacity: var(--op-disabled);
}

.input[type="number"] {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  text-align: right;
  padding-right: var(--sp-3);
}

.input-sm {
  height: var(--ctrl-h-sm-cur);
  padding: 0 var(--sp-3);
  font-size: var(--fs-sm);
}

.textarea {
  height: auto;
  min-height: calc(var(--ctrl-h-cur) * 2.5);
  padding: var(--sp-3) var(--sp-4);
  line-height: var(--lh-normal);
  resize: vertical;
}

/* Campo de busqueda con icono a la izquierda. */
.input-search {
  position: relative;
  display: flex;
  align-items: center;
  min-width: 0;
}

.input-search > .icon {
  position: absolute;
  left: var(--sp-4);
  color: var(--fg-mute);
}

.input-search > .input {
  padding-left: calc(var(--sp-4) * 2 + 18px);
}

/* Select nativo con flecha propia (SVG embebido, sin recursos externos). */
.select {
  padding-right: 26px;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a3aebd' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--sp-3) center;
  background-size: 14px 14px;
  cursor: pointer;
}

.select::-ms-expand {
  display: none;
}

.select option {
  background: var(--s-2);
  color: var(--fg);
}

/* ---------------------------------------------------------------------------
   7. CHECKBOX Y SWITCH
   ------------------------------------------------------------------------ */
.checkbox {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-4);
  min-height: var(--ctrl-h-sm-cur);
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  font-size: var(--fs-md);
  color: var(--fg-dim);
}

.checkbox input[type="checkbox"],
.checkbox input[type="radio"] {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  margin: 0;
  background: var(--s-0);
  border: 1px solid var(--bd-strong);
  border-radius: var(--r-sm);
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  cursor: pointer;
  transition: background var(--t-fast), border-color var(--t-fast);
}

.checkbox input[type="radio"] {
  border-radius: var(--r-full);
}

.checkbox input[type="checkbox"]:checked {
  background: var(--accent);
  border-color: var(--accent);
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12.5 4.5 4.5L19 7'/%3E%3C/svg%3E");
  background-size: 12px 12px;
  background-position: center;
  background-repeat: no-repeat;
}

.checkbox input[type="radio"]:checked {
  border-color: var(--accent);
  background: radial-gradient(circle at center, var(--accent) 0 4px, transparent 4.5px);
}

.checkbox input:hover:not(:disabled) {
  border-color: var(--accent);
}

.checkbox:has(input:checked) {
  color: var(--fg);
}

.checkbox input:disabled {
  opacity: var(--op-disabled);
  cursor: not-allowed;
}

.switch {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-4);
  min-height: var(--ctrl-h-sm-cur);
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  font-size: var(--fs-md);
  color: var(--fg-dim);
}

.switch input[type="checkbox"] {
  position: relative;
  flex: 0 0 auto;
  width: 34px;
  height: 18px;
  margin: 0;
  background: var(--s-4);
  border: 1px solid var(--bd-strong);
  border-radius: var(--r-full);
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  cursor: pointer;
  transition: background var(--t-fast), border-color var(--t-fast);
}

.switch input[type="checkbox"]::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 12px;
  height: 12px;
  background: var(--fg-dim);
  border-radius: var(--r-full);
  transition: transform var(--t-fast), background var(--t-fast);
}

.switch input[type="checkbox"]:checked {
  background: var(--accent);
  border-color: var(--accent);
}

.switch input[type="checkbox"]:checked::after {
  background: #fff;
  transform: translateX(16px);
}

.switch:has(input:checked) {
  color: var(--fg);
}

.switch input:disabled {
  opacity: var(--op-disabled);
  cursor: not-allowed;
}

/* ---------------------------------------------------------------------------
   8. SLIDER  (input[type=range] estilizado en los tres motores)
   ------------------------------------------------------------------------ */
.slider {
  display: block;
  width: 100%;
  height: 18px;
  margin: 0;
  padding: 0;
  background: transparent;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  cursor: pointer;
  touch-action: pan-y;
}

/* -- WebKit / Blink -- */
.slider::-webkit-slider-runnable-track {
  height: 4px;
  background: var(--s-4);
  border: none;
  border-radius: var(--r-full);
}

.slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 14px;
  height: 14px;
  margin-top: -5px;
  background: var(--fg);
  border: 2px solid var(--s-1);
  border-radius: var(--r-full);
  box-shadow: var(--sh-1);
  transition: background var(--t-fast), transform var(--t-fast);
}

.slider:hover::-webkit-slider-thumb {
  background: var(--accent-ring);
}

.slider:active::-webkit-slider-thumb {
  transform: scale(1.12);
  background: var(--accent);
}

.slider:disabled::-webkit-slider-thumb {
  background: var(--fg-mute);
}

/* -- Gecko -- */
.slider::-moz-range-track {
  height: 4px;
  background: var(--s-4);
  border: none;
  border-radius: var(--r-full);
}

.slider::-moz-range-progress {
  height: 4px;
  background: var(--accent);
  border-radius: var(--r-full);
}

.slider::-moz-range-thumb {
  width: 12px;
  height: 12px;
  background: var(--fg);
  border: 2px solid var(--s-1);
  border-radius: var(--r-full);
  box-shadow: var(--sh-1);
  transition: background var(--t-fast);
}

.slider:hover::-moz-range-thumb {
  background: var(--accent-ring);
}

.slider:active::-moz-range-thumb {
  background: var(--accent);
}

.slider:disabled::-moz-range-thumb {
  background: var(--fg-mute);
}

/* -- Trident / EdgeHTML -- */
.slider::-ms-track {
  height: 4px;
  background: transparent;
  border-color: transparent;
  color: transparent;
}

.slider::-ms-fill-lower {
  background: var(--accent);
  border-radius: var(--r-full);
}

.slider::-ms-fill-upper {
  background: var(--s-4);
  border-radius: var(--r-full);
}

.slider::-ms-thumb {
  width: 12px;
  height: 12px;
  margin-top: 0;
  background: var(--fg);
  border: 2px solid var(--s-1);
  border-radius: var(--r-full);
}

.slider::-ms-tooltip {
  display: none;
}

.slider:disabled {
  opacity: var(--op-disabled);
  cursor: not-allowed;
}

/* Slider + valor numerico editable a la derecha. */
.slider-row {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  min-width: 0;
}

.slider-row > .slider {
  flex: 1 1 auto;
  min-width: 40px;
}

.slider-row > .slider-value {
  flex: 0 0 auto;
  width: 54px;
  height: var(--ctrl-h-sm-cur);
  padding: 0 var(--sp-3);
  background: var(--s-0);
  border: 1px solid var(--bd);
  border-radius: var(--r-sm);
  color: var(--fg);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.slider-row > .slider-value:focus {
  border-color: var(--accent);
}

/* ---------------------------------------------------------------------------
   9. SEGMENTED CONTROL
   ------------------------------------------------------------------------ */
.seg {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  height: var(--ctrl-h-cur);
  padding: 2px;
  background: var(--s-0);
  border: 1px solid var(--bd);
  border-radius: var(--r-md);
}

.seg-item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  height: 100%;
  min-width: calc(var(--ctrl-h-cur) - 6px);
  padding: 0 var(--sp-4);
  background: transparent;
  color: var(--fg-dim);
  border: 0;
  border-radius: calc(var(--r-md) - 2px);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  line-height: 1;
  white-space: nowrap;
  user-select: none;
  -webkit-user-select: none;
  transition: background var(--t-fast), color var(--t-fast);
}

.seg-item:hover:not(:disabled) {
  background: var(--s-2);
  color: var(--fg);
}

.seg-item.is-active,
.seg-item[aria-pressed="true"],
.seg-item[aria-checked="true"] {
  background: var(--s-3);
  color: var(--fg);
  box-shadow: var(--sh-1);
}

.seg-item:disabled {
  opacity: var(--op-disabled);
  cursor: not-allowed;
}

.seg-block {
  display: flex;
  width: 100%;
}

.seg-block > .seg-item {
  flex: 1 1 0;
}

/* ---------------------------------------------------------------------------
   10. CHIP / BADGE / DIVIDER
   ------------------------------------------------------------------------ */
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  height: 22px;
  padding: 0 var(--sp-4);
  background: var(--s-3);
  color: var(--fg-dim);
  border: 1px solid var(--bd);
  border-radius: var(--r-full);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  line-height: 1;
  white-space: nowrap;
  user-select: none;
  -webkit-user-select: none;
}

button.chip {
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}

button.chip:hover:not(:disabled) {
  background: var(--s-4);
  color: var(--fg);
}

.chip.is-active,
.chip[aria-pressed="true"] {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent-ring);
}

.chip-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  margin-right: -3px;
  border-radius: var(--r-full);
  color: var(--fg-mute);
}

.chip-close:hover {
  background: var(--s-hi);
  color: var(--fg);
}

.badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 16px;
  height: 16px;
  padding: 0 5px;
  background: var(--s-4);
  color: var(--fg-dim);
  border-radius: var(--r-full);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  white-space: nowrap;
}

.badge-accent { background: var(--accent); color: var(--accent-fg); }
.badge-ok     { background: var(--ok);     color: #04150e; }
.badge-warn   { background: var(--warn);   color: #1a1200; }
.badge-err    { background: var(--err);    color: #fff; }
.badge-dot {
  min-width: 8px;
  width: 8px;
  height: 8px;
  padding: 0;
}

.divider {
  height: 1px;
  margin: var(--sp-3) 0;
  background: var(--bd);
  border: 0;
  flex: 0 0 auto;
}

.divider-v {
  width: 1px;
  height: 60%;
  min-height: 16px;
  margin: 0 var(--sp-3);
  background: var(--bd);
  align-self: center;
  flex: 0 0 auto;
}

.divider-label {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  margin: var(--sp-4) 0;
  color: var(--fg-mute);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  user-select: none;
  -webkit-user-select: none;
}

.divider-label::before,
.divider-label::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: var(--bd);
}

/* ---------------------------------------------------------------------------
   11. PANEL PLEGABLE
   Marcado esperado:
     <section class="panel" id="panel-x" data-collapsed="false">
       <header class="panel-head">
         <button class="panel-toggle" aria-expanded="true">...</button>
         <div class="panel-actions">...</div>
       </header>
       <div class="panel-body">...</div>
     </section>
   ------------------------------------------------------------------------ */
.panel {
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--s-1);
  border-bottom: 1px solid var(--bd-soft);
}

.panel:last-child {
  border-bottom: 0;
}

.panel-head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  height: 30px;
  padding-right: var(--sp-2);
  /* Sin fondo ni linea propios: la cabecera pertenece al panel, no es una
     barra aparte. La jerarquia la da el rotulo en versalitas. */
  background: transparent;
  border-bottom: 0;
  flex: 0 0 auto;
  user-select: none;
  -webkit-user-select: none;
}

.panel-toggle {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
  padding: 0 var(--sp-4);
  background: none;
  color: var(--fg-dim);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  text-align: left;
  transition: color var(--t-fast);
}

.panel-toggle:hover {
  color: var(--fg);
}

.panel-toggle .panel-chevron {
  width: 12px;
  height: 12px;
  flex: 0 0 auto;
  color: var(--fg-mute);
  transition: transform var(--t-fast);
}

.panel-toggle .panel-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.panel-actions {
  display: flex;
  align-items: center;
  gap: 1px;
  flex: 0 0 auto;
}

.panel-body {
  flex: 1 1 auto;
  min-height: 0;
  padding: var(--sp-5);
  overflow: auto;
}

.panel-body-flush {
  padding: 0;
}

/* Estado plegado: soportamos los tres hooks habituales.
   OJO: la variante con :has() va en una regla APARTE a proposito. Si se mezclara
   en la misma lista de selectores, un navegador sin :has() descartaria tambien
   los selectores validos y el plegado dejaria de funcionar por completo. */
.panel[data-collapsed="true"] > .panel-body,
.panel.is-collapsed > .panel-body {
  display: none;
}

.panel:has(> .panel-head > .panel-toggle[aria-expanded="false"]) > .panel-body {
  display: none;
}

.panel[data-collapsed="true"] .panel-chevron,
.panel.is-collapsed .panel-chevron,
.panel-toggle[aria-expanded="false"] .panel-chevron {
  transform: rotate(-90deg);
}

.panel[data-collapsed="true"],
.panel.is-collapsed {
  flex: 0 0 auto;
}

/* Fila etiqueta + control usada dentro de los paneles. */
.panel-row {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  min-height: var(--ctrl-h-sm-cur);
}

.panel-row + .panel-row {
  margin-top: var(--sp-4);
}

.panel-row > .panel-row-label {
  flex: 0 0 auto;
  width: 64px;
  color: var(--fg-dim);
  font-size: var(--fs-sm);
  user-select: none;
  -webkit-user-select: none;
}

.panel-row > .grow {
  min-width: 0;
}

/* ---------------------------------------------------------------------------
   12. TOOLTIP
   Elemento posicionado por JS (`ui.js`) y colocado en position: fixed.
   ------------------------------------------------------------------------ */
.tooltip {
  position: fixed;
  z-index: var(--z-overlay);
  max-width: 260px;
  padding: var(--sp-2) var(--sp-4);
  background: var(--s-4);
  color: var(--fg);
  border: 1px solid var(--bd-strong);
  border-radius: var(--r-sm);
  box-shadow: var(--sh-2);
  font-size: var(--fs-sm);
  line-height: 1.35;
  white-space: normal;
  pointer-events: none;
  opacity: 0;
  transform: translateY(2px);
  transition: opacity var(--t-fast), transform var(--t-fast);
}

.tooltip.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.tooltip-key {
  margin-left: var(--sp-3);
  color: var(--fg-mute);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
}

/* ---------------------------------------------------------------------------
   13. TOAST
   ------------------------------------------------------------------------ */
#toast-root {
  position: fixed;
  right: var(--sp-6);
  bottom: var(--sp-6);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--sp-4);
  max-width: min(380px, calc(100vw - var(--sp-7)));
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-4);
  width: 100%;
  padding: var(--sp-4) var(--sp-5);
  background: var(--s-2);
  color: var(--fg);
  border: 1px solid var(--bd-strong);
  border-left: 3px solid var(--info);
  border-radius: var(--r-md);
  box-shadow: var(--sh-3);
  font-size: var(--fs-md);
  line-height: 1.4;
  pointer-events: auto;
  animation: toast-in 200ms var(--ease-out) both;
}

.toast.is-leaving {
  animation: toast-out 160ms var(--ease) both;
}

.toast .toast-icon {
  flex: 0 0 auto;
  margin-top: 1px;
  color: var(--info);
}

.toast .toast-message {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}

.toast .toast-close {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  margin: -2px -4px 0 0;
  border-radius: var(--r-sm);
  color: var(--fg-mute);
}

.toast .toast-close:hover {
  background: var(--s-3);
  color: var(--fg);
}

.toast-ok    { border-left-color: var(--ok); }
.toast-ok    .toast-icon { color: var(--ok); }
.toast-warn  { border-left-color: var(--warn); }
.toast-warn  .toast-icon { color: var(--warn); }
.toast-error { border-left-color: var(--err); }
.toast-error .toast-icon { color: var(--err); }
.toast-info  { border-left-color: var(--info); }
.toast-info  .toast-icon { color: var(--info); }

@keyframes toast-in {
  from { opacity: 0; transform: translateY(10px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

@keyframes toast-out {
  from { opacity: 1; transform: translateX(0); }
  to   { opacity: 0; transform: translateX(16px); }
}

/* ---------------------------------------------------------------------------
   14. DIALOGO MODAL
   Marcado esperado dentro de #dialog-root:
     <div class="dialog-backdrop">
       <div class="dialog" role="dialog" aria-modal="true">
         <header class="dialog-head">...</header>
         <div class="dialog-body">...</div>
         <footer class="dialog-foot">...</footer>
       </div>
     </div>
   ------------------------------------------------------------------------ */
#dialog-root {
  position: relative;
  z-index: var(--z-dialog);
}

.dialog-backdrop {
  position: fixed;
  inset: 0;
  z-index: var(--z-dialog);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-6);
  background: rgba(3, 6, 10, 0.62);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  animation: backdrop-in 160ms var(--ease) both;
}

.dialog {
  display: flex;
  flex-direction: column;
  width: min(560px, 100%);
  max-height: min(86vh, 860px);
  background: var(--s-2);
  border: 1px solid var(--bd);
  border-radius: calc(var(--r-lg) + 4px);
  box-shadow: var(--sh-3);
  overflow: hidden;
  animation: dialog-in 200ms var(--ease-out) both;
}

.dialog-sm { width: min(400px, 100%); }
.dialog-lg { width: min(760px, 100%); }
.dialog-xl { width: min(1000px, 100%); }

.dialog-head {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  flex: 0 0 auto;
  min-height: 46px;
  padding: var(--sp-4) var(--sp-5) var(--sp-4) var(--sp-6);
  background: var(--s-2);
  border-bottom: 1px solid var(--bd);
}

.dialog-title {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dialog-body {
  flex: 1 1 auto;
  min-height: 0;
  padding: var(--sp-6);
  overflow: auto;
}

.dialog-body-flush {
  padding: 0;
}

.dialog-foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sp-4);
  flex: 0 0 auto;
  padding: var(--sp-5) var(--sp-6);
  background: var(--s-1);
  border-top: 1px solid var(--bd);
}

.dialog-foot .grow {
  min-width: 0;
}

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

@keyframes dialog-in {
  from { opacity: 0; transform: translateY(12px) scale(0.985); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* ---------------------------------------------------------------------------
   14.1 DIALOGO DE FILTRO  (`ui/filterDialog.js`, contrato 47.5)

   Marcado que construye el modulo:
     <div class="dialog dialog-lg dialog-filter" data-filter-id="blur.gaussian">
       <div class="dialog-body">
         <div class="fd-preview-wrap"><canvas class="fd-preview checker"></canvas></div>
         <p class="fd-note" data-fd="note">...</p>
         <div class="divider"></div>
         <div class="opt-extra fd-params">  <- los controles del filtro
           <div class="opt opt-slider" data-param="radius">...</div>
           <div class="fd-curve" data-param="curve">...</div>
         </div>
       </div>
       <footer class="dialog-foot"><div class="fd-foot">...</div>...</footer>
     </div>

   Los controles NO llevan estilo propio: son los mismos `.opt*` de
   `#tool-options` (editor.css seccion 5), y `.opt-extra` ya los apila en columna
   con la pista estirada. Un deslizador de filtro y uno de herramienta tienen que
   ser el mismo control, y la unica forma de garantizarlo es que compartan reglas.
   ------------------------------------------------------------------------ */
.fd-preview-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-4);
  margin-bottom: var(--sp-4);
  background: var(--s-3);
  border: 1px solid var(--bd);
  border-radius: var(--r-md);
}

.fd-preview {
  display: block;
  max-width: 100%;
  height: auto;
  border-radius: var(--r-sm);
  box-shadow: var(--sh-1);
}

/* Estado de la vista previa. Siempre dice algo: «a resolucion completa» o «al
   N %». Una vista previa reducida que no se anuncia es peor que no tenerla. */
.fd-note {
  margin: 0 0 var(--sp-3);
  color: var(--fg-mute);
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
}

.fd-note-warn {
  padding: var(--sp-2) var(--sp-3);
  background: var(--warn-soft);
  border-radius: var(--r-sm);
  color: var(--warn);
}

/* Columna de controles. `.opt-extra` hace el reparto; aqui solo la separacion. */
.fd-params {
  gap: var(--sp-5);
}

/* Comparar y Restablecer, a la izquierda del pie. */
.fd-foot {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  flex-wrap: wrap;
}

/* --- Editor de curva y de paradas de degradado -------------------------- */
.fd-curve {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  width: 100%;
  min-width: 0;
}

.fd-curve-head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

.fd-curve-head .opt-label {
  flex: 1 1 auto;
  min-width: 0;
}

.fd-curve-plot {
  display: flex;
  justify-content: center;
}

/* Los colores del trazado los lee el modulo con getComputedStyle: se declaran
   aqui como alias de los tokens para que un tema los pueda cambiar sin tocar
   JavaScript, y para que el canvas nunca lleve un color literal dentro. */
.fd-curve-canvas {
  --fd-curve-bg: var(--s-3);
  --fd-curve-grid: var(--bd-strong);
  --fd-curve-line: var(--accent-ring);
  --fd-curve-point: var(--fg);
  display: block;
  max-width: 100%;
  background: var(--s-3);
  border: 1px solid var(--bd);
  border-radius: var(--r-sm);
  cursor: crosshair;
}

.fd-curve-canvas:focus-visible {
  outline: var(--focus-w) solid var(--accent-ring);
  outline-offset: 2px;
}

.fd-curve-axis {
  display: flex;
  justify-content: space-between;
  color: var(--fg-mute);
  font-size: var(--fs-xs);
}

.fd-curve-tools {
  gap: var(--sp-3);
}

/* ---------------------------------------------------------------------------
   15. MENUS (barra de menu, desplegables y menu contextual)
   ------------------------------------------------------------------------ */
.menu {
  min-width: 190px;
  max-width: 340px;
  padding: var(--sp-2);
  background: var(--s-2);
  border: 1px solid var(--bd-strong);
  border-radius: var(--r-md);
  box-shadow: var(--sh-3);
  list-style: none;
  user-select: none;
  -webkit-user-select: none;
}

/* Desplegable colgando de la barra de menu.

   NO recorta por defecto, y es a proposito: `overflow-y: auto` recorta TAMBIEN en
   horizontal, porque CSS convierte `overflow-x: visible` en `auto` cuando el otro
   eje no es visible. Con el recorte puesto, un submenu colocado en `left: 100%`
   quedaba fuera de la caja de recorte: se veia al abrirlo con el teclado o con un
   clic -porque el foco desplazaba el contenedor, arrastrando el desplegable de
   lado- y NO se veia al abrirlo pasando el puntero, que es como se abre siempre.
   Ocho submenus de filtros habrian sido cincuenta y dos filtros invisibles.

   El desplazamiento vertical se pone SOLO cuando el menu de verdad no cabe en la
   ventana: lo decide `_placeDropdown()` midiendolo, y anade `.is-scrollable`. */
.menu-dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: var(--z-menu);
  display: none;
  overflow: visible;
  animation: menu-in 110ms var(--ease-out) both;
}

.menu-dropdown.is-scrollable {
  max-height: calc(100vh - var(--menubar-h) - var(--sp-6));
  overflow-y: auto;
}

.menu-dropdown.is-open,
[aria-expanded="true"] + .menu-dropdown {
  display: block;
}

.menu-item {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  width: 100%;
  min-height: 26px;
  padding: var(--sp-2) var(--sp-4);
  background: none;
  color: var(--fg);
  border: 0;
  border-radius: var(--r-sm);
  font-size: var(--fs-md);
  line-height: 1.3;
  text-align: left;
  white-space: nowrap;
}

.menu-item:hover:not(:disabled):not([aria-disabled="true"]),
.menu-item.is-active {
  background: var(--accent);
  color: var(--accent-fg);
}

/* El foco de teclado NO puede ser indistinguible del hover del raton: al
   recorrer el menu con las flechas hay que ver donde esta el foco aunque el
   puntero este parado sobre otra entrada. El contorno va hacia dentro para
   que no lo recorte el overflow del desplegable. */
.menu-item:focus-visible {
  background: var(--accent);
  color: var(--accent-fg);
  outline: var(--focus-w) solid var(--accent-ring);
  outline-offset: -2px;
}

.menu-item:hover .menu-item-key,
.menu-item.is-active .menu-item-key,
.menu-item:focus-visible .menu-item-key {
  color: rgba(255, 255, 255, 0.78);
}

.menu-item:hover .icon,
.menu-item.is-active .icon {
  color: inherit;
}

.menu-item:disabled,
.menu-item[aria-disabled="true"] {
  color: var(--fg-mute);
  pointer-events: none;
}

.menu-item .icon {
  flex: 0 0 auto;
  width: 15px;
  height: 15px;
  color: var(--fg-dim);
}

.menu-item-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.menu-item-key {
  flex: 0 0 auto;
  margin-left: var(--sp-6);
  color: var(--fg-mute);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
}

.menu-item-key:empty {
  margin-left: 0;
}

/* Marca de seleccion / conmutador dentro del menu. */
.menu-item-check {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  opacity: 0;
}

.menu-item[aria-checked="true"] .menu-item-check {
  opacity: 1;
}

.menu-sep {
  height: 1px;
  margin: var(--sp-2) var(--sp-3);
  background: var(--bd);
  list-style: none;
}

/* Submenus: se despliegan al pasar por encima o al abrir con teclado. */
.menu-item.has-submenu {
  position: relative;
  padding-right: var(--sp-3);
}

.menu-item.has-submenu > .menu-submenu-arrow {
  flex: 0 0 auto;
  width: 12px;
  height: 12px;
  margin-left: auto;
  color: var(--fg-mute);
}

.menu-item.has-submenu:hover > .menu-submenu-arrow {
  color: inherit;
}

.has-submenu-wrap {
  position: relative;
}

.menu-submenu {
  position: absolute;
  top: calc(var(--sp-2) * -1);
  left: 100%;
  z-index: 1;
  display: none;
  margin-left: 2px;
}

.has-submenu-wrap:hover > .menu-submenu,
.has-submenu-wrap:focus-within > .menu-submenu,
.menu-submenu.is-open {
  display: block;
  animation: menu-in 110ms var(--ease-out) both;
}

/* Si no cabe a la derecha, el modulo anade .to-left. */
.menu-submenu.to-left {
  left: auto;
  right: 100%;
  margin-left: 0;
  margin-right: 2px;
}

#context-menu-root {
  position: fixed;
  inset: 0;
  z-index: var(--z-menu);
  pointer-events: none;
}

#context-menu-root:empty {
  display: none;
}

#context-menu-root > .menu {
  position: absolute;
  pointer-events: auto;
  animation: menu-in 110ms var(--ease-out) both;
}

@keyframes menu-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---------------------------------------------------------------------------
   16. SPINNER Y PROGRESO
   ------------------------------------------------------------------------ */
.spinner {
  display: inline-block;
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  border: 2px solid var(--s-4);
  border-top-color: var(--accent);
  border-radius: var(--r-full);
  animation: spin 700ms linear infinite;
}

.spinner-sm { width: 12px; height: 12px; border-width: 1.5px; }
.spinner-lg { width: 30px; height: 30px; border-width: 3px; }

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

.progress {
  position: relative;
  width: 100%;
  height: 6px;
  background: var(--s-0);
  border: 1px solid var(--bd);
  border-radius: var(--r-full);
  overflow: hidden;
}

.progress-bar {
  width: 0;
  height: 100%;
  background: var(--accent);
  border-radius: inherit;
  transition: width var(--t-med);
}

.progress-ok .progress-bar   { background: var(--ok); }
.progress-warn .progress-bar { background: var(--warn); }
.progress-err .progress-bar  { background: var(--err); }

.progress.is-indeterminate .progress-bar {
  width: 35%;
  animation: progress-slide 1100ms var(--ease) infinite;
}

@keyframes progress-slide {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(300%); }
}

.progress-label {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-bottom: var(--sp-3);
  color: var(--fg-dim);
  font-size: var(--fs-sm);
}

.progress-label .progress-value {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--fg);
}

/* ---------------------------------------------------------------------------
   17. ESTADO VACIO
   ------------------------------------------------------------------------ */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-4);
  padding: var(--sp-8) var(--sp-6);
  margin: auto;
  max-width: 440px;
  text-align: center;
  color: var(--fg-mute);
}

.empty-state .empty-icon {
  width: 42px;
  height: 42px;
  color: var(--s-hi);
  stroke-width: 1.2;
}

.empty-state .empty-title {
  color: var(--fg-dim);
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
}

.empty-state .empty-text {
  font-size: var(--fs-md);
  line-height: var(--lh-normal);
  max-width: 34ch;
}

.empty-state .empty-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--sp-4);
  margin-top: var(--sp-3);
}

/* ---------------------------------------------------------------------------
   18. UTILIDADES
   ------------------------------------------------------------------------ */
.row {
  display: flex;
  flex-direction: row;
  align-items: center;
}

.col {
  display: flex;
  flex-direction: column;
}

.wrap { flex-wrap: wrap; }
.center { align-items: center; justify-content: center; }
.between { justify-content: space-between; }
.end { justify-content: flex-end; }
.start { justify-content: flex-start; }
.items-start { align-items: flex-start; }
.items-end { align-items: flex-end; }
.items-stretch { align-items: stretch; }
.baseline { align-items: baseline; }

.gap    { gap: var(--sp-4); }
.gap-1  { gap: var(--sp-1); }
.gap-2  { gap: var(--sp-2); }
.gap-3  { gap: var(--sp-3); }
.gap-4  { gap: var(--sp-4); }
.gap-5  { gap: var(--sp-5); }
.gap-6  { gap: var(--sp-6); }
.gap-7  { gap: var(--sp-7); }

.grow { flex: 1 1 auto; min-width: 0; min-height: 0; }
.shrink-0 { flex-shrink: 0; }
.full { width: 100%; }
.full-h { height: 100%; }

.hidden { display: none !important; }

.invisible { visibility: hidden; }

.no-select {
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

.no-drag {
  -webkit-user-drag: none;
  user-drag: none;
}

.truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.scroll-y { overflow-y: auto; overflow-x: hidden; }
.scroll-x { overflow-x: auto; overflow-y: hidden; }

.text-dim  { color: var(--fg-dim); }
.text-mute { color: var(--fg-mute); }
.text-ok   { color: var(--ok); }
.text-warn { color: var(--warn); }
.text-err  { color: var(--err); }
.text-accent { color: var(--accent-ring); }

.text-xs { font-size: var(--fs-xs); }
.text-sm { font-size: var(--fs-sm); }
.text-lg { font-size: var(--fs-lg); }
.text-xl { font-size: var(--fs-xl); }

.text-center { text-align: center; }
.text-right { text-align: right; }

.uppercase {
  text-transform: uppercase;
  letter-spacing: var(--ls-wide);
}

.num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

.sr-only {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------------------------------------------------------------------------
   Enlace de salto al contenido.
   Invisible hasta que recibe el foco con el tabulador: es el primer elemento
   enfocable del documento, de modo que quien navega con teclado o lector de
   pantalla puede llegar al lienzo (o a la galeria) sin recorrer toda la barra
   de menus.
   -------------------------------------------------------------------------- */
.skip-link {
  position: absolute;
  z-index: var(--z-toast, 9000);
  top: 0;
  left: 50%;
  transform: translate(-50%, -110%);
  padding: var(--sp-2, 8px) var(--sp-4, 16px);
  border: 1px solid var(--accent, #4aa3ff);
  border-top: 0;
  border-radius: 0 0 var(--r-md, 6px) var(--r-md, 6px);
  background: var(--s-2, #1c2128);
  color: var(--fg, #e8ecf2);
  font: 500 var(--fs-sm, 13px) / 1 var(--font-ui, system-ui, sans-serif);
  text-decoration: none;
  white-space: nowrap;
  transition: transform var(--t-fast, 120ms) ease-out;
}

.skip-link:focus,
.skip-link:focus-visible {
  transform: translate(-50%, 0);
  outline: 2px solid var(--accent, #4aa3ff);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .skip-link { transition: none; }
}

/* Fondo de damero para previsualizar transparencia. */
.checker {
  background-color: var(--checker-b);
  background-image:
    linear-gradient(45deg, var(--checker-a) 25%, transparent 25%),
    linear-gradient(-45deg, var(--checker-a) 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, var(--checker-a) 75%),
    linear-gradient(-45deg, transparent 75%, var(--checker-a) 75%);
  background-size: 12px 12px;
  background-position: 0 0, 0 6px, 6px -6px, -6px 0;
}

/* Muestra de color reutilizable (paletas, capas, marcadores). */
.swatch {
  position: relative;
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
  border: 1px solid var(--bd-strong);
  border-radius: var(--r-sm);
  overflow: hidden;
  cursor: pointer;
}

.swatch::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--swatch-color, transparent);
}

.swatch.is-active {
  box-shadow: 0 0 0 2px var(--accent-ring);
}

/* ---------------------------------------------------------------------------
   19. PUNTERO GRUESO Y MOVIMIENTO REDUCIDO
   ------------------------------------------------------------------------ */
@media (pointer: coarse) {
  /* Regla global: ningun objetivo tactil por debajo de --touch-min. */
  .btn,
  .seg,
  .input,
  .select,
  .textarea {
    min-height: var(--ctrl-h-touch);
  }

  .btn-icon {
    min-width: var(--touch-min);
    width: var(--touch-min);
  }

  .btn-sm,
  .input-sm {
    min-height: var(--ctrl-h-sm-cur);
  }

  .menu-item {
    min-height: var(--touch-min);
    padding: var(--sp-3) var(--sp-5);
  }

  .checkbox input[type="checkbox"],
  .checkbox input[type="radio"] {
    width: 20px;
    height: 20px;
  }

  .switch input[type="checkbox"] {
    width: 42px;
    height: 24px;
  }

  .switch input[type="checkbox"]::after {
    width: 18px;
    height: 18px;
  }

  .switch input[type="checkbox"]:checked::after {
    transform: translateX(18px);
  }

  .slider {
    height: 28px;
  }

  .slider::-webkit-slider-thumb {
    width: 20px;
    height: 20px;
    margin-top: -8px;
  }

  .slider::-moz-range-thumb {
    width: 18px;
    height: 18px;
  }

  .slider-row > .slider-value {
    height: 32px;
    width: 60px;
  }

  .panel-head {
    height: 38px;
  }

  /* Los tooltips de hover no tienen sentido con el dedo. */
  .tooltip {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  .spinner {
    animation: spin 1.4s linear infinite !important;
  }

  .progress.is-indeterminate .progress-bar {
    width: 100%;
    animation: none !important;
    opacity: 0.5;
  }
}

/* ---------------------------------------------------------------------------
   19.b AJUSTE `animations` APAGADO

   `core/settings.js` pone los tres tokens de transicion a `0ms linear`, lo que
   frena las TRANSICIONES; las animaciones por `@keyframes` no dependen de esos
   tokens y seguian corriendo. Este bloque es lo que le da sentido al atributo
   `data-animations` que ese modulo publica en `<html>`.

   Se replica a proposito lo que hace el bloque de `prefers-reduced-motion` de
   aqui arriba, incluidas sus excepciones: un indicador de progreso quieto no
   informa de nada, asi que el spinner sigue girando (mas despacio) y la barra
   indeterminada pasa a un relleno estatico atenuado. Los esqueletos de carga y
   los dos indicadores del arranque se quedan fijos: ahi la informacion es la
   FORMA, no el movimiento.
   ------------------------------------------------------------------------ */
:root[data-animations="off"] *,
:root[data-animations="off"] *::before,
:root[data-animations="off"] *::after {
  animation-duration: 0.001ms !important;
  animation-delay: 0ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001ms !important;
  transition-delay: 0ms !important;
  scroll-behavior: auto !important;
}

:root[data-animations="off"] .spinner {
  animation: spin 1.4s linear infinite !important;
}

:root[data-animations="off"] .progress.is-indeterminate .progress-bar {
  width: 100%;
  animation: none !important;
  opacity: 0.5;
}


@media (forced-colors: active) {
  .btn,
  .input,
  .select,
  .panel,
  .menu,
  .dialog {
    border-color: ButtonBorder;
  }

  .btn.is-active,
  .btn[aria-pressed="true"] {
    forced-color-adjust: none;
    background: Highlight;
    color: HighlightText;
  }
}


/* ---------------------------------------------------------------------------
   20. LIENZO DEL EDITOR (#canvas-host)
   Estas reglas viven aqui, y no en editor.css, porque son el minimo que exige
   el §39 del contrato y sin ellas el editor no es usable: sin
   position:relative las reglas y el HUD se posicionan respecto al viewport en
   vez de respecto al host, y sin touch-action:none cada trazo con el dedo
   dispara el pan/pinch nativo del navegador (el meta viewport con
   user-scalable=no NO cubre eso: Safari iOS lo ignora desde iOS 10).
   editor.css se carga despues y puede ampliarlas.
   ------------------------------------------------------------------------ */
#canvas-host {
  position: relative;            /* origen de #ruler-*, #canvas-hud y overlays */
  overflow: hidden;
  background: var(--canvas-bg);
  touch-action: none;            /* el gesto es del InputManager, no del navegador */
  overscroll-behavior: contain;  /* sin "tirar para recargar" al dibujar */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;   /* sin menu de pulsacion larga en iOS */
}

#view-canvas,
#overlay-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;               /* el tamano CSS lo fija el renderer */
  touch-action: none;
}

/* Los overlays se pintan encima pero no reciben punteros: quien captura el
   gesto es siempre #canvas-host (§17). */
#overlay-canvas {
  pointer-events: none;
}

/* La linea de tiempo si admite desplazamiento tactil en los dos ejes. */
#timeline-tracks {
  touch-action: pan-x pan-y;
}

/* ===================================================================
   Estilos del dialogo de Preferencias, trasladados desde
   app/js/ui/settingsDialog.js.
   Estaban inyectados como <style> desde JavaScript, cosa que la
   politica de seguridad de contenido (style-src 'self') bloquea.
   Viven en main.css y NO en panels.css porque el dialogo se abre tanto
   desde el editor como desde la PORTADA, y index.php no carga panels.css.
   =================================================================== */
.as-settings { width: min(940px, 100%); max-height: min(88vh, 900px); }
.as-settings-body { display: flex; min-height: 0; height: min(66vh, 620px); }
.as-settings-nav {
  flex: 0 0 auto; width: 188px; padding: var(--sp-3);
  border-right: 1px solid var(--bd); background: var(--s-1);
  overflow-y: auto; display: flex; flex-direction: column; gap: 2px;
}
.as-settings-nav .as-tab {
  display: flex; align-items: center; gap: var(--sp-3);
  width: 100%; min-height: var(--ctrl-h-cur); padding: 0 var(--sp-4);
  background: transparent; color: var(--fg-dim); border: 0;
  border-radius: var(--r-md); font-size: var(--fs-md); font-weight: var(--fw-medium);
  text-align: left; cursor: pointer; transition: background var(--t-fast), color var(--t-fast);
}
.as-settings-nav .as-tab:hover { background: var(--s-3); color: var(--fg); }
.as-settings-nav .as-tab[aria-selected="true"] {
  background: var(--accent-soft); color: var(--accent-ring);
}
.as-settings-panel { flex: 1 1 auto; min-width: 0; padding: var(--sp-6); overflow-y: auto; }
.as-section { display: flex; flex-direction: column; gap: var(--sp-5); }
.as-group { display: flex; flex-direction: column; gap: var(--sp-4); }
.as-row { display: flex; align-items: center; gap: var(--sp-4); min-width: 0; }
.as-row > .as-row-label { flex: 1 1 auto; min-width: 0; }
.as-row > .as-row-control { flex: 0 0 auto; width: 210px; max-width: 55%; }
.as-row-title { font-size: var(--fs-md); color: var(--fg); }
.as-row-hint { color: var(--fg-mute); font-size: var(--fs-xs); line-height: 1.35; }
.as-themes { display: flex; gap: var(--sp-4); flex-wrap: wrap; }
.as-theme {
  display: flex; flex-direction: column; gap: var(--sp-3); align-items: stretch;
  padding: var(--sp-3); background: var(--s-1); border: 2px solid var(--bd);
  border-radius: var(--r-md); cursor: pointer; width: 132px;
}
.as-theme[aria-pressed="true"] { border-color: var(--accent); }
.as-theme-preview { height: 62px; border-radius: var(--r-sm); overflow: hidden; display: flex; }
.as-theme-preview i { display: block; }
.as-theme-name { font-size: var(--fs-sm); color: var(--fg-dim); text-align: center; }
.as-theme[aria-pressed="true"] .as-theme-name { color: var(--fg); }
.as-meter { height: 8px; border-radius: var(--r-full); background: var(--s-4); overflow: hidden; }
.as-meter > i { display: block; height: 100%; background: var(--accent); border-radius: var(--r-full); }
.as-meter.is-warn > i { background: var(--warn); }
.as-meter.is-err > i { background: var(--err); }
.as-sc-list { display: flex; flex-direction: column; gap: 2px; }
.as-sc-group {
  margin-top: var(--sp-4); color: var(--fg-mute); font-size: var(--fs-xs);
  font-weight: var(--fw-semibold); letter-spacing: var(--ls-wide); text-transform: uppercase;
}
.as-sc-row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3); border-radius: var(--r-sm);
}
.as-sc-row:nth-child(odd) { background: var(--s-1); }
.as-sc-name { flex: 1 1 auto; min-width: 0; font-size: var(--fs-sm); color: var(--fg-dim); }
.as-sc-combo {
  flex: 0 0 auto; min-width: 128px; height: var(--ctrl-h-sm-cur); padding: 0 var(--sp-3);
  background: var(--s-0); color: var(--fg); border: 1px solid var(--bd);
  border-radius: var(--r-sm); font-family: var(--font-mono); font-size: var(--fs-sm);
  text-align: center; cursor: pointer;
}
.as-sc-combo.is-recording { border-color: var(--accent); color: var(--accent-ring); }
.as-sc-combo.is-empty { color: var(--fg-mute); }
.as-about dt { color: var(--fg-mute); font-size: var(--fs-xs); }
.as-about dd { margin: 0 0 var(--sp-4) 0; color: var(--fg); font-size: var(--fs-md); }
@media (max-width: 720px) {
  .as-settings-body { flex-direction: column; height: auto; max-height: none; }
  .as-settings-nav {
    width: 100%; flex-direction: row; overflow-x: auto; overflow-y: hidden;
    border-right: 0; border-bottom: 1px solid var(--bd);
  }
  .as-settings-nav .as-tab { width: auto; white-space: nowrap; }
  .as-row { flex-direction: column; align-items: stretch; gap: var(--sp-2); }
  .as-row > .as-row-control { width: 100%; max-width: none; }
}

/* --- Editor de paradas del degradado (§47.11.4) -------------------------- */
.grad-editor {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}

.grad-bar-wrap {
  width: 100%;
}

/* El canvas se estira al ancho disponible; su alto lo fija el guion, que es
   quien sabe cuanto miden la tira y las pastillas. */
.grad-bar {
  display: block;
  width: 100%;
  cursor: pointer;
  touch-action: none;       /* el arrastre es nuestro, no un desplazamiento */
  user-select: none;
  -webkit-user-select: none;
}

.grad-hint {
  margin: 0;
  color: var(--fg-dim);
  font-size: var(--fs-xs);
  line-height: 1.5;
}

.grad-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
}

.grad-lbl {
  color: var(--fg-dim);
  font-size: var(--fs-xs);
  white-space: nowrap;
}

.grad-color {
  width: 34px;
  height: 26px;
  padding: 0;
  border: 1px solid var(--bd);
  border-radius: var(--r-sm);
  background: none;
  cursor: pointer;
}

.grad-alpha { width: 120px; }

.grad-out {
  min-width: 3.5em;
  color: var(--fg-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
}

.grad-pos { width: 5.5em; }

.grad-h {
  margin: 0;
  color: var(--fg-dim);
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
}

.grad-presets {
  display: flex;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

/* Damero de fondo: tres de los siete preajustes acaban en transparente, y
   sobre un fondo liso «transparente» y «del color del fondo» son el mismo
   pixel. Con el damero se distinguen de un vistazo. */
.grad-preset {
  padding: 2px;
  border: 1px solid var(--bd);
  border-radius: var(--r-sm);
  background-color: #3a3a42;
  background-image:
    linear-gradient(45deg, #4a4a52 25%, transparent 25%, transparent 75%, #4a4a52 75%),
    linear-gradient(45deg, #4a4a52 25%, transparent 25%, transparent 75%, #4a4a52 75%);
  background-size: 12px 12px;
  background-position: 0 0, 6px 6px;
  cursor: pointer;
  line-height: 0;
}

.grad-preset:hover { border-color: var(--accent); }

.grad-preset:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* --- Editor de curvas de animacion (§47.13) ------------------------------ */
.curve-editor-body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.curve-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
}

.curve-lbl {
  color: var(--fg-dim);
  font-size: var(--fs-xs);
  white-space: nowrap;
}

.curve-sel { min-width: 8em; }

/* SIEMPRE en su propia linea (`flex-basis: 100%`), nunca al final de la fila
   de controles.

   Compartiendo linea, el texto pasaba de «Pulsa una clave para editarla» a
   «Fotograma 0 - 0» al seleccionar, la fila dejaba de partirse en dos, el
   dialogo encogia unos 22 px y —al estar centrado en la ventana— SALTABA 11 px
   bajo el cursor. El arrastre media ese salto como movimiento del raton y movia
   la clave que solo se queria seleccionar. Un dialogo que se mueve mientras
   arrastras hace que toda la herramienta se sienta poco fiable. */
.curve-info {
  flex: 1 0 100%;
  text-align: right;
  color: var(--fg-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
}

/* El lienzo necesita un alto EXPLICITO: un canvas sin alto declarado colapsa a
   su tamano intrinseco y la curva saldria de 150 px pase lo que pase. */
.curve-wrap {
  width: 100%;
  height: 300px;
  background: var(--s-1);
  border: 1px solid var(--bd);
  border-radius: var(--r-md);
  overflow: hidden;
}

.curve-canvas {
  display: block;
  width: 100%;
  height: 100%;
  cursor: crosshair;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

.curve-hint {
  margin: 0;
  color: var(--fg-dim);
  font-size: var(--fs-xs);
  line-height: 1.5;
}

/* --- Editor de pinceles (§47.15.4) ---------------------------------------
   Prefijo `be-` y no `brush-`: el PANEL de pinceles del dock ya usa
   `.brush-item` y `.brush-preview`, y reutilizar esos nombres hacia que los
   estilos del editor cayeran encima de un panel que no tiene nada que ver.
   Se descubrio contando: el dialogo mostraba 32 pinceles donde hay 16, y los
   otros 16 eran los del panel, que el selector alcanzaba sin querer.
   ------------------------------------------------------------------------ */
.be-editor-body {
  display: grid;
  grid-template-columns: minmax(280px, 340px) 1fr;
  gap: var(--sp-4);
  align-items: start;
}

/* En pantalla estrecha, una columna: la muestra arriba y los controles debajo.
   Con dos columnas forzadas, los deslizadores quedan de 60 px y no se pueden
   ajustar. */
@media (max-width: 760px) {
  .be-editor-body { grid-template-columns: 1fr; }
}

.be-left,
.be-right {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  min-width: 0;
}

.be-prev-wrap {
  border: 1px solid var(--bd);
  border-radius: var(--r-md);
  overflow: hidden;
  line-height: 0;
}

.be-prev {
  display: block;
  width: 100%;
  height: auto;
}

.be-hint {
  margin: 0;
  color: var(--fg-dim);
  font-size: var(--fs-xs);
  line-height: 1.5;
}

.be-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 220px;
  overflow-y: auto;
  padding: 2px;
  border: 1px solid var(--bd);
  border-radius: var(--r-md);
  background: var(--s-1);
}

.be-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 4px var(--sp-3);
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  color: var(--fg);
  font-size: var(--fs-sm);
  text-align: left;
  cursor: pointer;
}

.be-item:hover { background: var(--s-2); }
.be-item.is-active { background: var(--accent-soft, var(--s-3)); }

.be-item-name {
  flex: 1 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.be-badge {
  flex: 0 0 auto;
  color: var(--fg-dim);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: .03em;
}

.be-actions {
  display: flex;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

.be-sec {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3);
  border: 1px solid var(--bd);
  border-radius: var(--r-md);
}

.be-h {
  margin: 0 0 2px;
  color: var(--fg-dim);
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
}

.be-row {
  display: grid;
  grid-template-columns: 9.5em 1fr 3.8em;
  align-items: center;
  gap: var(--sp-2);
}

.be-row.be-check {
  grid-template-columns: auto 1fr;
}

.be-lbl {
  color: var(--fg-dim);
  font-size: var(--fs-xs);
}

.be-range { width: 100%; }

.be-out {
  color: var(--fg-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.be-sel { width: 100%; }

.be-curve-wrap {
  align-self: center;
  border: 1px solid var(--bd);
  border-radius: var(--r-sm);
  overflow: hidden;
  line-height: 0;
}

.be-curve {
  display: block;
  cursor: crosshair;
  touch-action: none;
}

.be-curves {
  display: flex;
  gap: var(--sp-2);
  flex-wrap: wrap;
  justify-content: center;
}

/* --- Paleta de comandos (§47.17.3) ---------------------------------------
   No usa los estilos de dialogo a proposito: una paleta no atenua el fondo ni
   pide una decision, aparece arriba y desaparece. El fondo es transparente y
   solo captura el clic de fuera.
   ------------------------------------------------------------------------ */
.cmdp-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding-top: 12vh;
  background: rgba(0, 0, 0, .28);
}

.cmdp {
  width: min(620px, calc(100vw - 32px));
  max-height: 64vh;
  display: flex;
  flex-direction: column;
  background: var(--s-2);
  border: 1px solid var(--bd);
  border-radius: var(--r-lg, 10px);
  box-shadow: var(--sh-3, 0 16px 48px rgba(0, 0, 0, .5));
  overflow: hidden;
}

.cmdp-input {
  flex: 0 0 auto;
  padding: var(--sp-4);
  border: 0;
  border-bottom: 1px solid var(--bd);
  background: none;
  color: var(--fg);
  font-size: var(--fs-md, 15px);
  outline: none;
}

.cmdp-list {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 4px;
}

.cmdp-item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  padding: 6px var(--sp-3);
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  color: var(--fg);
  font-size: var(--fs-sm);
  text-align: left;
  cursor: pointer;
}

.cmdp-item:hover { background: var(--s-3); }
.cmdp-item.is-sel { background: var(--accent); color: #fff; }

.cmdp-label {
  flex: 1 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cmdp-group {
  flex: 0 0 auto;
  color: var(--fg-dim);
  font-size: var(--fs-xs);
}

.cmdp-item.is-sel .cmdp-group { color: rgba(255, 255, 255, .8); }

.cmdp-kbd {
  flex: 0 0 auto;
  padding: 1px 6px;
  border: 1px solid var(--bd);
  border-radius: var(--r-sm);
  background: var(--s-1);
  color: var(--fg-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
}

.cmdp-item.is-sel .cmdp-kbd {
  border-color: rgba(255, 255, 255, .35);
  background: rgba(0, 0, 0, .2);
  color: #fff;
}

.cmdp-empty {
  padding: var(--sp-4);
  color: var(--fg-dim);
  font-size: var(--fs-sm);
  text-align: center;
}

.cmdp-empty[hidden] { display: none; }
