/* ═══════════════════════════════════════════════════════════
   Nimboo Cloud — Base
   Reset minimal, tipografia, animaciones y componentes base.
   Importar DESPUES de tokens.css.
   ═══════════════════════════════════════════════════════════ */

/* ─── Reset moderno ─────────────────────────────────────── */

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

* {
  margin: 0;
  padding: 0;
}

html {
  /* Se acabo el rebote elastico.
  
     macOS e iOS dejan estirar la pagina mas alla de su final y la
     sueltan de golpe. En un sitio suelto se lee como que el
     navegador respira; en una herramienta de trabajo se lee como
     que la pantalla esta floja, sobre todo porque aqui no hay
     nada que recargar al tirar hacia abajo. Adriano lo describio
     el 10 agosto 2026: "estiras la pagina y rebota".
     
     `none` corta el rebote y ademas evita que un scroll que llega
     al final se lo lleve el contenedor de atras. */
  overscroll-behavior: none;

  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

body {
  min-height: 100vh;
  background: var(--paper);
  color: var(--black);
  font-family: var(--display);
  font-size: var(--t-base);
  font-weight: var(--w-regular);
  line-height: var(--lh-normal);
}

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

input, button, textarea, select {
  font: inherit;
  color: inherit;
}

button {
  background: none;
  border: none;
  cursor: pointer;
}

a {
  color: inherit;
  text-decoration: none;
}

ul, ol {
  list-style: none;
}

/* ─── Animaciones compartidas ───────────────────────────── */

@keyframes float-cloud {
  0%, 100% { transform: translate(0, 0) scale(1); }
  33%      { transform: translate(20px, -15px) scale(1.05); }
  66%      { transform: translate(-15px, 10px) scale(0.98); }
}

@keyframes float-soft {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-6px); }
}

@keyframes pulse-soft {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.7; transform: scale(0.95); }
}

@keyframes fade-in-up {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: translateY(0); }
}

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

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

/* Respeto por quien pide menos movimiento */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ─── Tipografia ────────────────────────────────────────── */

.kicker {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--display);
  font-size: 10px;
  font-weight: var(--w-semibold);
  letter-spacing: var(--ls-widest);
  text-transform: uppercase;
  color: var(--cloud-deep);
}

.kicker::before {
  content: "";
  width: 24px;
  height: 1px;
  background: var(--cloud);
}

.kicker.no-line::before {
  display: none;
}

.headline {
  font-family: var(--display);
  font-weight: var(--w-bold);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-tight);
}

/* Palabra destacada dentro de un titular. Nunca en italic:
   se distingue por color, no por inclinacion. */
.headline em,
.accent {
  font-style: normal;
  font-weight: var(--w-bold);
  color: var(--cloud-deep);
}

.body-text {
  font-family: var(--body-text);
  line-height: var(--lh-relaxed);
}

.caption {
  font-family: var(--display);
  font-size: var(--t-sm);
  color: var(--ink-60);
}

/* ─── Layout helpers ────────────────────────────────────── */

.container {
  width: 100%;
  max-width: var(--container-lg);
  margin: 0 auto;
  padding: 0 var(--s-6);
}

.container-narrow { max-width: var(--container-narrow); }
.container-md     { max-width: var(--container-md); }
.container-xl     { max-width: var(--container-xl); }

.stack > * + * {
  margin-top: var(--stack-gap, var(--s-4));
}

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

.items-center { align-items: center; }
.items-start  { align-items: flex-start; }
.items-end    { align-items: flex-end; }

.justify-between { justify-content: space-between; }
.justify-center  { justify-content: center; }
.justify-end     { justify-content: flex-end; }

.gap-1 { gap: var(--s-1); }
.gap-2 { gap: var(--s-2); }
.gap-3 { gap: var(--s-3); }
.gap-4 { gap: var(--s-4); }
.gap-6 { gap: var(--s-6); }
.gap-8 { gap: var(--s-8); }

/* ─── Botones ───────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  padding: 14px 28px;
  font-family: var(--display);
  font-size: 12px;
  font-weight: var(--w-semibold);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  transition: all var(--d-base);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  position: relative;
  overflow: hidden;
}

.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
}

/* ═══════════════════════════════════════════════════════════
   La cascara de la ventana modal

   Vivia entera en ventana.css, que cargan once pantallas. El
   problema es que la confirmacion de "Cerrar sesion" no la
   dispara ninguna pantalla: la dispara el GUARDIA, que corre en
   todas. En las 23 que no cargaban la hoja, el aviso salia como
   texto suelto al pie de la pagina, con sus dos botones, sin
   fondo oscuro y sin ser modal. Adriano lo vio en el portal del
   cliente el 12 agosto 2026.

   La leccion: lo que puede aparecer en cualquier pantalla no
   puede depender de que esa pantalla se acuerde de pedirlo. Va
   en la base, que la cargan todas.

   Aqui esta solo la cascara. Los campos y los pasos siguen en
   ventana.css, porque esos si son de las ventanas con
   formulario y no tienen por que pesar en todas partes.
   ═══════════════════════════════════════════════════════════ */

.vent-fondo {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal-bg, 800);
  background: rgba(15, 20, 25, .5);
  backdrop-filter: blur(2px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  animation: vent-entra var(--d-fast) ease-out;
}

@keyframes vent-entra { from { opacity: 0; } to { opacity: 1; } }

.vent-caja {
  background: var(--white);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  padding: 28px 30px 22px;
  width: 100%;
  max-width: 480px;
  max-height: 88vh;
  overflow-y: auto;
  animation: fade-in-up var(--d-base) ease-out;
}

.vent-caja h2 {
  font-size: 18px;
  font-weight: var(--w-bold);
  color: var(--black);
  margin: 0 0 6px;
}

.vent-sub {
  font-size: 12px;
  color: var(--ink-60);
  line-height: var(--lh-relaxed);
  margin: 0 0 20px;
}

.vent-pie {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding-top: 16px;
  border-top: 1px solid var(--line-soft);
}

@media (max-width: 520px) {
  .vent-fondo { padding: 12px; align-items: flex-end; }
  .vent-caja { padding: 22px 18px 18px; max-height: 92vh; }
  .vent-pie { flex-direction: column-reverse; }
  .vent-pie .btn { width: 100%; }
}

/* Boton principal: el azul de la marca con texto blanco.
   Decision de Adriano el 9 agosto 2026. El texto oscuro sobre el
   azul contrasta mas, pero se ve agresivo y no es la marca. */
.btn-cloud {
  background: var(--cloud);
  color: var(--on-cloud);
  box-shadow: 0 4px 14px rgba(122, 181, 205, 0.40);
  position: relative;
  overflow: hidden;
}

/* Un destello que cruza al pasar el mouse. Cruza UNA vez y se
   queda quieto: si se repitiera solo, a los diez segundos seria
   un anuncio parpadeando. */
.btn-cloud::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  width: 42%;
  left: -60%;
  background: linear-gradient(
    100deg,
    transparent,
    rgba(255, 255, 255, .38),
    transparent
  );
  pointer-events: none;
}

.btn-cloud:hover:not(:disabled) {
  background: var(--cloud-hover);
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(122, 181, 205, 0.55);
}

.btn-cloud:hover:not(:disabled)::after {
  animation: destello .75s ease-out;
}

@keyframes destello {
  to { left: 120%; }
}

@media (prefers-reduced-motion: reduce) {
  .btn-cloud::after { display: none; }
}

.btn-secondary {
  background: var(--white);
  color: var(--cloud-deeper);
  border-color: var(--cloud-soft);
}
.btn-secondary:hover:not(:disabled) {
  background: var(--cloud-mist);
  border-color: var(--cloud);
  transform: translateY(-1px);
}

/* Deshacer, quitar, dar de baja. Rojo de contorno, no de relleno:
   el relleno rojo compite con el boton principal de la pantalla y
   quien lo ve cree que es la accion que se espera de el. */
.btn-peligro {
  background: var(--white);
  color: var(--red);
  border-color: var(--red-soft);
}
.btn-peligro:hover:not(:disabled) {
  background: var(--red-pale);
  border-color: var(--red);
  transform: translateY(-1px);
}
.btn-peligro:disabled { color: var(--ink-40); border-color: var(--line); }

.btn-success {
  background: var(--green);
  color: var(--white);
  box-shadow: 0 4px 14px rgba(5, 150, 105, 0.25);
}
.btn-success:hover:not(:disabled) {
  background: #047857;
  transform: translateY(-2px);
}

.btn-ghost {
  background: transparent;
  color: var(--ink-60);
  padding: 10px 16px;
}
.btn-ghost:hover:not(:disabled) {
  background: var(--cloud-mist);
  color: var(--cloud-deeper);
}

.btn-block { width: 100%; }
.btn-sm    { padding: 10px 20px; font-size: 11px; }
.btn-lg    { padding: 16px 32px; font-size: 13px; }

/* ─── Inputs ────────────────────────────────────────────── */

.input {
  display: block;
  width: 100%;
  padding: 14px 18px;
  font-family: var(--display);
  font-size: var(--t-base);
  background: var(--cloud-mist);
  color: var(--black);
  border: 1.5px solid transparent;
  border-radius: var(--r-md);
  transition: all var(--d-base);
}

.input::placeholder { color: var(--ink-40); }

.input:focus {
  outline: none;
  background: var(--white);
  border-color: var(--cloud);
  box-shadow: 0 0 0 4px rgba(154, 197, 214, 0.50);
}

.input:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.input.is-error {
  border-color: var(--red);
  background: var(--red-pale);
}

textarea.input {
  min-height: 100px;
  resize: vertical;
  font-family: var(--display);
}

.input-label {
  display: block;
  margin-bottom: 10px;
  font-family: var(--display);
  font-size: 10px;
  font-weight: var(--w-semibold);
  letter-spacing: var(--ls-wider);
  text-transform: uppercase;
  color: var(--ink-60);
}

.input-hint {
  margin-top: var(--s-2);
  font-size: var(--t-sm);
  color: var(--ink-60);
}

.input-hint.is-error { color: var(--red); }

/* ─── Badges ────────────────────────────────────────────── */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  font-family: var(--display);
  font-size: 10px;
  font-weight: var(--w-semibold);
  letter-spacing: 0.10em;
  text-transform: uppercase;
  border-radius: var(--r-pill);
  background: var(--cloud-pale);
  color: var(--cloud-deeper);
}

.badge-success { background: var(--green-pale); color: var(--green); }
.badge-warning { background: var(--amber-pale); color: var(--amber); }
.badge-error   { background: var(--red-pale);   color: var(--red); }
.badge-neutral { background: var(--ink-10);     color: var(--ink-80); }
.badge-gold    { background: var(--gold-pale);  color: var(--gold); }

/* El azul de la casa. Para lo que esta en marcha y es nuestro,
   frente al dorado, que en Cloud significa que algo salio al
   cliente. */
.badge-cloud   { background: var(--cloud-pale);  color: var(--cloud-ink); }

.badge-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
  animation: pulse-soft 2s var(--ease) infinite;
}

/* ─── Avatar ────────────────────────────────────────────── */

.avatar {
  width: 36px;
  height: 36px;
  border-radius: var(--r-pill);
  background: var(--cloud);
  color: var(--on-cloud);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: var(--w-semibold);
  letter-spacing: 0.05em;
  flex-shrink: 0;
  box-shadow: var(--shadow-sm);
}

.avatar-sm { width: 28px; height: 28px; font-size: 10px; }
.avatar-lg { width: 48px; height: 48px; font-size: 14px; }

/* ─── Superficies ───────────────────────────────────────── */

.surface {
  background: var(--paper-pure);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xs);
}

.surface-padded { padding: var(--s-8); }

/* ─── Toasts (consumidos por ui-helpers.js) ─────────────── */

/* ═══════════════════════════════════════════════════════════
   El aviso de la esquina

   Al pasar el mouse encima se detiene la cuenta, porque un aviso
   que desaparece justo cuando lo ibas a leer es peor que no
   ponerlo. Eso no cambia con el aspecto.
   ═══════════════════════════════════════════════════════════ */

.toast-container {
  position: fixed;
  top: var(--s-6);
  right: var(--s-6);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  gap: 10px;
  pointer-events: none;
}

/* ═══════════════════════════════════════════════════════════
   CAPSULA

   Elegida por Adriano, que la habia pedido desde el principio
   con una captura de una pildora flotante. La primera version
   fue un bloque de color macizo, la segunda una tarjeta con
   filo, y ninguna de las dos era lo que enseno.

   Es una pildora entera: sin borde, sin filo de color, sin
   linea de tiempo al pie. Solo la superficie, una sombra que la
   despega del fondo, y el simbolo en su circulo del color que
   toque. El color ya no se pinta en un canto, se dice con el
   circulo, que es lo primero que mira el ojo.

   Sin borde y sin barra hace falta la sombra: es lo unico que
   la separa del fondo y dice que esta flotando encima.
   ═══════════════════════════════════════════════════════════ */

.toast {
  pointer-events: auto;
  position: relative;
  display: flex;
  align-items: center;
  gap: 13px;
  min-width: 300px;
  max-width: 430px;
  padding: 11px 22px 11px 11px;
  background: var(--white);
  border-radius: 999px;
  box-shadow: 0 2px 4px rgba(15, 20, 25, .04),
              0 10px 30px rgba(15, 20, 25, .09);
  animation: toast-entra var(--d-base);
}

/* El simbolo, en su circulo del mismo color pero tenue. */
.toast-glifo {
  flex-shrink: 0;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--cloud-pale);
  color: var(--cloud-deep);
}

.toast-glifo svg { width: 18px; height: 18px; }

.toast-texto {
  flex: 1;
  min-width: 0;
  font-size: 13.5px;
  font-weight: var(--w-medium);
  line-height: 1.4;
  color: var(--black);
}

.toast-cerrar {
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  border-radius: var(--r-xs);
  background: transparent;
  color: var(--ink-40);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--d-fast), color var(--d-fast);
}

.toast-cerrar:hover { background: var(--paper); color: var(--ink-80); }
.toast-cerrar svg { width: 13px; height: 13px; }

/* La capsula no lleva cuenta atras: la linea al pie pedia un
   canto recto donde apoyarse y aqui no lo hay. El elemento se
   sigue creando desde el guion, escondido, para no tener que
   tocar el guion cada vez que cambie el aspecto. */
.toast-tiempo { display: none; }

/* ─── Los cuatro tonos ────────────────────────────────────
   Cambia el circulo y el simbolo, nada mas. El fondo NUNCA: la
   superficie es la misma que la de cualquier tarjeta, y es lo
   que hace que se vea de la misma casa. */

.toast.is-success .toast-glifo { background: var(--green-pale); color: var(--green); }
.toast.is-error   .toast-glifo { background: var(--red-pale);   color: var(--red); }
.toast.is-warning .toast-glifo { background: var(--amber-pale); color: var(--amber); }

.toast.is-leaving { animation: toast-sale var(--d-fast) forwards; }

@keyframes toast-entra {
  from { opacity: 0; transform: translateX(16px) scale(.98); }
  to   { opacity: 1; transform: translateX(0) scale(1); }
}

@keyframes toast-sale {
  to { opacity: 0; transform: translateX(16px) scale(.98); }
}

@keyframes toast-tiempo {
  from { transform: scaleX(1); }
  to   { transform: scaleX(0); }
}

@media (max-width: 560px) {
  .toast-container { top: auto; bottom: var(--s-4); left: var(--s-4); right: var(--s-4); }
  .toast { min-width: 0; max-width: none; }
}
}

@media (max-width: 600px) {
  .toast-container {
    top: auto;
    bottom: var(--s-4);
    left: var(--s-4);
    right: var(--s-4);
  }
  .toast { min-width: 0; max-width: none; }
}

/* ─── Loading / spinner ─────────────────────────────────── */

.spinner {
  display: inline-block;
  width: 16px;
  height: 16px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

.spinner-lg {
  width: 32px;
  height: 32px;
  border-width: 3px;
}

/* Capa de carga mientras se resuelve la sesion */
.boot-screen {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--paper);
  color: var(--cloud);
  transition: opacity var(--d-base);
}

.boot-screen.is-hidden {
  opacity: 0;
  pointer-events: none;
}

/* ─── Nubes decorativas de fondo ────────────────────────── */

.cloud-deco {
  position: absolute;
  pointer-events: none;
  border-radius: 50%;
  filter: blur(80px);
  z-index: 0;
}

/* ─── Visually hidden (a11y) ────────────────────────────── */

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

.is-hidden { display: none !important; }

/* ─── Seleccion y foco ──────────────────────────────────── */

::selection {
  background: var(--cloud-pale);
  color: var(--cloud-ink);
}

:focus-visible {
  outline: 2px solid var(--cloud);
  outline-offset: 2px;
}

button:focus-visible,
.btn:focus-visible {
  outline-offset: 3px;
}

/* ═══════════════════════════════════════════════════════════
   Controles nativos, vestidos

   La casilla y el selector de archivo del navegador son lo unico
   de la plataforma que no se diseño: llegan con la caja gris de
   Chrome, la palomita azul del sistema y un boton que dice
   "Choose File" en ingles. Adriano lo señalo el 10 agosto 2026 y
   tenia razon: rompen la pantalla justo donde alguien esta a
   punto de firmar un contrato.

   Los dos siguen siendo el control nativo por dentro. Se esconde
   el que dibuja el navegador y se dibuja el nuestro encima, asi
   que el teclado, el foco y el lector de pantalla siguen
   funcionando igual.
   ═══════════════════════════════════════════════════════════ */

/* ─── La casilla ─────────────────────────────────────────── */

.check {
  appearance: none;
  -webkit-appearance: none;
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  margin: 0;
  border: 1.5px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--white);
  cursor: pointer;
  position: relative;
  transition: all var(--d-fast);
}

.check:hover { border-color: var(--cloud); }

.check:checked {
  background: var(--cloud);
  border-color: var(--cloud);
}

/* La palomita se dibuja con dos rayas y un giro, no con un
   caracter: un check tipografico cambia de forma segun la fuente
   que cargue, y aqui tiene que verse igual siempre. */
.check:checked::after {
  content: '';
  position: absolute;
  left: 5px;
  top: 1px;
  width: 5px;
  height: 10px;
  border: solid var(--cloud-ink);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

.check:focus-visible {
  outline: 2px solid var(--cloud);
  outline-offset: 2px;
}

/* ─── El selector de archivo ─────────────────────────────── */
/* El <input type="file"> se esconde y su <label> hace de boton.
   Al elegir algo, el nombre del archivo aparece al lado: sin eso
   nadie sabe si el clic sirvio de algo. */

.archivo { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

.archivo input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.archivo-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 9px 16px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  background: var(--white);
  font-family: var(--display);
  font-size: 13px;
  font-weight: var(--w-semibold);
  color: var(--ink-80);
  cursor: pointer;
  transition: all var(--d-fast);
  white-space: nowrap;
}

.archivo-btn:hover {
  border-color: var(--cloud);
  color: var(--cloud-deep);
  background: var(--cloud-mist);
}

.archivo input[type="file"]:focus-visible + .archivo-btn {
  outline: 2px solid var(--cloud);
  outline-offset: 2px;
}

.archivo-nombre {
  font-size: 12px;
  color: var(--ink-60);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.archivo-nombre.es-puesto { color: var(--cloud-deep); font-weight: var(--w-semibold); }

/* ═══════════════════════════════════════════════════════════
   El aviso

   Una franja para decir algo que hay que saber antes de seguir,
   sin llegar a interrumpir.

   Vivia dentro del <style> de proyecto.html y de acceso.html, y
   programacion.html la usaba sin definirla: ahi salia sin fondo,
   sin color y con el triangulo suelto, como texto plano en medio
   del diseño. Adriano lo vio el 10 agosto 2026.

   La leccion, para no repetirla: una clase que usa mas de una
   pantalla NO puede vivir en el <style> de una de ellas. La
   siguiente que la use la hereda rota y nadie se entera hasta
   que alguien mira esa pantalla.
   ═══════════════════════════════════════════════════════════ */

.aviso {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: 13px;
  line-height: var(--lh-normal);
  color: var(--amber);
  background: var(--amber-pale);
  padding: 12px 16px;
  border-radius: var(--r-sm);
  margin-bottom: 8px;
}

.aviso svg { flex-shrink: 0; margin-top: 2px; }

/* Lo que ya costo algo, no lo que puede costar. */
.aviso.is-grave { color: var(--red); background: var(--red-pale); }

/* Informativo, ni bueno ni malo: azul de la casa. */
.aviso.is-nota { color: var(--cloud-ink); background: var(--cloud-pale); }

/* ═══════════════════════════════════════════════════════════
   El panel: titulo, entrada y pie

   Las tres piezas de cabecera y cierre de un panel o modal.

   Vivian dentro del <style> de proyecto.html, equipo.html y
   renderistas.html, tres copias del mismo estilo. asignacion.html
   y mi-proyecto.html las usaban SIN definirlas, asi que el
   "Tus datos / Quedan registrados en el contrato" del modal de
   firmar salia como texto plano. Adriano lo vio el 10 agosto
   2026, el mismo dia que lo de .aviso y por la misma causa.

   Es la segunda vez en un dia. La regla queda escrita en los dos
   sitios: una clase que usa mas de una pantalla NO puede vivir
   en el <style> de una de ellas. La siguiente que la use la
   hereda rota, y nadie se entera hasta que alguien mira esa
   pantalla.
   ═══════════════════════════════════════════════════════════ */

.panel-titulo {
  font-size: 20px;
  font-weight: var(--w-bold);
  letter-spacing: -0.02em;
  color: var(--black);
  margin-bottom: 4px;
}

.panel-sub {
  font-size: 13px;
  color: var(--ink-60);
  line-height: var(--lh-relaxed);
  margin-bottom: 24px;
}

.panel-pie {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 26px;
  padding-top: 22px;
  border-top: 1px solid var(--line);
}


/* ═══════════════════════════════════════════════════════════
   La caja

   El contenedor blanco de toda la vida, con su cabecera opcional.
   Vivia en programacion.css y lo usaban tambien acceso.html y
   carga.html sin cargar esa hoja. Sube aqui, que es donde va lo
   que usa mas de una pantalla.
   ═══════════════════════════════════════════════════════════ */

.caja {
  background: var(--white);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xs);
  overflow: hidden;
}

.caja-cabeza {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 18px 22px;
  border-bottom: 1px solid var(--line-soft);
}

.caja-titulo {
  font-size: 14px;
  font-weight: var(--w-bold);
  letter-spacing: -0.01em;
  color: var(--black);
}

.caja-cuenta { font-size: 12px; color: var(--ink-60); }

/* El boton de mes anterior y mes siguiente. Lo usan el
   calendario de Programacion y la tira de Carga del equipo. */
.cal-mover {
  width: 30px;
  height: 30px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--white);
  color: var(--ink-60);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all var(--d-fast);
}

.cal-mover:hover { border-color: var(--cloud); color: var(--cloud-deep); }

/* ═══════════════════════════════════════════════════════════
   La ayuda detras de un signo de interrogacion

   Las pantallas explicaban con un parrafo debajo de cada titulo.
   Con seis secciones eso son seis parrafos que se leen una vez
   en la vida y estorban para siempre. La explicacion sigue
   estando, pero solo sale si se pide.
   ═══════════════════════════════════════════════════════════ */

.ayuda {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  margin-left: 8px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--white);
  color: var(--ink-50);
  font-family: var(--display);
  font-size: 11px;
  font-weight: var(--w-bold);
  line-height: 1;
  cursor: pointer;
  vertical-align: middle;
  transition: background var(--d-fast), color var(--d-fast), border-color var(--d-fast);
}

.ayuda:hover,
.ayuda.is-on {
  background: var(--cloud-mist);
  border-color: var(--cloud);
  color: var(--cloud-ink);
}

.ayuda-globo {
  position: absolute;
  z-index: 90;
  max-width: 340px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--white);
  box-shadow: var(--shadow-md);
  font-size: var(--t-sm);
  line-height: 1.55;
  color: var(--ink-70);
  animation: fade-in var(--d-fast);
}

@media (max-width: 560px) {
  .ayuda-globo { max-width: calc(100vw - 32px); }
}

/* ═══════════════════════════════════════════════════════════
   Piezas que resultaron ser de todos

   Nacieron dentro de una pantalla y despues las quiso otra, y
   otra. Mientras vivieron en la hoja de una sola, cada pantalla
   nueva que las necesitaba tenia que cargar una hoja entera que
   no le tocaba, o copiarlas. Aqui viven una vez.
   ═══════════════════════════════════════════════════════════ */
.section-sub {
  font-size: 12px;
  color: var(--ink-60);
  line-height: var(--lh-relaxed);
  margin: 4px 0 0;
  max-width: 70ch;
}
.filtro-chip {
  padding: 7px 14px;
  border-radius: var(--r-pill);
  border: none;
  background: none;
  font-family: var(--display);
  font-size: 12px;
  font-weight: var(--w-medium);
  color: var(--ink-60);
  cursor: pointer;
  transition: all var(--d-fast);
  white-space: nowrap;
}
.filtro-chip:hover { color: var(--cloud-deep); }
.filtro-chip.is-on {
  background: var(--cloud);
  color: var(--on-cloud);
  font-weight: var(--w-semibold);
}
.filtro-num {
  display: inline-block;
  margin-left: 5px;
  opacity: .65;
  font-weight: var(--w-medium);
}

/* ═══════════════════════════════════════════════════════════
   Los desplegables

   Se quedan NATIVOS y se visten, en lugar de reemplazarlos por
   uno hecho a mano. Es una decision, no pereza.

   Un desplegable propio se ve exactamente igual mientras esta
   cerrado, que es el 99 por ciento del tiempo, y a cambio pierde
   tres cosas que el nativo trae puestas: la rueda del teclado
   para elegir escribiendo, el lector de pantalla, y la lista a
   pantalla completa del telefono, que es mucho mejor que
   cualquier cosa que se pueda dibujar en 375 pixeles.

   Lo que SI se quita es la cara de Chrome: la flechita gris del
   sistema se cambia por una nuestra, y el marco por el de la
   casa. Adriano lo pidio el 11 agosto 2026, y lo que le molestaba
   era justo eso, no el mecanismo.

   Lo unico que no se puede vestir es la lista ABIERTA: la pinta
   el sistema operativo y ningun sitio del mundo puede tocarla.
   Con color-scheme puesto al menos sale oscura en modo oscuro.
   ═══════════════════════════════════════════════════════════ */

select {
  appearance: none;
  -webkit-appearance: none;
  padding: 10px 34px 10px 13px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background-color: var(--white);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 16 16' fill='none' stroke='%23808F9A' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6.5l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 11px center;
  font-family: var(--display);
  font-size: var(--t-sm);
  color: var(--black);
  cursor: pointer;
  transition: border-color var(--d-fast), box-shadow var(--d-fast);
}

select:hover:not(:disabled) { border-color: var(--cloud); }

select:focus {
  outline: none;
  border-color: var(--cloud);
  box-shadow: 0 0 0 3px var(--cloud-mist);
}

select:disabled {
  background-color: var(--paper);
  color: var(--ink-40);
  cursor: not-allowed;
}

/* La casilla de verificar, tambien nuestra. La del sistema es
   azul de Chrome y sale hasta en modo oscuro. */
input[type="checkbox"], input[type="radio"] {
  appearance: none;
  -webkit-appearance: none;
  flex-shrink: 0;
  width: 17px;
  height: 17px;
  border: 1.5px solid var(--ink-20);
  border-radius: 5px;
  background: var(--white);
  cursor: pointer;
  position: relative;
  transition: background var(--d-fast), border-color var(--d-fast);
}

input[type="radio"] { border-radius: 50%; }

input[type="checkbox"]:hover:not(:disabled),
input[type="radio"]:hover:not(:disabled) { border-color: var(--cloud); }

input[type="checkbox"]:checked,
input[type="radio"]:checked {
  background: var(--cloud);
  border-color: var(--cloud);
}

input[type="checkbox"]:checked::after {
  content: '';
  position: absolute;
  left: 5px;
  top: 1.5px;
  width: 4px;
  height: 9px;
  border: solid var(--on-cloud);
  border-width: 0 2px 2px 0;
  transform: rotate(42deg);
}

input[type="radio"]:checked::after {
  content: '';
  position: absolute;
  inset: 4px;
  border-radius: 50%;
  background: var(--on-cloud);
}

input[type="checkbox"]:focus-visible,
input[type="radio"]:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--cloud-mist);
}

input[type="checkbox"]:disabled,
input[type="radio"]:disabled { opacity: .5; cursor: not-allowed; }

/* ═══════════════════════════════════════════════════════════
   El autocompletado de Chrome

   Cuando el navegador rellena un campo le pinta encima un azul
   lavanda suyo, el #e8f0fe, y de paso le cambia el color a la
   letra. Adriano lo vio en los campos de correo el 11 agosto
   2026 y lo describio exacto: "un azul moradiento".

   No es un fondo cualquiera: Chrome lo aplica con mas prioridad
   que cualquier `background` nuestro, asi que no se quita
   escribiendo otro color encima.

   La forma que si funciona es una sombra INTERIOR gigante del
   color que queremos. La sombra se pinta por encima del fondo
   del navegador y lo tapa por completo. Es un truco viejo y feo,
   pero es el unico que hay, y el resultado es que un campo
   rellenado por el navegador se ve igual que uno escrito a mano.

   Va con --cloud-mist y no con un color fijo, asi que en modo
   oscuro tambien queda bien. Sin esto, en oscuro el azul
   lavanda de Chrome sale disparado en medio de la pantalla.
   ═══════════════════════════════════════════════════════════ */

input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active,
textarea:-webkit-autofill,
select:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 1000px var(--cloud-mist) inset !important;
  box-shadow: 0 0 0 1000px var(--cloud-mist) inset !important;
  -webkit-text-fill-color: var(--black) !important;
  caret-color: var(--black);

  /* Chrome vuelve a pintar su fondo con una transicion al
     enfocar. Con una transicion imposiblemente larga nunca llega
     a hacerlo. */
  transition: background-color 9999s ease-in-out 0s;
}

/* Los campos con marco propio, como los de las puertas, llevan
   su mismo fondo blanco en lugar del azul tenue. */
.puerta-campo input:-webkit-autofill,
.cli-campo input:-webkit-autofill,
.vent-campo input:-webkit-autofill,
.aj-campo input:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 1000px var(--white) inset !important;
  box-shadow: 0 0 0 1000px var(--white) inset !important;
}


/* ═══════════════════════════════════════════════════════════
   El desplegable propio

   Convive con el <select> nativo vestido de aqui arriba, y NO
   se contradicen: cada uno gana en un sitio distinto.

   El nativo se queda donde hay muchas opciones o donde se
   trabaja con el teclado: trae la busqueda escribiendo, el
   lector de pantalla y la lista a pantalla completa del
   telefono, que es mejor que cualquier cosa dibujable en 375
   pixeles. Su unico defecto es la lista ABIERTA, que la pinta
   el sistema operativo y nadie en el mundo puede vestir.

   Y ese defecto pesa distinto segun quien mire. Adentro es un
   detalle. En el PORTAL DEL CLIENTE no: ahi la plataforma es la
   cara de Nimboo frente a alguien que nos esta pagando, y un
   menu gris de Chrome en medio rompe justo lo que se quiere
   sostener. Adriano lo vio el 11 agosto 2026.

   Asi que este se usa donde son pocas opciones y se ven, que es
   el caso del selector de proyecto del cliente. Nacio en el
   comparador de versiones del panel de revision y se subio aqui
   para que lo pueda usar cualquier pantalla.
   ═══════════════════════════════════════════════════════════ */

.desp { position: relative; }

.desp-boton {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 12px;
  border-radius: var(--r-md);
  border: 1.5px solid var(--line);
  background: var(--white);
  font-family: var(--display);
  font-size: 12px;
  font-weight: var(--w-semibold);
  color: var(--black);
  cursor: pointer;
  transition: all var(--d-fast);
  white-space: nowrap;
}

.desp-boton:hover { border-color: var(--cloud); }

.desp-boton svg { color: var(--ink-40); flex-shrink: 0; }

.desp-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: var(--z-modal);
  min-width: 190px;
  max-height: 280px;
  overflow-y: auto;
  padding: 6px;
  border-radius: var(--r-md);
  background: var(--white);
  box-shadow: var(--shadow-lg);
  border: 1px solid var(--line-soft);
}

.desp-menu.es-derecha { left: auto; right: 0; }

/* Abre hacia arriba. La caja de la revision recorta lo que se
   sale, y un menu al pie se cortaria a la mitad. Hacia arriba
   cae sobre la imagen, que es espacio de sobra. */
.desp-menu.es-arriba {
  top: auto;
  bottom: calc(100% + 6px);
}

.desp-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  padding: 9px 11px;
  border: none;
  border-radius: var(--r-xs);
  background: none;
  font-family: var(--display);
  font-size: 12px;
  font-weight: var(--w-medium);
  color: var(--ink-80);
  cursor: pointer;
  text-align: left;
  transition: background var(--d-fast);
}

.desp-item:hover { background: var(--cloud-mist); }

.desp-item.is-on {
  background: var(--cloud);
  color: var(--on-cloud);
  font-weight: var(--w-semibold);
}

.desp-item-nota { font-size: 10px; color: var(--ink-40); }
.desp-item.is-on .desp-item-nota { color: var(--on-cloud); opacity: .75; }

/* El punto verde: esa version la vio el cliente */
.desp-punto {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--green);
  flex-shrink: 0;
}


/* ─── La cortina de la app ──────────────────────────────────
   Quien entra desde un telefono ve esto una vez. La web de Cloud
   es un panel de escritorio y el telefono es trabajo de la app;
   la razon larga esta en `en-el-telefono.js`.

   Se pinta con los tokens de siempre, asi que en modo oscuro no
   hay nada que hacer: cambia sola. */

.app-cortina {
  position: fixed;
  inset: 0;
  z-index: 9000;
  background: var(--paper);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s-6, 24px);
  overflow-y: auto;
}

.app-cortina-caja {
  width: 100%;
  max-width: 380px;
  background: var(--white);
  border-radius: var(--r-lg, 16px);
  padding: 32px 24px;
  text-align: center;
  box-shadow: var(--shadow-sm);
}

.app-cortina-nube {
  color: var(--cloud);
  margin-bottom: 18px;
}

.app-cortina-caja h1 {
  font-family: var(--display);
  font-size: 22px;
  font-weight: var(--w-bold, 700);
  color: var(--ink);
  margin: 0 0 12px;
  line-height: 1.25;
}

.app-cortina-caja p {
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-60);
  margin: 0 0 24px;
}

.app-cortina-botones {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.app-cortina-botones .btn {
  width: 100%;
  min-height: 48px;
}

/* ═══════════════════════════════════════════════════════════
   EL RECORDATORIO DE LAS FECHAS SIN PONER

   Vive en base.css y no en una hoja suya porque lo carga
   `auth-guard.js` en las 37 pantallas, y base.css es la unica
   que todas traen. Una hoja aparte seria una etiqueta mas que
   olvidar en la pantalla 38.

   Adriano el 25 agosto 2026: lo quiere molesto. Por eso el fondo
   tapa entera y no hay tache. Lo que NO se hace es gritar con
   rojo: no es un error, es trabajo pendiente, y el rojo de la
   casa esta reservado para lo que se rompio.
   ═══════════════════════════════════════════════════════════ */
.fp-fondo {
  position: fixed;
  inset: 0;
  z-index: 900;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 22px;
  background: rgba(15, 20, 25, 0.55);
  backdrop-filter: blur(3px);
  animation: fp-entra var(--d-md, .22s) ease;
}

@keyframes fp-entra { from { opacity: 0 } to { opacity: 1 } }

.fp-caja {
  width: 100%;
  max-width: 520px;
  max-height: 88vh;
  overflow-y: auto;
  background: var(--white);
  border-radius: var(--r-lg);
  box-shadow: var(--sombra-lg);
  padding: 26px 26px 20px;
}

.fp-cabeza { display: flex; gap: 13px; align-items: flex-start; margin-bottom: 18px; }
.fp-cabeza svg { color: var(--cloud); flex: none; margin-top: 2px; }

.fp-titulo {
  margin: 0 0 5px;
  font-family: var(--display);
  font-size: var(--t-lg);
  font-weight: 600;
  color: var(--black);
  letter-spacing: -0.01em;
}

.fp-sub { margin: 0; font-size: var(--t-sm); line-height: var(--lh-relaxed); color: var(--ink-60); }

.fp-lista {
  border: 1px solid var(--ink-10);
  border-radius: var(--r-md);
  overflow: hidden;
}

.fp-fila {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 14px;
  text-decoration: none;
  color: inherit;
  border-bottom: 1px solid var(--ink-10);
  transition: background var(--d-sm, .15s) ease;
}

.fp-fila:last-child { border-bottom: 0; }
.fp-fila:hover { background: var(--cloud-mist); }
.fp-fila svg { color: var(--cloud); flex: none; }
.fp-fila-texto { flex: 1; min-width: 0; }

.fp-grupo {
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--black);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.fp-porque { margin-top: 2px; font-size: var(--t-xs); color: var(--ink-60); }

.fp-proyecto {
  flex: none;
  font-size: var(--t-xs);
  color: var(--ink-50);
  text-transform: uppercase;
  letter-spacing: .06em;
}

.fp-mas { padding: 10px 14px; font-size: var(--t-xs); color: var(--ink-50); }

.fp-nota {
  margin: 12px 0 0;
  font-size: var(--t-xs);
  line-height: var(--lh-relaxed);
  color: var(--ink-50);
}

.fp-pie {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 20px;
}

@media (max-width: 560px) {
  .fp-proyecto { display: none; }
  .fp-pie { flex-direction: column-reverse; align-items: stretch; }
}
