/* Cáscara Botcito Web (W1-S1). La identidad de marca llega en W4; esto es
   deliberadamente sobrio. El CSS del editor viene aparte (editor.css, extraído
   del index.html de editor-web por el build). */

/* ==========================================================================
   BASE COMPARTIDA (subtarea 0 del encargo `docs/encargo-ui-web.md`)

   Los tokens de la app, en un solo lugar: si cada pantalla reinventa estos
   valores, ninguna coincide con Android. Origen de cada grupo:
     · colores de marca  → ui/welcome/BotcitoLogoArt.kt + ui/HubScaffold.kt
     · colores del editor→ ui/theme/Color.kt
     · tipografía        → ui/theme/Type.kt (escala de Material 3)
     · retícula del hub  → ui/HubMetrics.kt (también en src/ui/hub.ts)
     · botón circular    → CircleIconButton (ui/editor/EditorScreen.kt)
   1 dp = 1 px CSS y 1 sp = 1 px (§4 del encargo): los números van tal cual.
   ========================================================================== */
:root {
  /* --- Marca (BotcitoLogoArt.kt:52-58, HubScaffold.kt:34, MenuScreen.kt) --- */
  --head-dark: #B73F25;
  --head-body: #EF4A45;
  --head-top: #D24635;
  --face-yellow: #EFC42B;
  --letter-blue: #303370;
  --letter-blue-rgb: 48, 51, 112;   /* para los alfa de la marca */
  --outline-gray: #9E9A94;
  --hub-bg: #FFF8F1;          /* HubBackground = MenuBackground (crema) */
  --learn-green: #2E9E7B;     /* 4.º color, tarjeta "Aprende" */
  --card-shadow-rgb: 107, 58, 34;  /* CardShadow #6B3A22, marrón cálido */
  --reconnect-amber: #E08A12; /* HubConnectionFace.kt:77 */

  /* --- Editor (theme/Color.kt) --- */
  --play-green: #3DD35C;
  --stop-red: #FF3B30;
  --console-cyan: #5CB1D6;
  --monitor-surface: #EAF2F8;
  --monitor-on-surface: #1C1B1F;
  --monitor-on-surface-variant: #49454F;
  --monitor-error: #B3261E;
  --monitor-accent: #1B6C8C;
  --icon-gray: #575E75;       /* gris Scratch de los íconos del lienzo */

  /* --- Tipografía. Sin Google Fonts (rompe el offline de la PWA, §4): en
         Android el navegador encuentra Roboto, la MISMA fuente de la app. --- */
  --font-stack: Roboto, "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  /* Escala de Material 3 (los estilos que usan las pantallas del hub). */
  --fs-headline-small: 24px; --lh-headline-small: 32px;
  --fs-title-large: 22px;    --lh-title-large: 28px;
  --fs-title-medium: 16px;   --lh-title-medium: 24px;  --ls-title-medium: .15px;
  --fs-body-large: 16px;     --lh-body-large: 24px;    --ls-body-large: .5px;
  --fs-body-medium: 14px;    --lh-body-medium: 20px;   --ls-body-medium: .25px;
  --fs-body-small: 12px;     --lh-body-small: 16px;    --ls-body-small: .4px;
  --fs-label-large: 14px;    --lh-label-large: 20px;   --ls-label-large: .1px;
  --fs-label-medium: 12px;   --lh-label-medium: 16px;  --ls-label-medium: .5px;

  /* --- Retícula del hub (HubMetrics.kt). --hub-m / --hub-header-h /
         --hub-cards-h los publica observeHubMetrics() al medir la pantalla,
         como BoxWithConstraints; acá van solo las constantes. --- */
  --hub-logo-width: 148px;
  --hub-cards-fraction: .6014;
  --hub-card-aspect: .945;
  --hub-card-gap: 18px;
  --hub-content-offset: 56px;
  --hub-card-corner: 28px;
  --hub-min-margin: 12px;

  /* --- Elevaciones. Equivalencia MEDIDA en la ronda 6 (editor-web/index.js:391):
         shadowElevation 3.dp ≈ feDropShadow dy 1 / stdDeviation 1,5 / .20 más
         dy 1 / 0,5 / .14; en box-shadow el blur es 2 × stdDeviation. --- */
  --elev-2: 0 1px 2px rgba(0, 0, 0, .20), 0 1px 1px rgba(0, 0, 0, .14);
  --elev-3: 0 1px 3px rgba(0, 0, 0, .20), 0 1px 1px rgba(0, 0, 0, .14);
  --elev-6: 0 2px 6px rgba(0, 0, 0, .20), 0 2px 2px rgba(0, 0, 0, .14);
  /* Sombra "luz desde arriba" de las tarjetas del hub (MenuScreen.kt:84): las
     MISMAS cinco capas apiladas (40 · 20 · 12 · 12 · 12 dp) con el tinte
     cálido; las repetidas oscurecen el borde inferior sin ensanchar el
     difuminado. Deshabilitada = las mismas al 80 % de elevación. */
  --card-elev: 0 26px 36px rgba(var(--card-shadow-rgb), .13),
               0 13px 18px rgba(var(--card-shadow-rgb), .13),
               0 8px 11px rgba(var(--card-shadow-rgb), .15),
               0 8px 11px rgba(var(--card-shadow-rgb), .15),
               0 8px 11px rgba(var(--card-shadow-rgb), .15);
  --card-elev-dim: 0 21px 29px rgba(var(--card-shadow-rgb), .13),
                   0 10px 14px rgba(var(--card-shadow-rgb), .13),
                   0 6px 9px rgba(var(--card-shadow-rgb), .15),
                   0 6px 9px rgba(var(--card-shadow-rgb), .15),
                   0 6px 9px rgba(var(--card-shadow-rgb), .15);

  /* --- Botón circular (CircleIconButton) y chrome del editor --- */
  /* CIRCLE_BUTTON_SIZE: 44 en la app; acá el grupo del lienzo (mira, lupas,
     deshacer, rehacer, basurero) va al tamaño del retroceso (pedido del
     usuario, 2026-08-24). */
  --circle-size: 63px;
  /* Chrome del editor. En la app: fila de 37 con texto de 14 sp. Acá el usuario
     pidió (2026-08-24) que el nombre del proyecto y el nombre del robot se lean
     al tamaño de los títulos del hub (24), así que la fila entera crece con el
     texto: 37 × 24/14 = 63, y con ella el retroceso, la pastilla del nombre
     (dentro del SVG del editor, vía setChromeMetrics) y la carita. */
  --chrome-size: 63px;        /* TOP_CHROME_SIZE ×24/14 */
  --chrome-font: 24px;        /* = --fs-headline-small (títulos del hub) */
  --chrome-margin: 12px;      /* TOP_CHROME_MARGIN */
  /* ▶/■/monitor: los 44 de la app +30 % (pedido del usuario, 2026-08-24;
     antes probamos el doble y lo revirtió). 44 × 1,3 = 57,2. */
  --run-size: 57.2px;
  --chrome-font: 14px;        /* TOP_CHROME_FONT */
  --face-pill-height: 48px;   /* FACE_PILL_HEIGHT del hub */
}


.screen {
  position: fixed;
  inset: 0;
}
.screen[data-active="false"] {
  visibility: hidden;
  pointer-events: none;
}
/* Los circulitos de categoría del toolbox llevan `visibility: visible
   !important` (editor.css, donde SÍ hay que forzarlo) y se colaban encima de
   las demás pantallas — el editor va último en el DOM, así que pinta arriba.
   Se le gana por especificidad sin tocar el CSS del editor. */
.screen[data-active="false"] .blocklyToolboxCategoryIcon { visibility: hidden !important; }

/* ---- Botón pastilla del hub (HubButton de ConnectPanes.kt, y el
   "+ Nuevo proyecto" de Proyectos: mismo Button de Material 3 con shape 50 %,
   containerColor LetterBlue y contentColor blanco; los filled no llevan
   sombra). Alto 40 y padding 24, los defaults de Material. ---- */
.hub-button {
  height: 40px; border: none; border-radius: 999px; padding: 0 24px;
  background: var(--letter-blue); color: #fff; cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  font-family: var(--font-stack);
  font-size: var(--fs-label-large); line-height: var(--lh-label-large);
  letter-spacing: var(--ls-label-large); font-weight: 500;
  -webkit-tap-highlight-color: transparent;
}
.hub-button:active { filter: brightness(.92); }
.hub-button:disabled {
  background: rgba(28, 27, 31, .12); color: rgba(28, 27, 31, .38);
  cursor: default; filter: none;
}
/* Variante clara para las acciones que en la app no viven en esta pantalla
   (Importar es propia de la web; el idioma se muda a Ajustes). */
.hub-button--ghost {
  background: #fff; color: var(--letter-blue); box-shadow: var(--elev-2);
}

/* ---- Armazón de las pantallas de detalle del hub (HubScaffold.kt) ----
   Fondo crema + los tres márgenes de la retícula + encabezado con ← y título a
   la izquierda y acciones a la derecha. El contenido se alinea con el TÍTULO
   (M + CONTENT_OFFSET), no con el borde. Lo usan el formulario y Ajustes. */
.hub-scaffold {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  background: var(--hub-bg); font-family: var(--font-stack);
}
.hub-header {
  flex: none; position: relative; height: var(--hub-header-h);
  /* Mismo ritmo vertical que el menú y Proyectos (pedido del usuario). */
  margin: var(--grid-top-gap) var(--hub-mx) 0;
  display: flex; align-items: center; justify-content: space-between;
}
.hub-title-group { display: flex; align-items: center; min-width: 0; }
.hub-back {
  flex: none; width: 48px; height: 48px; padding: 0; /* IconButton de Material */
  border: none; background: none; cursor: pointer; border-radius: 50%;
  color: var(--letter-blue);
  display: inline-flex; align-items: center; justify-content: center;
  -webkit-tap-highlight-color: transparent;
}
.hub-back:active { background: rgba(48, 51, 112, .12); }
.hub-title {
  margin: 0 0 0 8px;
  font-size: var(--fs-headline-small); line-height: var(--lh-headline-small);
  font-weight: 700; color: var(--letter-blue);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hub-actions { display: flex; align-items: center; flex: none; }
.hub-content {
  flex: 1 1 auto; position: relative; min-height: 0; overflow: auto;
  margin: var(--grid-top-gap) var(--hub-mx) var(--grid-top-gap)
          calc(var(--hub-mx) + var(--hub-content-offset));
}

/* ---- Bienvenida (subtarea 7: el SHOW completo, espejo de WelcomeScreen) ----
   Fondo blanco puro, el logo al 41,25 % del ancho y la pista 36 abajo. Las
   coreografías las dibuja el JS (ui/logoShow.ts): acá no hay animación CSS. */
#screen-welcome { background: #fff; }
.welcome-stage {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 36px;
  cursor: pointer; font-family: var(--font-stack);
}
/* overflow visible: las coreografías sacan la cabeza FUERA del cuadro del logo
   (entra desde el borde de la pantalla) y no debe recortarse. */
.welcome-logo { width: 41.25%; max-width: 720px; margin-top: 12px; overflow: visible; }
.welcome-hint {
  font-size: var(--fs-body-medium); line-height: var(--lh-body-medium);
  letter-spacing: var(--ls-body-medium);
  color: rgba(var(--letter-blue-rgb), .55);
  opacity: 0; /* la maneja el show: aparece con las letras y pulsa */
}

/* ---- Menú hub (subtarea 1: espejo de MenuScreen.kt) ----
   Retícula del hub: M encima del logo, M entre el logo y las tarjetas y M
   debajo (el tercero es lo que sobra, como el Spacer final de Compose). */
#screen-menu { background: var(--hub-bg); overflow: hidden; font-family: var(--font-stack); }
.menu-root { position: absolute; inset: 0; display: flex; flex-direction: column; }
.menu-header {
  flex: none; position: relative;
  /* Margen vertical de la referencia (el mismo que separa el encabezado de las
     tarjetas); el horizontal sigue siendo el del hub. */
  height: var(--hub-header-h); margin: var(--grid-top-gap) var(--hub-mx) 0;
}
.menu-logo {
  position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: var(--hub-logo-width); cursor: pointer; overflow: visible;
}
.menu-actions {
  position: absolute; right: 0; top: 50%; transform: translateY(-50%);
  display: flex; align-items: center;
  gap: 7px; /* GEAR_GAP: con el aire del botón de 32 da los ~15 px medidos */
}
.menu-gear {
  flex: none; width: 32px; height: 32px; padding: 0; /* GEAR_BUTTON_SIZE */
  border: none; background: none; cursor: pointer; border-radius: 50%;
  color: var(--letter-blue);
  display: inline-flex; align-items: center; justify-content: center;
  -webkit-tap-highlight-color: transparent;
}
.menu-gear:active { background: rgba(48, 51, 112, .12); }

/* Tarjetas en FILAS CENTRADAS DE CUATRO (referencia del usuario): el tamaño y
   los huecos salen de la retícula medida (ui/hub.ts) y, cuando las filas no
   entran, la zona de tarjetas se desplaza en VERTICAL. */
.menu-cards {
  flex: 1 1 auto; min-height: 0;
  overflow-y: auto; overflow-x: hidden;
  padding: var(--grid-top-gap) var(--grid-mx);
  display: grid; grid-template-columns: repeat(4, var(--card-w));
  gap: var(--grid-gap-y) var(--grid-gap-x);
  justify-content: center; align-content: start;
  scrollbar-width: none;
}
.menu-cards::-webkit-scrollbar { display: none; }
.menu-card {
  position: relative; padding: 0; border: none; font: inherit;
  width: var(--card-w); height: var(--card-h);
  background: var(--card-bg); border-radius: var(--hub-card-corner);
  box-shadow: var(--card-elev); cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .1s ease;
}
.menu-card[data-enabled="false"] { box-shadow: var(--card-elev-dim); cursor: default; }
/* El ripple de Material no existe en la web: :active con transición corta. */
.menu-card[data-enabled="true"]:active { transform: scale(.985); }
/* El contenido de una tarjeta deshabilitada se atenúa; la pastilla
   "Próximamente" queda FUERA de la atenuación para leerse bien. */
.menu-card-dim { position: absolute; inset: 0; border-radius: inherit; overflow: hidden; }
.menu-card[data-enabled="false"] .menu-card-dim { opacity: .45; }
.menu-card-art { position: absolute; inset: 0; }
.menu-card-name {
  position: absolute; left: 20px; top: 16px; right: 20px; text-align: left;
  font-size: var(--fs-headline-small); line-height: var(--lh-headline-small);
  font-weight: 700; color: var(--card-title);
}
.menu-soon {
  position: absolute; left: 20px; top: 58px;
  background: #fff; border-radius: 999px; padding: 5px 14px;
  font-size: var(--fs-label-large); line-height: var(--lh-label-large);
  letter-spacing: var(--ls-label-large); font-weight: 500;
  color: var(--letter-blue);
}
.projects-title-group { display: flex; align-items: center; gap: 10px; }

/* ---- La CARITA de conexión (subtarea 6: espejo de HubConnectionFace) ----
   Pastilla blanca con la cabeza del logo, el anillo y —solo conectada— el
   nombre del robot. El alto (48 en el hub, 37 en el editor) y la sombra los
   pone el JS; todo lo demás escala con él. */
.conn-face {
  display: inline-flex; align-items: center; gap: 8px;
  box-sizing: border-box; border: none; background: #fff; cursor: pointer;
  border-radius: 999px; padding: 0 4px;
  -webkit-tap-highlight-color: transparent;
}
.conn-face:active { transform: scale(0.97); }
.conn-face-box { position: relative; flex: none; display: inline-block; }
.conn-face-ring { position: absolute; left: 0; top: 0; }
.conn-face-head {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  overflow: visible;
}
.conn-face-name {
  font-family: var(--font-stack); font-weight: 700; color: var(--letter-blue);
  max-width: 240px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* En el editor el nombre se lee al tamaño de los títulos del hub, y la caja
   crece con él (el ancho lo pone el JS con el alto de la pastilla). */
#editor-conn .conn-face-name { max-width: 360px; }

/* ---- Proyectos (subtarea 2: espejo de ProjectsScreen.kt) ----
   Misma retícula y mismas tarjetas que el menú; las de proyecto son BLANCAS y
   PLANAS (sin sombra, pedido del usuario). */
#screen-projects {
  background: var(--hub-bg); overflow: hidden;
  font-family: var(--font-stack); color: var(--letter-blue);
}
.projects-root { position: absolute; inset: 0; display: flex; flex-direction: column; }
.projects-header {
  flex: none; position: relative;
  height: var(--hub-header-h); margin: var(--grid-top-gap) var(--hub-mx) 0;
}
/* ← + título a la izquierda, pestañas al CENTRO, acciones a la derecha. */
.projects-header .hub-title-group {
  position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  max-width: 42%;
}
.projects-tabs { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); }
.projects-actions {
  position: absolute; right: 0; top: 50%; transform: translateY(-50%);
  display: flex; align-items: center; gap: 8px;
}

/* Modo angosto (solo en la web: la app va en horizontal fija). Ver fitHeader. */
.projects-header[data-narrow="true"] .hub-title { display: none; }
.projects-header[data-narrow="true"] .hub-button { padding: 0 12px; gap: 0; }
.projects-header[data-narrow="true"] .hub-button span { display: none; }

/* Selector segmentado de placa: píldora blanca sobre el riel translúcido. */
.projects-tabs {
  display: flex; padding: 4px; border-radius: 999px;
  background: rgba(var(--letter-blue-rgb), .10);
}
.board-tab {
  border: none; background: none; cursor: pointer;
  border-radius: 999px; padding: 9px 16px;
  font-family: var(--font-stack);
  font-size: var(--fs-label-large); line-height: var(--lh-label-large);
  letter-spacing: var(--ls-label-large); font-weight: 400;
  color: var(--letter-blue); white-space: nowrap;
  -webkit-tap-highlight-color: transparent;
}
.board-tab[data-active="true"] { background: #fff; font-weight: 700; box-shadow: var(--elev-2); }

/* Tarjetas en FILAS CENTRADAS DE CUATRO con scroll vertical (referencia del
   usuario): mismo criterio que el menú, con las medidas de su propia foto. */
.projects-row {
  flex: 1 1 auto; min-height: 0;
  overflow-y: auto; overflow-x: hidden;
  padding: var(--grid-top-gap) var(--grid-mx);
  display: grid; grid-template-columns: repeat(4, var(--card-w));
  gap: var(--grid-gap-y) var(--grid-gap-x);
  justify-content: center; align-content: start;
  scrollbar-width: none;
}
.projects-row::-webkit-scrollbar { display: none; }
.project-card, .new-project-card {
  position: relative; box-sizing: border-box;
  width: var(--card-w); height: var(--card-h);
  border-radius: var(--hub-card-corner);
}
.project-card {
  background: #fff; border: none; padding: 0; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .1s ease;
}
.project-card:active { transform: scale(.985); }
.project-body {
  position: absolute; inset: 0; padding: 12px 14px; box-sizing: border-box;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
}
/* Ícono +20 % y +15 % (58 → 69,6 → 80,04; el segundo lo pidió el usuario el
   2026-08-24). Se acota a una fracción del alto de la tarjeta para que en
   pantallas chicas —donde cuatro columnas dejan tarjetas bajas— no se coma el
   nombre y la fecha; esa cota sube con el ícono (0,35 → 0,4025), si no el
   aumento no se vería justo donde la tarjeta es baja. En un monitor normal
   manda el 80,04. */
.project-icon {
  font-size: min(80.04px, calc(var(--card-h) * 0.4025)); line-height: 1.2;
}
.project-name {
  margin-top: 10px; max-width: 100%;
  font-size: var(--fs-title-medium); line-height: var(--lh-title-medium);
  letter-spacing: var(--ls-title-medium); font-weight: 700;
  color: var(--letter-blue);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.project-date {
  max-width: 100%;
  font-size: var(--fs-body-small); line-height: var(--lh-body-small);
  letter-spacing: var(--ls-body-small);
  color: rgba(var(--letter-blue-rgb), .55);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Engranaje arriba a la derecha: IconButton de 48 con el ícono de 24. */
.project-gear {
  position: absolute; top: 0; right: 0; width: 48px; height: 48px;
  border: none; background: none; padding: 0; cursor: pointer; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  color: rgba(var(--letter-blue-rgb), .45);
  -webkit-tap-highlight-color: transparent;
}
.project-gear:active { background: rgba(var(--letter-blue-rgb), .10); }

/* Tarjeta punteada "+" (última celda). El trazo de la app es de 2,5 dp con
   guiones de 20/16 px CRUDOS (no dp): a la densidad del Redmi se ven de 7,3 y
   5,8 dp — que es, redondeando, lo que dibuja el borde punteado del navegador
   para un trazo de 2,5 px. */
.new-project-card {
  background: none; padding: 0; cursor: pointer;
  border: 2.5px dashed rgba(var(--letter-blue-rgb), .35);
  display: flex; align-items: center; justify-content: center;
  color: rgba(var(--letter-blue-rgb), .55);
  -webkit-tap-highlight-color: transparent;
}

/* Menú de desborde del encabezado (Importar + idioma; ver projects.ts). */
.projects-more { position: relative; }
.projects-more .card-menu { right: 0; top: 44px; }

/* Menú del engranaje (DropdownMenu de Material 3). */
.card-menu {
  position: absolute; right: 12px; top: 48px; z-index: 5;
  background: #fff; border-radius: 4px; box-shadow: var(--elev-3);
  display: flex; flex-direction: column; min-width: 112px; overflow: hidden;
  padding: 8px 0;
}
.card-menu button {
  font-family: var(--font-stack);
  font-size: var(--fs-body-large); line-height: var(--lh-body-large);
  letter-spacing: var(--ls-body-large);
  color: var(--monitor-on-surface); text-align: left; white-space: nowrap;
  border: none; background: none; padding: 0 12px; height: 48px; cursor: pointer;
}
.card-menu button:active { background: rgba(var(--letter-blue-rgb), .10); }

/* ---- Formulario de proyecto (subtarea 3: espejo de ProjectFormScreen.kt) ----
   Va dentro del armazón del hub: el contenido arranca alineado con el TÍTULO.
   Campos separados por 6, como el Column del original. */
.form-fields { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.field-label {
  font-size: var(--fs-body-medium); line-height: var(--lh-body-medium);
  letter-spacing: var(--ls-body-medium);
  color: rgba(var(--letter-blue-rgb), .7);
}
/* OutlinedTextField con shape 50 %: pastilla blanca, borde transparente en
   reposo y borde de marca al enfocar (alto 56 y padding 16, los de Material;
   el padding compensa el borde de 2 para que el texto no se mueva). */
.form-input {
  box-sizing: border-box; width: 100%; max-width: 520px; height: 56px;
  border-radius: 999px; padding: 0 16px;
  border: 1px solid transparent; background: #fff;
  font-family: var(--font-stack);
  font-size: var(--fs-body-large); line-height: var(--lh-body-large);
  letter-spacing: var(--ls-body-large); color: var(--monitor-on-surface);
}
.form-input:focus { outline: none; border: 2px solid var(--letter-blue); padding: 0 15px; }

.form-field { display: flex; flex-direction: column; gap: 8px; }
/* Al crear, "tipo de robot" e ícono van LADO A LADO: en horizontal la franja
   libre es corta y apilados quedaban fuera de vista. */
/* En la web hay pantallas angostas que la app no tiene (horizontal fija): los
   dos campos y las tarjetas de placa bajan de fila solos cuando no entran. */
.form-pair { display: flex; align-items: flex-start; gap: 24px 48px; flex-wrap: wrap; }
.robot-types { display: flex; gap: 12px; flex-wrap: wrap; }
/* Tarjeta seleccionable del hub: la comparten "tipo de robot" (formulario) y
   el idioma (Ajustes) — mismo Surface blanco de radio 16 con borde de 1 px al
   15 % y de 2 px de marca al elegirla. El padding compensa el borde para que
   el texto no se mueva (en Compose el borde no cambia el tamaño). */
.choice-card {
  box-sizing: border-box;
  border-radius: 16px; background: #fff; cursor: pointer; text-align: left;
  /* El borde de Compose se dibuja DENTRO del Surface y no corre al texto: el
     padding se descuenta para que el texto quede a 16/20 del borde exterior
     con cualquiera de los dos grosores. */
  border: 1px solid rgba(var(--letter-blue-rgb), .15); padding: 15px 19px;
  font-family: var(--font-stack);
  font-size: var(--fs-title-medium); line-height: var(--lh-title-medium);
  letter-spacing: var(--ls-title-medium); font-weight: 400;
  color: rgba(var(--letter-blue-rgb), .75);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  -webkit-tap-highlight-color: transparent;
}
.choice-card[data-selected="true"] {
  border: 2px solid var(--letter-blue); padding: 14px 18px;
  font-weight: 700; color: var(--letter-blue);
}
/* La del formulario además tiene ancho mínimo (widthIn de la app). */
.robot-type { min-width: 160px; max-width: 260px; }

/* Ícono: "Cambiar" + vista previa (la tarjeta blanca de la lista, en chico). */
.icon-row { display: flex; align-items: center; gap: 16px; }
.icon-preview {
  width: 76px; height: 76px; border-radius: 18px; background: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: 34px; line-height: 1;
}

/* ---- Ajustes (subtarea 4: espejo de SettingsScreen.kt) ---- */
.settings-group { display: flex; flex-direction: column; gap: 10px; align-items: flex-start; }
.settings-options { display: flex; gap: 12px; flex-wrap: wrap; }

/* ---- Diálogos (AlertDialog de Material 3) ---- */
.dialog-scrim {
  position: fixed; inset: 0; z-index: 300;
  background: rgba(0, 0, 0, .32);
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
.dialog-card {
  box-sizing: border-box; background: #fff; border-radius: 28px; padding: 24px;
  box-shadow: var(--elev-6); max-width: min(560px, 100%); max-height: 100%;
  overflow: auto; font-family: var(--font-stack);
  color: var(--monitor-on-surface);
}
.dialog-title {
  margin: 0 0 16px;
  font-size: var(--fs-headline-small); line-height: var(--lh-headline-small);
  font-weight: 400;
}
.dialog-text {
  margin: 0;
  font-size: var(--fs-body-medium); line-height: var(--lh-body-medium);
  letter-spacing: var(--ls-body-medium);
  color: var(--monitor-on-surface-variant);
}
.dialog-buttons { display: flex; justify-content: flex-end; gap: 8px; margin-top: 24px; }
.text-button {
  border: none; background: none; cursor: pointer; border-radius: 999px;
  height: 40px; padding: 0 12px; color: var(--letter-blue);
  font-family: var(--font-stack);
  font-size: var(--fs-label-large); line-height: var(--lh-label-large);
  letter-spacing: var(--ls-label-large); font-weight: 500;
  -webkit-tap-highlight-color: transparent;
}
.text-button:active { background: rgba(var(--letter-blue-rgb), .12); }

/* Grilla de íconos: 6 por fila (4 filas) — con 4 por fila no entra en horizontal. */
.icon-grid { display: grid; grid-template-columns: repeat(6, auto); justify-content: start; }
.icon-cell {
  border: none; background: none; cursor: pointer; border-radius: 12px;
  padding: 5px 7px; font-size: 26px; line-height: 1.2;
  -webkit-tap-highlight-color: transparent;
}
.icon-cell[data-current="true"] { background: rgba(var(--letter-blue-rgb), .12); }

/* El editor respeta las zonas seguras, como el windowInsetsPadding(safeDrawing)
   del original (recorte de cámara). Sin viewport-fit=cover los env() valen 0 y
   el navegador ya excluye el recorte; queda listo para cuando se active. */
#screen-editor {
  box-sizing: border-box;
  padding: env(safe-area-inset-top) env(safe-area-inset-right)
           env(safe-area-inset-bottom) env(safe-area-inset-left);
}

/* ---- Chrome del editor (subtarea 5: espejo de EditorScreen.kt) ----
   Fila superior a 12 del borde del TOOLBOX (ronda 5/6): retroceso a la
   izquierda y carita a la derecha. La pastilla del NOMBRE no está acá: la
   dibuja el editor dentro de su SVG, DEBAJO de los bloques. */
#editor-chrome {
  position: absolute; top: var(--chrome-margin); left: var(--chrome-margin);
  display: flex; gap: 8px;
  /* Sobre el toolbox de Blockly (z-index 70) y bajo su UI de edición
     (widgetDiv 99 / dropDownDiv 100), que además oculta el chrome. */
  z-index: 80;
}
#editor-chrome[data-hidden="true"] { visibility: hidden; }
.circle-btn {
  /* CircleIconButton: blanco, sombra de elevación 3 y el ícono centrado. El
     tamaño base es el del chrome (37); --44 es el del grupo de controles. */
  width: var(--chrome-size); height: var(--chrome-size); border-radius: 50%;
  border: none; background: #fff; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  box-shadow: var(--elev-3);
  padding: 0;
  -webkit-tap-highlight-color: transparent;
}
.circle-btn:active { transform: scale(0.94); }
.circle-btn--44 { width: var(--circle-size); height: var(--circle-size); box-shadow: var(--elev-6); }
/* La pila de ejecución va al doble; el grupo de la izquierda se queda en 44. */
.circle-btn--44.run-btn { width: var(--run-size); height: var(--run-size); }

/* ---- Grupo de controles del lienzo (W1-S4, F8 ronda 3) ---- */
#editor-controls {
  position: absolute; bottom: var(--chrome-margin); left: var(--chrome-margin);
  display: flex; align-items: center; gap: 3px;
  z-index: 80; /* como #editor-chrome: sobre el toolbox, bajo la UI de edición */
}
#editor-controls[data-hidden="true"] { visibility: hidden; }
/* El toggle NO es un círculo blanco (en la app es un IconButton pelado de 24
   con el triángulo de 15 adentro). Acá crece con las burbujas del grupo, que
   pasaron de 44 a 63: 24 × 63/44 ≈ 34, con el triángulo a 21,5. */
.toggle-btn {
  width: 34px; height: 34px; padding: 0; border: none; background: none;
  border-radius: 50%; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  -webkit-tap-highlight-color: transparent;
}
/* El `overflow: hidden` que hace la cortina del despliegue recortaba la SOMBRA
   de los botones contra su propia caja (44 de alto justos): las burbujas se
   veían cortadas en la base. Se le da aire con relleno y se lo descuenta con
   margen negativo, así el recorte de la cortina cae fuera de las sombras y la
   fila no se mueve ni un pixel. `border-box` para que el relleno no reviva la
   cortina cuando max-width vale 0. */
#controls-expansion {
  display: flex; align-items: center; gap: 3px;
  overflow: hidden; max-width: 0; opacity: 0;
  box-sizing: border-box; padding: 8px; margin: -8px;
  transition: max-width .35s ease, opacity .25s ease;
}
#editor-controls[data-expanded="true"] #controls-expansion {
  /* 5 burbujas de 63 + 4 separaciones de 3 = 327, + los 16 del relleno. */
  max-width: 344px; opacity: 1;
}
/* 540° por toque (540 ≡ 180 mod 360), 450 ms — los números del original. */
#toggle-icon { display: inline-flex; transition: transform .45s ease; }

/* ---- Estado de conexión (W2-S1): la carita, a la altura del chrome ---- */
#editor-conn {
  position: absolute; top: var(--chrome-margin); right: var(--chrome-margin); z-index: 80;
}
#editor-conn[data-hidden="true"] { visibility: hidden; }

/* ---- Pila de ejecución (W3-S1, F8-S4) ---- */
#editor-run {
  position: absolute; bottom: var(--chrome-margin); right: var(--chrome-margin); z-index: 80;
  display: flex; flex-direction: column; gap: 8px; align-items: center;
}
#editor-run[data-hidden="true"] { visibility: hidden; }
.run-btn { position: relative; }
.run-btn[data-color="play"] { background: var(--play-green); }
.run-btn[data-color="stop"] { background: var(--stop-red); }
.run-btn[data-color="console"] { background: var(--console-cyan); }
/* Aro de progreso de la descarga: 20 px con trazo de 2, como el
   CircularProgressIndicator del original. */
#play-ring {
  position: absolute; inset: 15.6px; border-radius: 50%;
  border: 2.6px solid rgba(255, 255, 255, 0.45); border-top-color: #fff;
  display: none;
}
#btn-play[data-busy="true"] #play-ring { display: block; animation: ring-spin .9s linear infinite; }
#btn-play[data-busy="true"] svg { visibility: hidden; }
@keyframes ring-spin { to { transform: rotate(360deg); } }

/* ---- Banner de sincronización (W3-S3, F5-S2; top 64 como la app) ----
   De ancho completo con 12 de margen, para no tapar el retroceso. */
#sync-banner {
  position: absolute; top: 64px; left: 12px; right: 12px;
  z-index: 70; /* sobre el monitor (60), bajo la UI de edición de Blockly */
  display: flex; align-items: center; gap: 4px;
  background: #dbe9ff; border-radius: 12px;
  padding: 4px 4px 4px 16px;
  font-family: var(--font-stack);
  font-size: var(--fs-body-medium); line-height: var(--lh-body-medium);
  letter-spacing: var(--ls-body-medium);
  color: #1d3a6b; box-shadow: var(--elev-6);
}
#sync-banner span { flex: 1; }
#sync-banner .text-button { color: #1d3a6b; }
.sync-x {
  width: 48px; height: 48px; flex: none; border: none; background: none;
  cursor: pointer; color: #1d3a6b; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
}

/* ---- MonitorCard (W3-S2, F8-S5) ----
   Tarjeta flotante SIN scrim (el editor detrás sigue visible y tocable),
   pegada a la derecha con el borde en el CENTRO del play (12 + 57,2/2 = 40,6
   acá, donde el play va +30 %; 12 + 44/2 = 34 en la app) y centrada en vertical. El ancho lo calcula el JS: la mitad del LIENZO (el
   editor menos el toolbox). Alto 63,75 % (0,85 − 25 %). */
#monitor-card {
  position: absolute; top: 50%; right: 40.6px;
  height: 63.75%;
  background: var(--monitor-surface); border-radius: 16px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, .20), 0 4px 4px rgba(0, 0, 0, .14);
  display: flex; flex-direction: column;
  font-family: var(--font-stack); color: var(--monitor-on-surface);
  z-index: 60; /* bajo el chrome (80) — el chrome sigue tocable, como la app */
  box-sizing: border-box; overflow: hidden;
}
#monitor-card[data-hidden="true"] { visibility: hidden; }
.monitor-header {
  flex: none;
  display: flex; align-items: center;
  padding: 4px 4px 4px 16px; cursor: grab; user-select: none; touch-action: none;
}
.monitor-title {
  flex: 1;
  font-size: var(--fs-title-medium); line-height: var(--lh-title-medium);
  letter-spacing: var(--ls-title-medium); font-weight: 500;
}
.monitor-x {
  width: 48px; height: 48px; flex: none; border: none; background: none;
  cursor: pointer; color: var(--monitor-on-surface); border-radius: 50%; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
}
/* Pestañas: TabRow de Material — dos mitades, texto de 14 y una barra de 2 px
   bajo la elegida. */
.monitor-tabs {
  flex: none; display: flex; align-items: stretch;
  padding: 0 4px; border-bottom: 1px solid rgba(28, 27, 31, .12);
}
.monitor-tab {
  flex: 1; height: 48px; position: relative;
  border: none; background: none; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; gap: 12px;
  font-family: var(--font-stack);
  font-size: var(--fs-label-large); line-height: var(--lh-label-large);
  letter-spacing: var(--ls-label-large); font-weight: 500;
  color: var(--monitor-on-surface);
  -webkit-tap-highlight-color: transparent;
}
.monitor-tab[data-active="true"]::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--monitor-accent);
}
/* El basurero de limpiar va DENTRO de la pestaña de mensajes y solo cuando
   está activa (limpiar desde Variables no aplica). */
.monitor-clear {
  border: none; background: none; cursor: pointer; padding: 5px;
  border-radius: 50%; color: var(--monitor-accent);
  display: inline-flex; align-items: center; justify-content: center;
}
.monitor-list {
  flex: 1; overflow-y: auto; padding: 0 16px;
  font-family: ui-monospace, Consolas, monospace;
  font-size: var(--fs-body-medium); line-height: var(--lh-body-medium);
}
.monitor-line { padding: 0; white-space: pre-wrap; word-break: break-word; }
.monitor-line[data-source="error"] { color: var(--monitor-error); }
/* Aviso de vacío: centrado, con el texto del original y (en mensajes) la
   imagen del bloque "decir" debajo. */
.monitor-empty {
  height: 100%; margin: 0; padding: 16px 24px; box-sizing: border-box;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
  font-family: var(--font-stack);
  font-size: var(--fs-body-medium); line-height: var(--lh-body-medium);
  letter-spacing: var(--ls-body-medium);
  color: var(--monitor-on-surface-variant); text-align: center;
}
.say-block { height: 44px; width: auto; }

/* ---- Toast/aviso (W3-S1) ---- */
#toast {
  position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%);
  z-index: 300; display: flex; align-items: center; gap: 12px;
  background: #26323f; color: #fff; border-radius: 12px;
  padding: 12px 16px; font-family: var(--font-stack); font-size: .95rem;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35); max-width: 90vw;
}
#toast button {
  font: inherit; font-weight: bold; border: none; cursor: pointer;
  background: none; color: #7ab8ff; padding: 4px 6px;
}

/* ---- Hoja de robots (subtarea 6: espejo de RobotSheet/RobotSheetOverlay) ----
   Sube desde abajo con el fondo crema del hub (las tarjetas blancas sobre
   blanco desaparecían), el alto del 62 % y el margen lateral de la retícula.
   No lleva carita adentro: la del encabezado queda a la vista. */
#robot-sheet-overlay { position: fixed; inset: 0; z-index: 200; }
.sheet-catcher { position: absolute; inset: 0; }
.robot-sheet {
  position: absolute; left: var(--hub-mx); right: var(--hub-mx); bottom: 0;
  height: 62%; box-sizing: border-box;
  background: var(--hub-bg); border-radius: 28px 28px 0 0;
  box-shadow: 0 4px 12px rgba(0, 0, 0, .20), 0 4px 4px rgba(0, 0, 0, .14);
  display: flex; flex-direction: column;
  padding: 8px 12px 16px 24px;
  font-family: var(--font-stack); color: var(--letter-blue);
  animation: sheet-up .22s ease-out;
}
@keyframes sheet-up { from { transform: translateY(100%); opacity: 0; } to { transform: none; opacity: 1; } }
/* Al cerrarse hace el MISMO viaje al revés (la app la anima con
   slideOutVertically + fadeOut, espejo de su entrada): misma duración y la
   curva invertida —el reverso exacto de ease-out es ease-in—. `forwards` la
   deja abajo y transparente hasta que el JS la saca del DOM. */
#robot-sheet-overlay[data-closing="true"] { pointer-events: none; }
#robot-sheet-overlay[data-closing="true"] .robot-sheet {
  animation: sheet-down .22s ease-in forwards;
}
@keyframes sheet-down { from { transform: none; opacity: 1; } to { transform: translateY(100%); opacity: 0; } }
.sheet-header { flex: none; display: flex; align-items: center; margin-bottom: 8px; }
.sheet-title {
  flex: 1; margin: 0;
  font-size: var(--fs-headline-small); line-height: var(--lh-headline-small);
  font-weight: 700; color: var(--letter-blue);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sheet-x {
  width: 48px; height: 48px; flex: none; border: none; background: none;
  cursor: pointer; color: var(--letter-blue); border-radius: 50%; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
}
/* El cuerpo de la hoja solo hace de marco: adentro va un StatusPane o el
   ScanPane, como las dos ramas de RobotSheet.kt. */
.sheet-body { flex: 1; min-height: 0; display: flex; flex-direction: column; }
/* StatusPane: rueda opcional, mensaje centrado y botones debajo. */
.status-pane {
  flex: 1; min-height: 0; box-sizing: border-box; padding: 32px; overflow: auto;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center;
}
.sheet-message {
  margin: 0;
  font-size: var(--fs-body-large); line-height: var(--lh-body-large);
  letter-spacing: var(--ls-body-large); color: var(--letter-blue);
}
.sheet-connected {
  margin: 0;
  font-size: var(--fs-title-medium); line-height: var(--lh-title-medium);
  letter-spacing: var(--ls-title-medium); font-weight: 700; color: var(--letter-blue);
}
.sheet-vm {
  margin: 6px 0 0;
  font-size: var(--fs-body-medium); line-height: var(--lh-body-medium);
  letter-spacing: var(--ls-body-medium); color: rgba(var(--letter-blue-rgb), .7);
}
.sheet-spinner {
  width: 40px; height: 40px; margin-bottom: 24px; border-radius: 50%;
  border: 4px solid rgba(var(--letter-blue-rgb), .25);
  border-top-color: var(--letter-blue);
  animation: ring-spin .9s linear infinite;
}

/* ScanPane (ConnectPanes.kt): barra indeterminada azul, "Buscando robots…",
   los robots como tarjetas blancas y el aviso de vacío. Mismos números que la
   app: barra hasta 560 con 16 abajo, texto con 10, tarjetas separadas 10, radio
   16 y 18/14 de relleno. El botón del final (el chooser del navegador) es lo
   único que la app no tiene: sin él, un robot nunca permitido no puede entrar
   a la lista (D-W-7). */
/* El contenido va CENTRADO (porteo del hermano, 2026-08-28; solo el título de
   la hoja queda a la izquierda): barra, texto, tarjetas y botón comparten el
   eje. Las tarjetas topean en 560 y en pantallas anchas quedaban a la
   izquierda. */
.scan-pane {
  flex: 1; min-height: 0; display: flex; flex-direction: column;
  align-items: center; text-align: center;
}
.scan-progress {
  flex: none; width: 100%; max-width: 560px; height: 4px; margin-bottom: 16px;
  border-radius: 2px; overflow: hidden;
  background: rgba(var(--letter-blue-rgb), .15);
}
.scan-progress span {
  display: block; width: 40%; height: 100%; border-radius: 2px;
  background: var(--letter-blue);
  animation: scan-sweep 1.8s cubic-bezier(.4, 0, .2, 1) infinite;
}
@keyframes scan-sweep {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(250%); }
}
.scan-status {
  flex: none; margin: 0 0 10px;
  font-size: var(--fs-body-medium); line-height: var(--lh-body-medium);
  letter-spacing: var(--ls-body-medium); color: rgba(var(--letter-blue-rgb), .7);
}
.scan-hint {
  flex: none; margin: 0; max-width: 560px;
  font-size: var(--fs-body-medium); line-height: var(--lh-body-medium);
  letter-spacing: var(--ls-body-medium); color: rgba(var(--letter-blue-rgb), .7);
}
.robot-list {
  flex: 0 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden;
  width: 100%; display: flex; flex-direction: column; align-items: center;
  /* Relleno simétrico: solo a la derecha (para el scroll) corría las tarjetas
     2 px del eje. */
  gap: 10px; padding: 0 4px; box-sizing: border-box; scrollbar-width: none;
}
.robot-list::-webkit-scrollbar { display: none; }
.robot-list:empty { display: none; }
.robot-card {
  flex: none; box-sizing: border-box; width: 100%; max-width: 560px;
  text-align: left;
  display: flex; align-items: center; gap: 14px; text-align: left;
  padding: 14px 18px; border: none; border-radius: 16px; background: #fff;
  color: var(--letter-blue); cursor: pointer; font-family: var(--font-stack);
  -webkit-tap-highlight-color: transparent; transition: transform .1s ease;
}
.robot-card:active { transform: scale(.985); }
.robot-card-icon { flex: none; color: var(--letter-blue); }
.robot-card-texts { min-width: 0; display: flex; flex-direction: column; }
.robot-card-name {
  font-size: var(--fs-title-medium); line-height: var(--lh-title-medium);
  letter-spacing: var(--ls-title-medium); font-weight: 700; color: var(--letter-blue);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.robot-card-signal {
  font-size: var(--fs-body-small); line-height: var(--lh-body-small);
  letter-spacing: var(--ls-body-small); color: rgba(var(--letter-blue-rgb), .55);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.scan-more { flex: none; }
