:root {
  --azul: #1b3a8f;          /* blue from the banner's "Distribuidor Autorizado" bar */
  --azul-oscuro: #142a68;
  --azul-suave: #eef2fb;
  --amarillo: #ffcc00;
  --fondo: #eef1f6;
  --texto: #1f2937;
  --texto-suave: #5b6572;
  --borde: #d3d9e3;
  --error: #b91c1c;
  --error-suave: #fef2f2;
  --ok: #15803d;
  --radio: 14px;
  --sombra: 0 6px 24px rgba(16, 24, 40, .08);
  --sombra-alta: 0 12px 32px rgba(16, 24, 40, .12);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--fondo);
  color: var(--texto);
  font-family: "Segoe UI", Tahoma, Arial, sans-serif;
  line-height: 1.5;
  -webkit-text-size-adjust: 100%;
}

/* --------------------------------------------------------------- header
   Fondo claro a proposito: el logo Express by Sistel es oscuro y sobre el
   azul de antes se perdia por completo. */
.topbar, .header {
  background: #fff;
  border-bottom: 3px solid var(--azul);
  padding: 12px 20px;
}
.topbar-in {
  max-width: 1240px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}
.topbar-logo { display: block; flex: none; }
.topbar-logo img { display: block; width: auto; height: 38px; }
.topbar-sub {
  font-weight: 700;
  font-size: 14px;
  color: var(--azul);
  letter-spacing: .02em;
  padding-left: 14px;
  border-left: 1px solid var(--borde);
}
/* legal.ejs still uses .header with a text h1 */
.header h1 { font-size: 20px; margin: 0; color: var(--azul); }
.accent { color: var(--azul); }

/* ------------------------------------------------------------ split view */
.split {
  display: grid;
  grid-template-columns: minmax(0, 1.02fr) minmax(0, .98fr);
  align-items: start;
  gap: 26px;
  max-width: 1240px;
  margin: 26px auto;
  padding: 0 20px;
}

/* ---------------------------------------------------------- left column */
.promo { position: sticky; top: 22px; min-width: 0; }

.promo-box {
  position: relative;
  background: #fff;
  border-radius: var(--radio);
  box-shadow: var(--sombra);
  overflow: hidden;
}

/* The 3 promos stack in the same grid cell and cross-fade with opacity.
   They all share the same aspect ratio, so the box does not jump in height
   when the slide changes and nothing has to be measured in JS. */
.promo-track {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
}
.promo-slide {
  grid-area: 1 / 1;
  min-width: 0;
  opacity: 0;
  visibility: hidden;
  transition: opacity .5s ease, visibility .5s ease;
}
.promo-slide.is-active { opacity: 1; visibility: visible; }

/* contain, never cover: the banners carry legal fine print ("*Aplican
   restricciones...") pinned to the bottom edge. Cropping would cut off the
   legal disclaimer. */
.promo-slide img {
  display: block;
  width: 100%;
  height: auto;
  object-fit: contain;
}

.promo-dots {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 8px;
  padding: 12px 10px;
  background: #fff;
}
.promo-dot {
  width: 26px;
  height: 26px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  display: grid;
  place-items: center;
}
/* The visible dot is the pseudo-element; the button is 26px to give a
   decent touch target on mobile without painting a giant circle. */
.promo-dot::before {
  content: "";
  width: 9px;
  height: 9px;
  border-radius: 99px;
  background: #c3cbd9;
  transition: width .25s ease, background .25s ease;
}
.promo-dot[aria-selected="true"]::before { width: 24px; background: var(--azul); }
.promo-dot:hover::before { background: var(--azul-oscuro); }

.perks {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  margin: 14px 0 0;
  padding: 0;
}
.perks li {
  display: flex;
  align-items: center;
  gap: 9px;
  background: #fff;
  border-radius: 11px;
  padding: 11px 12px;
  box-shadow: 0 2px 8px rgba(16, 24, 40, .06);
  font-size: 12.5px;
  color: var(--texto-suave);
}
.perks strong {
  display: block;
  color: var(--texto);
  font-size: 13.5px;
  line-height: 1.25;
}
.perk-ico { width: 22px; height: 22px; flex: none; color: var(--azul); }

/* --------------------------------------------------------- right column */
.form-col { min-width: 0; }

.wrap { max-width: 1050px; margin: 24px auto; padding: 0 16px; }

.card {
  background: #fff;
  border-radius: var(--radio);
  padding: 26px;
  box-shadow: var(--sombra);
  margin-bottom: 20px;
}

.center { text-align: center; }
h1, h2 { color: var(--azul); }
.welcome h2 { color: var(--azul); margin: 0 0 10px; }

.hero-title { font-size: 24px; line-height: 1.25; margin: 0 0 6px; }
.hero-sub { margin: 0 0 18px; color: var(--texto-suave); }
.hero-sub strong { color: var(--texto); }

/* Three steps: tells the guest this will be over quickly. */
.steps {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 22px;
  padding: 14px 0 0;
  border-top: 1px solid var(--borde);
  font-size: 13px;
  color: var(--texto-suave);
}
.steps li { display: flex; align-items: center; gap: 7px; }
.steps li + li::before {
  content: "";
  width: 14px;
  height: 1px;
  background: var(--borde);
  margin-right: 1px;
}
.steps-n {
  width: 22px;
  height: 22px;
  flex: none;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--azul-suave);
  color: var(--azul);
  font-size: 12px;
  font-weight: 700;
}
.steps .is-now { color: var(--texto); font-weight: 600; }
.steps .is-now .steps-n { background: var(--azul); color: #fff; }

/* ------------------------------------------------------------------ form */
.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 18px; }
.field { min-width: 0; position: relative; margin-top: 18px; }

label { display: block; font-weight: 600; margin: 12px 0 6px; font-size: 14px; }
.lbl-opt { font-weight: 400; color: var(--texto-suave); }

input, textarea {
  width: 100%;
  border: 1px solid var(--borde);
  border-radius: 9px;
  padding: 11px 12px;
  font-size: 16px; /* 16px stops iOS from auto-zooming on focus */
  font-family: inherit;
  color: var(--texto);
  background: #fff;
  transition: border-color .15s ease, box-shadow .15s ease;
}
input::placeholder { color: #9aa3b1; }

/* ------------------------------------------------------- floating labels

   The label sits inside the field and rises on focus or once there is a
   value. It stays a real <label for>, only repositioned, so nothing changes
   for a screen reader.

   The input comes BEFORE the label in the DOM so `input + label` works. The
   alternative, :has() on the wrapper, is newer than some of the phones that
   reach a captive portal, and a form whose labels overlap the text is worse
   than one that never floats them.

   Every field needs placeholder=" " -- a single space. :placeholder-shown is
   what tells an empty field from a filled one without JS, and it only matches
   when a placeholder exists. */
.field > input,
.field > textarea {
  padding: 13px 12px;
}
.field > textarea { min-height: 84px; }

.field > label {
  position: absolute;
  top: 14px;
  left: 12px;
  margin: 0;
  max-width: calc(100% - 24px);
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 15px;
  font-weight: 400;
  color: var(--texto-suave);
  white-space: nowrap;
  pointer-events: none;

  /* The white background is what notches the border once the label sits on
     top of it. Painted here, not only in the raised state, so the transition
     does not flash a box behind the resting label. */
  background: #fff;
  padding: 0 5px;
  border-radius: 3px;

  transition: top .14s ease, font-size .14s ease, color .14s ease;
}
.lbl-ico {
  width: 14px;
  height: 14px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Raised: the label straddles the top border, cutting a notch in it. `top`
   and `font-size` instead of transform, because a scaled label blurs its
   own background edge against the border it is covering. */
.field > input:not(:placeholder-shown) + label,
.field > textarea:not(:placeholder-shown) + label,
.field > input:focus + label,
.field > textarea:focus + label {
  top: -8px;
  left: 9px;
  font-size: 12px;
}
.field > input:not(:placeholder-shown) + label .lbl-ico,
.field > textarea:not(:placeholder-shown) + label .lbl-ico,
.field > input:focus + label .lbl-ico,
.field > textarea:focus + label .lbl-ico { width: 12px; height: 12px; }

.field > input:focus + label,
.field > textarea:focus + label { color: var(--azul); }

.field > input.is-invalid + label,
.field > textarea.is-invalid + label { color: var(--error); }

/* Chrome paints its own background on autofill, which would swallow the
   raised label. The inset shadow repaints white behind it. */
.field > input:-webkit-autofill {
  box-shadow: 0 0 0 100px #fff inset;
  -webkit-text-fill-color: var(--texto);
}
input:hover, textarea:hover { border-color: #b9c2d0; }
input:focus, textarea:focus {
  outline: none;
  border-color: var(--azul);
  box-shadow: 0 0 0 3px rgba(27, 58, 143, .16);
}
textarea { resize: vertical; display: block; }

/* Per-field message. Zero height when empty so the form does not jump. */
.field-msg {
  margin: 4px 0 0;
  font-size: 12.5px;
  line-height: 1.35;
  color: var(--error);
  min-height: 1px;
}
.field-msg:empty { margin: 0; }
input.is-invalid, textarea.is-invalid { border-color: var(--error); }
input.is-invalid:focus { box-shadow: 0 0 0 3px rgba(185, 28, 28, .15); }

.check {
  display: flex;
  gap: 11px;
  align-items: flex-start;
  margin: 16px 0 0;
}
.check input {
  width: 22px;
  height: 22px;
  flex: none;
  margin: 1px 0 0;
  accent-color: var(--azul);
  cursor: pointer;
}
.check label { margin: 0; font-weight: 400; font-size: 14px; cursor: pointer; }
.check a, .legal a { color: var(--azul); font-weight: 600; }
.check-msg { margin-left: 33px; }
.req { color: var(--error); font-weight: 600; }
.opt { display: block; font-size: 12.5px; color: var(--texto-suave); margin-top: 2px; }

button, .btn {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  width: 100%;
  margin-top: 22px;
  border: 0;
  border-radius: 10px;
  padding: 14px;
  background: var(--azul);
  color: #fff;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: .04em;
  font-family: inherit;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background .15s ease, transform .06s ease, box-shadow .15s ease;
}
button:hover, .btn:hover { background: var(--azul-oscuro); box-shadow: var(--sombra-alta); }
button:active, .btn:active { transform: translateY(1px); }
button:disabled { opacity: .8; cursor: wait; }

/* Spinner: hidden until the form is actually submitted. */
.btn-spin { display: none; width: 16px; height: 16px; flex: none; }
button.is-sending .btn-spin {
  display: block;
  border: 2px solid rgba(255, 255, 255, .4);
  border-top-color: #fff;
  border-radius: 50%;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Visible, consistent focus ring for keyboard use. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
.promo-dot:focus-visible {
  outline: 3px solid var(--azul);
  outline-offset: 2px;
}

.alert {
  display: flex;
  gap: 11px;
  align-items: flex-start;
  background: var(--error-suave);
  border: 1px solid #fca5a5;
  border-left: 4px solid var(--error);
  color: #7f1d1d;
  border-radius: 10px;
  padding: 13px 14px;
  margin-bottom: 18px;
  font-size: 14px;
}
.alert-ico { width: 20px; height: 20px; flex: none; color: var(--error); margin-top: 1px; }
.alert ul { margin: 5px 0 0; padding-left: 18px; }

.trust {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  font-size: 12.5px;
  color: var(--texto-suave);
  margin: 18px 0 0;
  text-align: center;
}
.trust-ico { width: 16px; height: 16px; flex: none; color: var(--ok); }

.small { font-size: 13px; color: var(--texto-suave); text-align: center; margin-top: 12px; }
.small a { color: var(--azul); }

.legal p { line-height: 1.6; }

/* Honeypot: out of sight but reachable by bots that read the DOM. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ------------------------------------------------- sticky CTA (mobile only)

   Hidden by default, shown only in one-column layout. `visibility: hidden`
   rather than `display: none` so the browser keeps it out of the tab order
   while hidden but can still animate it in. */
.cta-flotante {
  position: fixed;
  /* Full width, inset to line up with the cards rather than floating loose:
     a wide target is easier to hit with a thumb, and the guest reads it as
     part of the page instead of an ad overlay. The inset matches .split's
     padding at each breakpoint. */
  left: 20px;
  right: 20px;
  transform: translateY(8px);
  bottom: calc(14px + env(safe-area-inset-bottom, 0px));
  z-index: 50;

  display: none;
  align-items: center;
  justify-content: center;
  gap: 8px;

  padding: 15px 22px;
  border-radius: 99px;
  background: var(--azul);
  color: #fff;
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
  /* As a flex container the text becomes an anonymous item that happily wraps,
     and the pill grew to two lines on a 375px screen. */
  white-space: nowrap;
  box-shadow: 0 6px 20px rgba(27, 58, 143, .35);

  opacity: 0;
  visibility: hidden;
  transition: opacity .2s ease, transform .2s ease, visibility .2s;
}
.cta-flotante svg { width: 18px; height: 18px; }
.cta-flotante:active { background: var(--azul-oscuro); }

/* form.js quita esta clase cuando el formulario entra en pantalla. */
.cta-flotante.is-visible {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

/* The anchor target must clear the sticky topbar, or the heading lands under it. */
#registro { scroll-margin-top: 16px; }

html { scroll-behavior: smooth; }

/* ------------------------------------------------------------ responsive */

/* Stacks before the column gets so narrow that the banners' fine print
   becomes unreadable. */
@media (max-width: 960px) {
  .cta-flotante { display: flex; }
  .split {
    grid-template-columns: 1fr;
    gap: 18px;
    margin: 16px auto;
  }
  .promo { position: static; }
  .card { padding: 22px; }
  .hero-title { font-size: 21px; }
}

@media (max-width: 620px) {
  .grid { grid-template-columns: 1fr; }
  .wrap { margin: 12px auto; }
  .split { padding: 0 12px; gap: 14px; }
  .cta-flotante { left: 12px; right: 12px; }
  .card { padding: 18px; border-radius: 12px; }
  .topbar, .header { padding: 10px 14px; }
  .topbar-logo img { height: 30px; }
  .topbar-sub { font-size: 12px; padding-left: 10px; }
  .header h1 { font-size: 16px; }
  .perks { grid-template-columns: 1fr; gap: 7px; }
  .perks li { padding: 9px 11px; }
  .steps { font-size: 12px; }
  .steps li + li::before { width: 8px; }
}

/* The captive portal mini-browser (CNA) opens a short window: there the form
   is what's urgent and the advertising must not eat the screen.

   DOM order puts the advertising first, which is right in two columns. In one
   column with little height the guest would have to scroll to find the form,
   and whoever does not scroll does not sign up. `order` flips it without
   touching the DOM, so desktop is unaffected. */
@media (max-height: 560px) and (max-width: 960px) {
  .perks { display: none; }
  /* Here the form is already first, so the CTA would only cover fields. */
  .cta-flotante { display: none; }
  .split { display: flex; flex-direction: column; }
  .form-col { order: 1; }
  .promo    { order: 2; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
  html { scroll-behavior: auto; }
}

/* ----------------------------------------------------------------- panel
   Only /admin uses this. The guest never has any use for these rules, but
   they live in the same file to avoid a second stylesheet request (and to
   leave the CSP alone). */

.wrap-ancho { max-width: 1100px; }
.wrap-angosto { max-width: 460px; }

.kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 12px;
  margin: 16px 0;
}
.kpi {
  background: var(--bg-soft, #f6f7f9);
  border: 1px solid var(--border, #e3e6ea);
  border-radius: 10px;
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.kpi-num { font-size: 28px; font-weight: 700; line-height: 1.1; }
.kpi-lbl { font-size: 13px; color: var(--muted, #666); }

.dos-col {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 16px;
}

.tabla { width: 100%; border-collapse: collapse; font-size: 14px; }
.tabla th, .tabla td {
  text-align: left;
  padding: 7px 10px;
  border-bottom: 1px solid var(--border, #e3e6ea);
}
.tabla th { font-size: 12px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted, #666); }
.tabla td.num { text-align: right; font-variant-numeric: tabular-nums; }
.tabla .mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 13px; }

/* Wide table on a small screen: scrolls inside itself, not the document. */
.tabla-scroll { overflow-x: auto; }

.tabla-barras .barra-td { width: 40%; padding-right: 0; }
.barra {
  display: block;
  height: 9px;
  border-radius: 5px;
  background: var(--acento, #6d50cc);
  min-width: 2px;
}

.tag {
  display: inline-block;
  font-size: 11px;
  padding: 1px 6px;
  border-radius: 999px;
  background: #fdecec;
  color: #a11;
  vertical-align: middle;
}

.btn-sec { background: transparent; color: inherit; border: 1px solid var(--border, #e3e6ea); }

/* A warning, not an error: signup can continue. */
.alert-aviso { background: #fff8e6; border-color: #f0d089; color: #6b4c00; }
.alert-aviso .alert-ico { color: #b58100; }
