/* ============================================================
   Dental Partners — B2B Area
   Visual style reference · Graphite × Terracotta (Light)
   Fonts: Host Grotesk (UI) + JetBrains Mono (numerals, labels)
   Mobile-first. PC breakpoint activates at ≥1024px.
   ============================================================ */

/* Los tokens viven en `tokens.css`, que la base carga ANTES que esta
   hoja. Aquí no se declara ninguno: estaban duplicados en las dos y
   cambiar uno dejaba el otro portal con el valor viejo, sin avisar. */

* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { background: #EDE5D7; min-height: 100vh; }

body {
  font-family: var(--font-ui);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  font-feature-settings: "ss01", "ss03", "cv11";
  display: grid;
  place-items: center;
  padding: 24px 12px 60px;
}

button { font-family: inherit; }
a { color: inherit; text-decoration: none; }

/* --- mockup stage (sólo referencia visual, se elimina en prod) --- */
.stage { width: 100%; max-width: 420px; }
.stage-label {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--muted);
  text-align: center;
  margin-bottom: 14px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.stage-label span { color: var(--terracotta); }

.app {
  background: var(--bg);
  border-radius: 34px;
  overflow: hidden;
  position: relative;
  box-shadow:
    0 0 0 1px rgba(43, 36, 32, 0.06),
    0 30px 60px -20px rgba(176, 74, 46, 0.18),
    0 12px 30px -10px rgba(43, 36, 32, 0.14);
  /* La card debe llenar el viewport disponible aunque la vista no
     tenga contenido. body padding mobile = 24px + 60px = 84px. */
  width: 100%;
  max-width: 420px;
  min-height: calc(100dvh - 84px);
  display: flex;
  flex-direction: column;
}

/* Contenedor del bloque content: crece y empuja el tabbar al fondo
   en vistas con poco contenido (p. ej. liquidaciones vacía). */
.app-main {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-width: 0;
  position: relative;
  z-index: 1;
}

/* Empty state aislado: se centra en el espacio sobrante de la card
   en lugar de quedar flotando justo bajo el hero. */
.app-main > .empty-state:last-child {
  margin-top: auto;
  margin-bottom: auto;
}

/* Ambient warmth — subtle terracotta haze at top */
.app::before {
  content: "";
  position: absolute;
  top: -60px; left: 50%;
  transform: translateX(-50%);
  width: 320px; height: 280px;
  background:
    radial-gradient(ellipse at 45% 60%, rgba(176, 74, 46, 0.09), transparent 60%),
    radial-gradient(ellipse at 70% 40%, rgba(201, 130, 31, 0.06), transparent 55%);
  pointer-events: none;
  z-index: 0;
}

/* ============================================================
   TOP BAR
   ============================================================ */
.topbar {
  position: relative;
  z-index: 2;
  padding: 18px 20px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
}
.brand-mark {
  width: 30px; height: 30px;
  border-radius: 9px;
  background: linear-gradient(135deg, var(--terracotta) 0%, var(--ochre) 100%);
  display: grid;
  place-items: center;
  color: var(--terracotta-foreground);
  font-weight: 700;
  font-size: 13px;
  box-shadow:
    0 0 0 1px rgba(176, 74, 46, 0.25),
    0 6px 16px -4px rgba(176, 74, 46, 0.35);
}
.brand-mark--img {
  width: 36px; height: 36px;
  border-radius: 10px;
  background: transparent;
  box-shadow: 0 4px 14px -6px rgba(46, 38, 34, 0.35);
  object-fit: contain;
  display: block;
}
.brand-name {
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text);
}
.brand-name em {
  color: var(--muted);
  font-style: normal;
  font-weight: 400;
}

.topbar-actions {
  display: flex;
  gap: 8px;
  align-items: center;
}
.icon-btn {
  width: 36px; height: 36px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-2);
  display: grid;
  place-items: center;
  cursor: pointer;
  position: relative;
  transition: border-color 0.18s ease, background 0.18s ease;
}
.icon-btn:hover { border-color: var(--border-strong); background: var(--bg); }
.icon-btn svg { width: 18px; height: 18px; stroke-width: 1.8; }
.dot {
  position: absolute;
  top: 8px; right: 8px;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--terracotta);
  box-shadow: 0 0 10px rgba(176, 74, 46, 0.7);
}

/* ============================================================
   HERO
   ============================================================ */
.hero {
  position: relative;
  z-index: 1;
  padding: 18px 20px 24px;
}
.hero-kicker {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--terracotta);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin-bottom: 10px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.hero-kicker::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--terracotta);
  box-shadow: 0 0 8px rgba(176, 74, 46, 0.6);
}
.hero-title {
  font-size: clamp(26px, 8vw, 30px);
  line-height: 1.08;
  letter-spacing: -0.028em;
  font-weight: 500;
  margin-bottom: 8px;
  color: var(--text);
}
.hero-title em {
  font-style: normal;
  background: linear-gradient(90deg, var(--terracotta), var(--ochre));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-weight: 600;
}
.hero-sub {
  font-size: 13.5px;
  color: var(--text-2);
  line-height: 1.5;
}
.hero-sub + .hero-sub { margin-top: 10px; }
.hero-sub strong { color: var(--text); font-weight: 600; }

/* ============================================================
   KPI ROW
   ============================================================ */
.kpi-row {
  padding: 0 20px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  position: relative;
  z-index: 1;
}
.kpi {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 14px 14px 16px;
  position: relative;
  overflow: hidden;
}
a.kpi {
  display: block;
  text-decoration: none;
  color: inherit;
  -webkit-tap-highlight-color: transparent;
  transition: border-color 0.2s ease, transform 0.15s ease, box-shadow 0.2s ease;
}
a.kpi:hover {
  border-color: var(--border-strong);
  transform: translateY(-1px);
  box-shadow: 0 6px 16px -10px rgba(43, 36, 32, 0.18);
}
a.kpi:active { transform: translateY(0); }
.kpi-primary {
  grid-column: span 2;
  background:
    radial-gradient(circle at top right, rgba(176, 74, 46, 0.09), transparent 55%),
    var(--surface);
  border-color: rgba(176, 74, 46, 0.22);
}
.kpi-label {
  font-family: var(--font-mono);
  font-size: 9.5px;
  color: var(--muted);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin-bottom: 8px;
}
.kpi-primary .kpi-label { color: var(--terracotta); }
.kpi-value {
  font-family: var(--font-ui);
  font-feature-settings: "tnum", "lnum";
  font-size: clamp(18px, 5.6vw, 26px);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.05;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 4px;
  color: var(--text);
  min-width: 0;
}
.kpi-primary .kpi-value {
  font-size: clamp(28px, 9vw, 38px);
  flex-wrap: nowrap;
}
.kpi-unit {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--muted);
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
}
.kpi-delta {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  margin-top: 8px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--ochre-ink);
  padding: 3px 7px;
  background: var(--ochre-soft);
  border-radius: var(--radius-sm);
  border: 1px solid rgba(201, 130, 31, 0.24);
}
.kpi-delta.danger {
  color: var(--terracotta);
  background: var(--terracotta-soft);
  border-color: rgba(176, 74, 46, 0.24);
}
.kpi-delta.success {
  color: var(--success-ink);
  background: rgba(93, 138, 46, 0.1);
  border-color: rgba(93, 138, 46, 0.24);
}
.kpi-meta {
  margin-top: 8px;
  font-size: 11px;
  color: var(--text-2);
}
.kpi-meta .hl { color: var(--terracotta); font-weight: 600; }

.progress-bar {
  margin-top: 14px;
  height: 4px;
  background: var(--surface-3);
  border-radius: 4px;
  overflow: hidden;
  position: relative;
}
.progress-fill {
  height: 100%;
  width: 62%;
  background: linear-gradient(90deg, var(--terracotta), var(--ochre));
  border-radius: 4px;
  position: relative;
  box-shadow: 0 0 8px rgba(176, 74, 46, 0.3);
}
.progress-fill::after {
  content: "";
  position: absolute;
  top: 0; right: 0;
  width: 8px; height: 100%;
  background: rgba(255, 250, 240, 0.7);
  filter: blur(4px);
}

/* ============================================================
   ALERT (CAE)
   ============================================================ */
.alert {
  margin: 14px 20px 0;
  padding: 14px 14px 14px 16px;
  background:
    linear-gradient(90deg, var(--ochre-soft), rgba(246, 226, 189, 0.2)),
    var(--surface);
  border: 1px solid rgba(201, 130, 31, 0.3);
  border-left: 3px solid var(--ochre);
  border-radius: var(--radius-md);
  display: flex;
  gap: 12px;
  align-items: center;
  position: relative;
  z-index: 1;
}
.alert.danger {
  background: linear-gradient(90deg, var(--terracotta-soft), rgba(245, 212, 196, 0.2)), var(--surface);
  border-color: rgba(176, 74, 46, 0.3);
  border-left-color: var(--terracotta);
}
.alert.danger .alert-icon { background: rgba(176, 74, 46, 0.18); color: var(--terracotta); }
.alert.danger .alert-cta { color: var(--terracotta); }

.alert-icon {
  width: 32px; height: 32px;
  flex-shrink: 0;
  border-radius: 9px;
  background: rgba(201, 130, 31, 0.2);
  color: var(--ochre-ink);
  display: grid;
  place-items: center;
}
.alert-icon svg { width: 16px; height: 16px; stroke-width: 2; }

.alert-body { flex: 1; min-width: 0; }
.alert-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  margin-bottom: 2px;
  letter-spacing: -0.005em;
}
.alert-sub {
  font-size: 11.5px;
  color: var(--text-2);
  font-family: var(--font-mono);
}

.alert-cta {
  font-size: 12px;
  color: var(--ochre-ink);
  font-weight: 700;
  background: transparent;
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}

/* ============================================================
   SECTION HEAD
   ============================================================ */
.section-head {
  padding: 26px 20px 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  position: relative;
  z-index: 1;
}
.section-title {
  font-size: 12px;
  color: var(--muted);
  font-family: var(--font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.section-link {
  font-size: 12px;
  color: var(--terracotta);
  text-decoration: none;
  display: flex;
  align-items: center;
  gap: 4px;
  font-weight: 600;
}

/* ============================================================
   RESERVAS LIST
   ============================================================ */
.reservas {
  padding: 0 20px;
  position: relative;
  z-index: 1;
}
.reserva {
  display: grid;
  grid-template-columns: 48px 1fr auto;
  gap: 14px;
  align-items: center;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  margin-bottom: 8px;
  cursor: pointer;
  transition: border-color 0.2s ease, transform 0.2s ease;
  text-decoration: none;
  color: inherit;
  min-height: var(--touch-target);
}
.reserva:hover {
  border-color: var(--border-strong);
  transform: translateX(2px);
}
.r-date-block {
  width: 48px;
  aspect-ratio: 1;
  background: var(--bg);
  border-radius: var(--radius-md);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
}
.r-day {
  font-size: 18px;
  font-weight: 600;
  line-height: 1;
  font-feature-settings: "tnum";
  letter-spacing: -0.02em;
  color: var(--text);
}
.r-month {
  font-family: var(--font-mono);
  font-size: 8.5px;
  color: var(--terracotta);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-top: 2px;
}
.r-body { min-width: 0; }
.r-time {
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 500;
  font-feature-settings: "tnum";
  color: var(--text);
  margin-bottom: 2px;
  letter-spacing: -0.01em;
}
.r-place {
  font-size: 11.5px;
  color: var(--text-2);
}
.r-place span {
  color: var(--petrol);
  font-family: var(--font-mono);
  font-size: 10.5px;
  padding: 2px 6px;
  background: var(--petrol-soft);
  border-radius: 4px;
  margin-left: 4px;
  font-weight: 500;
}
.r-arrow {
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--bg);
  color: var(--muted);
  display: grid;
  place-items: center;
  border: 1px solid var(--border);
}
.r-arrow svg { width: 10px; height: 10px; stroke-width: 2.5; }

/* ============================================================
   CTA
   ============================================================ */
.cta-wrap {
  padding: 22px 20px 24px;
  position: relative;
  z-index: 1;
}
.cta {
  width: 100%;
  min-height: 52px;
  padding: 16px 20px;
  background: linear-gradient(135deg, var(--terracotta) 0%, var(--ochre) 100%);
  color: var(--terracotta-foreground);
  border: none;
  border-radius: var(--radius-lg);
  font-family: var(--font-ui);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  box-shadow:
    0 0 0 1px rgba(255, 248, 236, 0.15) inset,
    0 10px 30px -8px rgba(176, 74, 46, 0.4),
    0 2px 8px -2px rgba(43, 36, 32, 0.14);
  transition: transform 0.2s ease;
}
.cta:active { transform: translateY(1px); }
.cta svg { width: 18px; height: 18px; stroke-width: 2.2; }

.cta-meta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-top: 10px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--muted);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.cta-meta strong { color: var(--terracotta); font-weight: 700; }

/* ============================================================
   ALTA EN CURSO (proceso de alta del colaborador en el dashboard)
   ============================================================ */
.alta-en-curso {
  padding: 0 20px;
  margin-top: 8px;
  position: relative;
  z-index: 1;
}
.alta-en-curso__head {
  padding: 26px 0 12px;
}
.alta-en-curso__kicker {
  font-size: 12px;
  color: var(--muted);
  font-family: var(--font-mono);
  letter-spacing: 0.1em;
}
.alta-en-curso__title {
  font-size: 18px;
  font-weight: 600;
  color: var(--text);
  letter-spacing: -0.01em;
  margin-top: 4px;
}
.alta-en-curso__estado {
  font-size: 13px;
  color: var(--text-2);
  margin-bottom: 12px;
}
.alta-en-curso__estado strong {
  color: var(--terracotta);
  font-weight: 700;
}
.alta-en-curso__pendientes,
.alta-en-curso__ok {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 16px;
}
.alta-en-curso__pendientes > p {
  font-size: 13px;
  color: var(--text-2);
  margin: 0 0 12px;
}
.alta-en-curso__pendientes ul {
  list-style: none;
  margin: 0 0 16px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.alta-en-curso__pendientes li {
  position: relative;
  padding-left: 22px;
  font-size: 14px;
  color: var(--text);
  line-height: 1.35;
}
.alta-en-curso__pendientes li::before {
  content: "";
  position: absolute;
  left: 4px;
  top: 7px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ochre);
}
.alta-en-curso__ok {
  font-size: 14px;
  color: var(--text-2);
  line-height: 1.4;
  border-left: 3px solid var(--terracotta);
}

/* ============================================================
   TAB BAR (bottom navigation)
   ============================================================ */
.tabbar {
  padding: 12px 8px 22px;
  background: var(--surface-2);
  border-top: 1px solid var(--border);
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 2px;
  position: relative;
  z-index: 1;
}
.tab {
  padding: 10px 0 6px;
  background: transparent;
  border: none;
  color: var(--muted);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  cursor: pointer;
  font-family: var(--font-ui);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: -0.01em;
  border-radius: var(--radius-md);
  position: relative;
  min-height: var(--touch-target);
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.tab svg { width: 20px; height: 20px; stroke-width: 1.8; }
.tab.active {
  color: var(--terracotta);
  background: var(--bg);
}
.tab.active::before {
  content: "";
  position: absolute;
  top: 0;
  width: 20px;
  height: 2px;
  background: var(--terracotta);
  border-radius: 0 0 2px 2px;
  box-shadow: 0 0 6px rgba(176, 74, 46, 0.5);
}

/* ============================================================
   PC breakpoint (≥1024px)
   ============================================================ */
@media (min-width: 1024px) {
  body { padding: 48px 24px; }
  .stage { max-width: 680px; }
  .app {
    border-radius: 28px;
    max-width: 680px;
    /* body padding PC = 48px × 2 = 96px */
    min-height: calc(100dvh - 96px);
  }
  .hero-title { font-size: 36px; }
  .kpi-primary .kpi-value { font-size: 44px; }
  .kpi-value { font-size: 26px; }
}

/* ============================================================
   Form primitives (base para futuros paso_NN)
   ============================================================ */
.form-field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
.form-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
}
.form-input {
  width: 100%;
  min-height: 48px;
  padding: 0 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 15px;
  letter-spacing: -0.005em;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.form-input:focus {
  outline: none;
  border-color: var(--terracotta);
  background: var(--bg);
  box-shadow: 0 0 0 3px rgba(176, 74, 46, 0.12);
}
.form-help { font-size: 12px; color: var(--text-2); }

/* Button variants */
.btn {
  min-height: 44px;
  padding: 10px 18px;
  border-radius: var(--radius-md);
  border: none;
  font-family: var(--font-ui);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.005em;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease;
}
.btn-primary {
  background: linear-gradient(135deg, var(--terracotta) 0%, var(--ochre) 100%);
  color: var(--terracotta-foreground);
  box-shadow: 0 6px 18px -6px rgba(176, 74, 46, 0.35);
}
.btn-primary:hover { filter: brightness(1.05); }
/* El atributo `hidden` lo pinta el navegador con `display:none`, y la
   propia `.btn` lo pisa con `inline-flex`. Sin esto, todo botón que se
   revele por JS se ve antes de que el JS decida — el «Compartir» de
   `_pdf_actions.html` salía siempre, también sin JS. */
.btn[hidden] { display: none; }
.btn-secondary { background: var(--surface); color: var(--text); border: 1px solid var(--border); }
.btn-secondary:hover { border-color: var(--border-strong); background: var(--bg); }
.btn-ghost { background: transparent; color: var(--terracotta); }
.btn-ghost:hover { background: var(--terracotta-soft); }

/* Badges */
.badge {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 4px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.badge-terracotta { background: var(--terracotta-soft); color: var(--terracotta-deep); }
.badge-ochre { background: var(--ochre-soft); color: var(--ochre-ink); }
.badge-petrol { background: var(--petrol-soft); color: var(--petrol); }
/* La píldora neutra va sobre `.doc-card`, que es `--surface`: entre esa y
   `--surface-2` hay tan poca diferencia que el estado no se leía como una
   píldora sino como texto suelto. El filete lo dibuja sin mover el hueco
   (`box-shadow` no ocupa caja, un `border` sí). */
.badge-neutral {
  background: var(--surface-2);
  color: var(--text-2);
  box-shadow: inset 0 0 0 1px var(--border-strong);
}
.badge-success { background: rgba(93, 138, 46, 0.12); color: var(--success-ink); }

/* Píldoras de estado de una cobertura entre colaboradores.
   Las plantillas escriben `class="badge badge--{{ s.estado }}"`, y la hoja
   solo declaraba las familias de color (`.badge-ochre`, `.badge-petrol`…):
   NINGUNA píldora de estado del portal recibía color. El componente existía,
   se copió y se le renombraron las partes.
   Cada estado de `EstadoSustitucion` tiene que estar aquí — lo custodia
   `tests/test_vocabulario_css.py`, que se pone rojo si se añade uno nuevo
   y se queda sin color. */
.badge--solicitada              { background: var(--ochre-soft); color: var(--ochre-ink); }
.badge--aceptada_por_sustituto  { background: var(--petrol-soft); color: var(--petrol); }
.badge--verificada              { background: rgba(93, 138, 46, 0.12); color: var(--success-ink); }
.badge--rechazada_por_sustituto { background: var(--terracotta-soft); color: var(--terracotta-deep); }
.badge--rechazada_por_gestion   { background: var(--terracotta-soft); color: var(--terracotta-deep); }
.badge--cancelada,
.badge--expirada {
  background: var(--surface-2);
  color: var(--text-2);
  box-shadow: inset 0 0 0 1px var(--border-strong);
}

/* Utility */
.hidden { display: none !important; }
.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;
}

/* Selection */
::selection { background: rgba(176, 74, 46, 0.25); color: var(--text); }

/* Focus visible — accessibility */
:focus-visible {
  outline: 2px solid var(--terracotta);
  outline-offset: 2px;
}

/* ============================================================
   CTA activar Web Push (dashboard) — oculto hasta que el JS decide
   ============================================================ */
.push-cta {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 14px 20px 0;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--terracotta);
  border-radius: var(--radius-md);
}
/* Respeta el atributo hidden por encima del display:flex de arriba. */
.push-cta[hidden] { display: none; }
.push-cta-text { display: flex; flex-direction: column; gap: 2px; flex: 1; }
.push-cta-text strong { font-size: 14px; color: var(--text); }
.push-cta-text span { font-size: 12px; color: var(--text-2); line-height: 1.35; }
.push-cta-btn {
  flex-shrink: 0;
  min-height: var(--touch-target);
  padding: 8px 18px;
  border: none;
  border-radius: var(--radius-sm);
  background: linear-gradient(135deg, var(--terracotta) 0%, var(--ochre) 100%);
  color: var(--terracotta-foreground);
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.push-cta-btn:active { transform: translateY(1px); }
.push-cta-btn:disabled { opacity: 0.6; cursor: default; }

/* ============================================================
   Calendario de disponibilidad (paso_11)
   ============================================================ */
.calendario-mes {
  padding: 0 20px 8px;
}

/* --- «Eso ya estaba comunicado» ---
   El envío que no cambiaba nada. Va en NEUTRO, deliberadamente fuera de las
   dos familias que esta pantalla usa para hablar de días —el ocre de lo que
   está en marcha y la terracota de lo que no viene—: no ha pasado nada malo y
   no hay ningún día que mirar. Pintarlo de aviso le haría buscar el error.
   Comparte la caja de `.propuesta-mes` porque ocupan el mismo sitio y nunca
   salen a la vez: al llegar aquí el borrador está ya vacío. */
.calendario-nota-envio {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin: 12px 0 4px;
  padding: 12px 14px;
  background: var(--surface-3);
  border: 1px solid var(--border);
  border-left-width: 4px;
  border-radius: var(--radius-md);
}
.calendario-nota-envio-titulo {
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
}
.calendario-nota-envio-detalle {
  font-size: 13px;
  line-height: 1.45;
  color: var(--muted);
}

/* --- Barra de la propuesta del mes (patrón declarado) ---
   Va arriba del calendario, con el mismo tono muy claro que las celdas
   propuestas para que se lea como la misma cosa a dos escalas. Su título
   dice de quién es la propuesta: es el salvavidas, no el color. */
.propuesta-mes {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 12px 0 4px;
  padding: 12px 14px;
  background: #FDF8EE;
  border: 1px solid rgba(201, 130, 31, 0.22);
  border-left-width: 4px;
  border-radius: var(--radius-md);
}
.propuesta-mes-texto {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.propuesta-mes-kicker {
  font-family: var(--font-mono);
  font-size: 10px;
  color: #7A5310;
  text-transform: uppercase;
  letter-spacing: 0.12em;
}
.propuesta-mes-titulo {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.35;
}
.propuesta-mes-titulo strong { font-weight: 800; }
/* De dónde sale la sugerencia, citando SUS meses. Va entre el título y la
   nota, y con el peso de un dato y no de una advertencia: es el argumento,
   no el aviso. La nota de «no queda comunicado» sigue siendo la última línea
   a propósito — es lo último que lee antes de pulsar. */
.propuesta-mes-eco {
  font-size: 12px;
  font-weight: 600;
  color: #7A5310;
  line-height: 1.4;
}
.propuesta-mes-nota {
  font-size: 12px;
  color: var(--text-2);
  line-height: 1.4;
}
.propuesta-mes-acciones {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

.calendar-nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 14px 0 12px;
}
.calendar-nav .btn-sm {
  min-height: 36px;
  padding: 6px 12px;
  font-size: 12px;
}
.calendar-title {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}
.calendar-title-mes {
  font-weight: 600;
  font-size: 15px;
  text-transform: capitalize;
  letter-spacing: -0.01em;
}
.calendar-title-anio {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--muted);
  letter-spacing: 0.12em;
}

/* ⚠️ `minmax(0, 1fr)` y no `1fr`, y esto es el arreglo — no una preferencia.
   `1fr` es `minmax(auto, 1fr)`, así que cada columna se niega a bajar del
   ancho mínimo de su contenido; con `aspect-ratio: 1` + `min-height: 44px` en
   la celda, ese mínimo son 44 px transferidos a lo ancho. Cuentas en un
   Galaxy S25 (360 px): 7 × 44 + 6 × 6 de hueco = 344 px contra los 296
   disponibles (360 − 12·2 del body − 20·2 de `.calendario-mes`). Sobraban 48
   px ≈ una columna exacta, y por eso el domingo caía fuera de la pantalla.
   Con `minmax(0, …)` la rejilla se reparte lo que hay y NO puede desbordar a
   ningún ancho — ni en un iPhone SE de 320 px.

   El resto son los dos milímetros que compran el tamaño de la celda sin
   quitar ningún día: hueco de 4 px y la rejilla sacando 8 px por cada lado
   del bloque (el título del mes y la barra de la propuesta se quedan
   alineados con el resto de la pantalla, que es lo que se leería mal si se
   moviera todo). Resultado medido: celdas de 41 × 44 px en 360 px de ancho,
   con los siete días dentro. La altura no se toca: el objetivo táctil sigue
   siendo 44 px por `min-height`. */
.calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 4px;
  margin-inline: -8px;
}
.calendar-header-cell {
  text-align: center;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  padding: 6px 0 8px;
}

.calendar-day {
  aspect-ratio: 1;
  min-height: var(--touch-target);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
  user-select: none;
  transition: transform 0.08s ease, background 0.12s ease, border-color 0.12s ease;
}
.calendar-day[role="button"]:hover {
  border-color: var(--border-strong);
  background: var(--bg);
}
.calendar-day[role="button"]:active {
  transform: scale(0.96);
}

.calendar-day--fuera_mes {
  background: transparent;
  border-color: transparent;
  cursor: default;
}
.calendar-day--pasado {
  opacity: 0.35;
  cursor: not-allowed;
  background: var(--surface-2);
}
.calendar-day--libre {
  background: var(--bg);
}
/* Pedido y CONCEDIDO: el día en firme. Se queda el petróleo, que era el color
   del día comprometido — lo que cambia no es el color sino de quién es el
   acto: ya no dice «lo tiene la clínica», dice «lo pediste y te lo dieron».
   El ocre que usaba `disponible_extra` se libera y vuelve a significar una
   sola cosa en esta pantalla: lo que está en marcha y aún no está resuelto
   (borrador y enviado). Dos rellenos ocres para «resuelto» y «sin resolver»
   era el ruido que hacía ilegible la diferencia que sí importa. */
.calendar-day--abierto {
  background: var(--petrol-soft);
  color: var(--petrol);
  border-color: rgba(44, 95, 93, 0.28);
}
/* Pedido y RECHAZADO. Los dos «no vienes» comparten familia de color porque
   el resultado es el mismo —ese día no viene—, pero no son la misma cosa y no
   se pintan igual: el cierre es suyo y va en relleno sólido con tachado; el
   rechazo es la respuesta de la clínica y va en hueco, con el borde marcando
   el contorno y el número en tinta fuerte.
   ⚠️ La marca ✕ es el discriminador, no el relleno: en una celda partida solo
   se ve media superficie, y ahí un relleno pálido no distingue nada. Tinta
   #8F3A22 sobre #FFF6F2 da 6.9:1 — el día que le han dicho que no es de los
   que más se mira, no puede ser el menos legible. */
.calendar-day--rechazado {
  background: #FFF6F2;
  color: #8F3A22;
  border-color: rgba(176, 74, 46, 0.45);
}
.calendar-day--rechazado .calendar-day-badge {
  font-size: 12px;
  opacity: 1;
}
.calendar-day--cerrado {
  background: var(--terracotta-soft);
  color: var(--terracotta-deep);
  border-color: rgba(176, 74, 46, 0.32);
  text-decoration: line-through;
}
/* Propuesto por SU patrón: nadie lo ha comunicado todavía.
   Relleno MUY CLARO del color de su dirección (apertura = ocre) + una marca
   pequeña. Nada de borde punteado: la celda se parte en mitades M/T y un
   patrón puede proponer solo mañanas, así que a media altura un borde no se
   lee como estado — se lee como que la celda está mal pintada, sobre todo
   junto a una mitad de relleno sólido. El borde queda para distinguir la
   celda entera (se hereda el de siempre), no el estado. */
/* ⚠️ El relleno NO es lo que distingue este estado, y saberlo evita
   "arreglarlo" subiéndolo. Medido sobre captura headless: #FDF8EE contra el
   blanco de un día libre da 1.06:1 — ruido, no superficie. Y no hay sitio para
   subirlo: apertura_pendiente ya ocupa 1.27 en la misma
   familia ocre, así que un propuesto más oscuro chocaría con ellos.
   Lo que la gente lee de verdad es la TINTA DEL NÚMERO, así que se hace buena
   a propósito: #7A5310 (la que ya usan los otros estados ocre) da 6.46:1 sobre
   su propio fondo. Con #9A7B43 daba 3.75:1 — por debajo de AA — y dejaba al
   día que EXIGE una decisión como el menos legible de la pantalla. */
.calendar-day--patron_propuesto {
  background: #FDF8EE;
  color: #7A5310;
}
/* El ◇ es el discriminador del estado, no un adorno: ni translúcido ni
   pequeño. Y la MISMA medida que en media celda — el caso difícil no puede
   llevar la marca más chica.
   ⚠️ 13px DECLARADOS renderizan ~7,3 px de glifo: U+25C7 ocupa ~56 % de su
   caja em. Medido, no estimado. Si algún día parece que "13 px es de sobra",
   el número miente en un 44 % — sube el declarado, no lo bajes. */
.calendar-day--patron_propuesto .calendar-day-badge {
  font-size: 13px;
  opacity: 1;
}
.calendar-day--apertura_propuesta {
  background: repeating-linear-gradient(
    -45deg,
    var(--ochre-soft) 0 6px,
    #fdefd0 6px 12px
  );
  color: #7a5310;
  border: 1px dashed var(--ochre);
}
.calendar-day--cierre_propuesto {
  background: repeating-linear-gradient(
    -45deg,
    var(--terracotta-soft) 0 6px,
    #f9dfd1 6px 12px
  );
  color: var(--terracotta-deep);
  border: 1px dashed var(--terracotta);
  text-decoration: line-through;
}
/* Pendiente de gestor: comunicación enviada, aún sin resolver. Mismo
   color base que la propuesta del borrador, pero con un punto en
   lugar de rayas y sin tachado para diferenciarlo. */
.calendar-day--apertura_pendiente {
  background: var(--ochre-soft);
  color: #7a5310;
  border: 1px dotted var(--ochre);
}
.calendar-day--cierre_pendiente {
  background: var(--terracotta-soft);
  color: var(--terracotta-deep);
  border: 1px dotted var(--terracotta);
}
/* La clínica no abre ese día: festivo, cierre de empresa o cierre anunciado.
   NEUTRO a propósito, fuera de la familia terracota. Los dos «no vienes» de
   esta pantalla —el cierre y el rechazo— son actos con autor: uno lo pidió él
   y el otro se lo negaron. Este no tiene autor ni decisión detrás, y pintarlo
   del mismo color lo metería en una conversación que no es la suya.
   Contraste medido: #6E5E50 sobre #EDE5D7 = 4,81:1 (AA). */
.calendar-day--clinica_cerrada {
  background: var(--surface-3);
  color: var(--muted);
  border-color: var(--border);
}
/* El HECHO, que convive con el estado en vez de sustituirlo: la celda de un
   día concedido que después se declaró festivo mantiene su petróleo y recibe
   encima esta trama. Va en un ::after y no en el `background` justamente por
   eso — un fondo la borraría, y con ella el día que él sí pidió.
   `pointer-events: none` para no comerse el hover de la celda de al lado, y
   `border-radius` heredado para no desbordar la esquina. */
.calendar-day--no-abre {
  position: relative;
  cursor: not-allowed;
}
.calendar-day--no-abre::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: inherit;
  background: repeating-linear-gradient(
    -45deg,
    rgba(110, 94, 80, 0.16) 0 2px,
    transparent 2px 6px
  );
}
/* Un trozo del día cerrado y aceptado, encima del estado que ya tiene. Va en
   ::before porque el ::after ya lo ocupa la trama de `--no-abre` y los dos
   hechos conviven: un día concedido, con la tarde recortada, que además cae en
   festivo se pinta con las tres cosas.
   La esquina y no el badge: en un día PARTIDO no se renderiza
   `.calendar-day-badge` —el número va en un círculo centrado— así que una
   marca de badge desaparecería justo en las celdas partidas, que son la mitad
   de los días con recorte. El ::before va en la esquina superior izquierda,
   donde no toca al círculo del número, y con `z-index: 2` para quedar por
   encima de él y de la trama del festivo.
   Terracota y no ocre: un recorte es un «no vienes», solo que de un trozo — lo
   pidió él y se lo aceptaron. Pintarlo en la familia de lo que está en marcha
   diría que falta por resolver. #8E3920 sobre el petróleo de `--abierto`
   (#BCD1CF), que es el caso normal, y sobre el blanco de una media celda. */
.calendar-day--con-recorte {
  position: relative;
}
.calendar-day--con-recorte::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 10px;
  height: 10px;
  z-index: 2;
  pointer-events: none;
  border-top-left-radius: inherit;
  background: linear-gradient(
    135deg,
    var(--terracotta-deep) 0 50%,
    transparent 50%
  );
}
.calendar-day--en-borrador {
  box-shadow: 0 0 0 2px rgba(176, 74, 46, 0.15);
}

.calendar-day-num {
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.calendar-day-badge {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.05em;
  opacity: 0.75;
}

/* --- Día partido: mañana arriba, tarde abajo --- */
/* Cuando estado_manana != estado_tarde, el template añade
   .calendar-day--partido y dos hijos .calendar-day-half que ocupan
   cada uno la mitad de la celda con el color de su turno. El número
   del día va superpuesto en el centro vía position:absolute. */
.calendar-day--partido {
  position: relative;
  background: transparent;
  border-color: var(--border);
  padding: 0;
  overflow: hidden;
}
.calendar-day-half {
  display: block;
  width: 100%;
  flex: 1 1 50%;
  pointer-events: none;
}
.calendar-day-half--manana {
  border-bottom: 1px dashed rgba(0, 0, 0, 0.08);
}
/* La marca del estado "propuesto" en media celda. Con relleno muy claro y
   sin badge, una mitad propuesta era indistinguible de una mitad libre; el
   ::after la marca sin tocar el borde, que es lo que no puede codificar
   estado en una celda partida. */
.calendar-day-half.calendar-day--patron_propuesto {
  position: relative;
}
.calendar-day-half.calendar-day--patron_propuesto::after {
  content: "◇";
  position: absolute;
  top: 1px;
  right: 3px;
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1;
  color: #7A5310;
}
.calendar-day-half--tarde.calendar-day--patron_propuesto::after {
  top: auto;
  bottom: 1px;
}
/* Media celda rechazada. Mismo problema que la propuesta y misma solución: su
   relleno es casi blanco, así que sin marca una mitad rechazada y una mitad
   libre son la misma superficie. El borde no sirve — a media altura no se lee
   como estado, se lee como que la celda está mal pintada. */
.calendar-day-half.calendar-day--rechazado {
  position: relative;
}
.calendar-day-half.calendar-day--rechazado::after {
  content: "✕";
  position: absolute;
  top: 1px;
  right: 3px;
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1;
  color: #8F3A22;
}
.calendar-day-half--tarde.calendar-day--rechazado::after {
  top: auto;
  bottom: 1px;
}
.calendar-day-num--partido {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 1;
  background: rgba(255, 255, 255, 0.92);
  border-radius: 50%;
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}

.calendar-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 24px;
  padding: 14px 0 4px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--muted);
  text-transform: uppercase;
}
/* Agrupada por pregunta ("cómo está el día" / "lo que has tocado tú"), no
   por color: así admite un estado más sin rehacer la maqueta. */
.legend-grupo {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-width: 150px;
}
.legend-grupo-titulo {
  color: var(--text-2);
  letter-spacing: 0.1em;
  font-weight: 600;
}
.legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  text-transform: none;
  letter-spacing: 0.02em;
}
.legend-swatch {
  width: 12px;
  height: 12px;
  border-radius: 3px;
  border: 1px solid var(--border);
}
.legend-swatch--abierto { background: var(--petrol-soft); border-color: rgba(44, 95, 93, 0.28); }
.legend-swatch--rechazado { background: #FFF6F2; border-color: rgba(176, 74, 46, 0.45); }
.legend-swatch--cerrado { background: var(--terracotta-soft); border-color: rgba(176, 74, 46, 0.32); }
/* La esquina de la celda, a escala de la muestra: el día al que SÍ viene con
   un trozo fuera. El relleno es el de `--abierto` a propósito — lo que la
   línea rotula no es un estado nuevo, es una marca que se apila sobre uno. */
.legend-swatch--con-recorte {
  background:
    linear-gradient(135deg, var(--terracotta-deep) 0 5px, transparent 5px),
    var(--petrol-soft);
  border-color: rgba(44, 95, 93, 0.28);
}
.legend-swatch--patron_propuesto {
  background: #FDF8EE;
  border-color: rgba(201, 130, 31, 0.22);
}
/* El grupo propio de la propuesta: su título es el salvavidas, no el color.
   Ocupa línea entera para que no se lea como una variante de los otros dos
   grupos. */
.legend-grupo--propuesta .legend-grupo-titulo {
  color: #7A5310;
}
.legend-swatch--apertura_propuesta {
  background: repeating-linear-gradient(-45deg, var(--ochre-soft) 0 3px, #fdefd0 3px 6px);
  border: 1px dashed var(--ochre);
}
.legend-swatch--cierre_propuesto {
  background: repeating-linear-gradient(-45deg, var(--terracotta-soft) 0 3px, #f9dfd1 3px 6px);
  border: 1px dashed var(--terracotta);
}
.legend-swatch--apertura_pendiente {
  background: var(--ochre-soft);
  border: 1px dotted var(--ochre);
}
.legend-swatch--cierre_pendiente {
  background: var(--terracotta-soft);
  border: 1px dotted var(--terracotta);
}
.legend-swatch--clinica_cerrada {
  background:
    repeating-linear-gradient(-45deg, rgba(110, 94, 80, 0.22) 0 2px, transparent 2px 5px),
    var(--surface-3);
  border-color: var(--border-strong);
}

/* --- Borrador de comunicación --- */
.borrador {
  margin: 12px 20px 24px;
  padding: 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.borrador-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}
.borrador-kicker {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.12em;
}
.borrador-contador {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--terracotta-deep);
  font-weight: 600;
}
/* --- Resumen del borrador (2026-08-15) ---------------------------------
   Lo primero que se lee antes de enviar: cuántos días de cada tipo, y que
   son días SUELTOS. El listado de gestión los pinta como "desde → hasta"
   y eso se leyó como un cierre de quince días.                          */
.borrador-resumen {
  margin: 0 0 10px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--bg);
  border: 1px solid var(--border);
  font-size: 13px;
  line-height: 1.5;
  color: var(--text);
}
.borrador-resumen-cierre { color: var(--terracotta-deep); }
.borrador-resumen-apertura { color: #7a5310; }
.borrador-aviso-mixto {
  margin: 0 0 10px;
  padding: 10px 12px;
  border-radius: var(--radius-md);
  border-left: 3px solid var(--terracotta);
  background: var(--terracotta-soft);
  font-size: 13px;
  line-height: 1.45;
  color: var(--text);
}
.borrador-aviso-mixto strong { color: var(--terracotta-deep); }

/* Gestor viendo el portal "como colaborador": lo que envíe queda a su
   nombre. Tiene que verlo antes de pulsar, no en el registro después. */
.borrador-aviso-impersonando {
  margin: 0 0 10px;
  padding: 10px 12px;
  border-radius: var(--radius-md);
  border: 1px dashed var(--ochre, #c9821f);
  background: var(--ochre-soft);
  font-size: 13px;
  line-height: 1.45;
  color: var(--text);
}
.borrador-aviso-impersonando strong { color: #7a5310; }

.borrador-lista {
  list-style: none;
  margin: 8px 0 14px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
/* ⚠️ Era `justify-content: space-between` SIN `flex-wrap`. En 360 px las tres
   piezas —fecha, chip de franja y tipo— no caben en una línea, así que en vez
   de bajar de renglón se estrujaban y partían su propio texto por dentro:
   «mié / 16/09/2026» a dos líneas con el chip «COMPLETO» encabalgado sobre
   «abrir / disponibilidad». Reportado desde un móvil el 2026-08-21.

   Envuelve, con gap, y las dos piezas cortas se declaran `nowrap` para que lo
   que baje de línea sea el bloque entero y nunca la mitad de una fecha. */
.borrador-item {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 8px;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  border: 1px solid var(--border);
  background: var(--bg);
}
.borrador-item--apertura { border-color: rgba(201, 130, 31, 0.35); }
.borrador-item--cierre { border-color: rgba(176, 74, 46, 0.35); }
.borrador-fecha {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--text-2);
  white-space: nowrap;
}
.borrador-tipo {
  font-weight: 600;
}
.borrador-acciones {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}
.borrador-empty {
  font-size: 13px;
  color: var(--muted);
  margin: 4px 0 2px;
}

/* --- Borrador: chip de turno en cada item --- */
.borrador-turno {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text-2);
  white-space: nowrap;
}
.borrador-turno--completo {
  background: var(--surface);
  border-color: var(--border-strong);
}
.borrador-turno--M {
  background: #fff8e6;
  border-color: rgba(201, 130, 31, 0.32);
  color: #7a5310;
}
.borrador-turno--T {
  background: #f0e8ff;
  border-color: rgba(120, 80, 180, 0.32);
  color: #4a3270;
}
.borrador-turno--custom {
  background: var(--terracotta-soft);
  border-color: rgba(176, 74, 46, 0.35);
  color: var(--terracotta-deep);
  font-family: var(--font-mono);
  text-transform: none;
  letter-spacing: 0;
}

/* ============================================================
   Bottom-sheet selector de turno (paso_11.1)
   ============================================================ */
.dia-selector-root {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  pointer-events: none;
}
.dia-selector-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(20, 16, 14, 0.45);
  cursor: pointer;
  pointer-events: auto;
  animation: dia-selector-fade 0.16s ease-out;
}
.dia-selector-sheet {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 520px;
  background: var(--bg);
  border-top-left-radius: 18px;
  border-top-right-radius: 18px;
  box-shadow: 0 -12px 32px rgba(0, 0, 0, 0.18);
  padding: 16px 20px 24px;
  pointer-events: auto;
  animation: dia-selector-rise 0.22s cubic-bezier(0.2, 0.7, 0.2, 1);
  max-height: 85vh;
  overflow-y: auto;
}
@media (min-width: 720px) {
  .dia-selector-root {
    align-items: center;
  }
  .dia-selector-sheet {
    border-radius: 14px;
    padding: 20px 24px;
    max-width: 480px;
  }
}
@keyframes dia-selector-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes dia-selector-rise {
  from { transform: translateY(24px); opacity: 0; }
  to   { transform: translateY(0); opacity: 1; }
}
.dia-selector-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 12px;
}
.dia-selector-kicker {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  margin-bottom: 4px;
}
.dia-selector-titulo {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-transform: capitalize;
}
.dia-selector-cerrar {
  background: transparent;
  border: none;
  width: 36px;
  height: 36px;
  font-size: 22px;
  line-height: 1;
  color: var(--muted);
  cursor: pointer;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.dia-selector-cerrar:hover {
  background: var(--surface-2);
  color: var(--text);
}

.dia-selector-actual {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  margin-bottom: 14px;
}
.dia-selector-actual-kicker {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.12em;
}
.dia-selector-actual-lista {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 13px;
}
.dia-selector-actual-item {
  min-width: 0;
  overflow-wrap: anywhere;
}
.dia-selector-actual-item--apertura strong { color: #7a5310; }
.dia-selector-actual-item--cierre strong { color: var(--terracotta-deep); }

.dia-selector-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
/* --- Situación del día (2026-08-15) ------------------------------------
   Lo primero del sheet: en qué estado está el día y quién lo puso ahí. El
   colaborador no elige entre dos opciones simétricas — cambia un día que
   ya tiene estado, y en 192 de 204 días futuros ese estado lo puso el
   cuadrante de OdontoHR, no él.                                          */
.dia-selector-situacion {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 12px 14px;
  border-radius: var(--radius-md);
  border-left: 4px solid var(--border-strong);
  background: var(--bg);
  margin-bottom: 4px;
}
.dia-selector-situacion--viene {
  border-left-color: var(--petrol, #2c5f5d);
  background: var(--petrol-soft);
}
.dia-selector-situacion--no-viene {
  border-left-color: var(--terracotta);
  background: var(--terracotta-soft);
}
.dia-selector-situacion--indefinida {
  border-left-color: var(--ochre, #c9821f);
  background: var(--ochre-soft);
}
.dia-selector-situacion-titulo {
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  line-height: 1.3;
}
.dia-selector-situacion-detalle {
  font-size: 12.5px;
  color: var(--text-2);
  line-height: 1.4;
}

/* --- Bloques de intención (2026-08-15) ---------------------------------
   Sustituyen al radio "tipo" que venía preseleccionado en "apertura". El
   tipo ya no es estado invisible del formulario: vive en el botón que se
   pulsa. Cada bloque se pinta de su color y lo dice con palabras, para
   que la elección sea legible sin leer el diálogo entero.               */
.dia-selector-intencion {
  border: 1px solid var(--border);
  border-left-width: 4px;
  border-radius: var(--radius-md);
  padding: 12px;
  background: var(--bg);
}
.dia-selector-intencion + .dia-selector-intencion {
  margin-top: 4px;
}
.dia-selector-intencion--apertura { border-left-color: var(--ochre, #c9821f); }
.dia-selector-intencion--cierre { border-left-color: var(--terracotta); }
/* La acción que NO cambia el día sigue disponible, pero no compite: si
   las dos pesan igual visualmente, se pulsa la contraria. */
.dia-selector-intencion--secundaria {
  opacity: 0.62;
  background: transparent;
}
.dia-selector-intencion--secundaria:hover,
.dia-selector-intencion--secundaria:focus-within {
  opacity: 1;
}
.dia-selector-intencion--secundaria .dia-selector-intencion-titulo {
  font-size: 13px;
}
.dia-selector-intencion--secundaria .dia-selector-turno-btn {
  min-height: 56px;
}
.dia-selector-intencion-head {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-bottom: 10px;
}
.dia-selector-intencion-titulo {
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
}
.dia-selector-intencion--apertura .dia-selector-intencion-titulo { color: #7a5310; }
.dia-selector-intencion--cierre .dia-selector-intencion-titulo { color: var(--terracotta-deep); }
.dia-selector-intencion-sub {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.12em;
}
.dia-selector-intencion--apertura .dia-selector-turno-btn:hover {
  border-color: var(--ochre, #c9821f);
}
.dia-selector-intencion--apertura .dia-selector-turno-icon { color: var(--ochre, #c9821f); }
.dia-selector-intencion--cierre .dia-selector-turno-btn:hover {
  border-color: var(--terracotta);
}
.dia-selector-intencion--cierre .dia-selector-turno-icon { color: var(--terracotta); }

/* --- El tercer par: confirmar / descartar la propuesta del patrón --- */
.dia-selector-intencion--propuesta {
  border-left-color: rgba(201, 130, 31, 0.45);
  background: #FDF8EE;
}
.dia-selector-intencion--propuesta .dia-selector-intencion-titulo {
  color: #7A5310;
}
.dia-selector-propuesta-lista {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.dia-selector-propuesta-item {
  display: grid;
  grid-template-columns: 1fr;
  gap: 6px;
}
.dia-selector-propuesta-franja {
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
}
.dia-selector-propuesta-apoyo {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.1em;
}
.dia-selector-propuesta-botones {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.dia-selector-turno-btn--confirmar {
  background: var(--bg);
  border-color: rgba(201, 130, 31, 0.35);
}
.dia-selector-turno-btn--confirmar .dia-selector-turno-icon {
  color: var(--ochre, #c9821f);
}
.dia-selector-turno-btn--descartar .dia-selector-turno-icon {
  color: var(--muted);
}
.dia-selector-propuesta-nota {
  margin-top: 10px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--text-2);
}

.dia-selector-aviso-citas {
  background: rgba(201, 130, 31, 0.10);
  border-left: 3px solid var(--ochre, #c9821f);
  padding: 10px 12px;
  border-radius: var(--radius-md);
  margin: 8px 0 4px;
  font-size: 13px;
  color: var(--text);
  line-height: 1.4;
}
.dia-selector-aviso-citas strong { color: var(--ochre, #c9821f); }

/* `auto-fit` y no `repeat(3, …)`: un día que solo abre por la mañana no pinta
   el botón de tarde, y con tres columnas fijas quedaría un hueco que se lee
   como un botón que falta. `minmax(0, 1fr)` para que el rango horario no
   ensanche la columna. */
.dia-selector-turnos-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
  gap: 8px;
}
.dia-selector-turno-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: 78px;
  padding: 10px 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  transition: transform 0.08s ease, background 0.12s ease,
              border-color 0.12s ease;
}
.dia-selector-turno-btn:hover {
  border-color: var(--border-strong);
  background: var(--bg);
}
.dia-selector-turno-btn:active {
  transform: scale(0.97);
}
.dia-selector-turno-icon {
  font-size: 22px;
  line-height: 1;
}
.dia-selector-turno-label {
  font-size: 12px;
  text-align: center;
}
/* El rango real de la clínica ese día, bajo el rótulo del turno. Va en la
   tipografía de datos y en tono apagado: informa de hasta cuándo abre el día
   que se está pulsando, no compite con el rótulo. */
.dia-selector-turno-horas {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  line-height: 1;
  color: var(--muted);
  white-space: nowrap;
}

.dia-selector-acciones-secundarias {
  display: flex;
  justify-content: center;
  margin-top: 4px;
}

/* --- Acordeón "Personalizar horario" (Fase 2) --- */
.dia-selector-custom {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
  overflow: hidden;
}
.dia-selector-custom[open] {
  border-color: var(--terracotta);
  background: var(--bg);
}
.dia-selector-custom-summary {
  list-style: none;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  user-select: none;
}
.dia-selector-custom-summary::-webkit-details-marker { display: none; }
.dia-selector-custom-summary::before {
  content: "▸";
  font-size: 11px;
  color: var(--muted);
  width: 12px;
  display: inline-block;
  transition: transform 0.15s ease;
}
.dia-selector-custom[open] .dia-selector-custom-summary::before {
  transform: rotate(90deg);
}
.dia-selector-custom-icon {
  font-size: 16px;
  line-height: 1;
}
.dia-selector-custom-label { flex: 1; }
.dia-selector-custom-hint {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 400;
}
.dia-selector-custom-body {
  padding: 4px 14px 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* Un grupo por tramo (Todo el día · Mañana · Tarde). Cada uno con sus horas
   y sus dos botones: es lo que permite decir un horario por la mañana y otro
   por la tarde, que con un solo par de campos era imposible.
   El filete de separación va con `border-top` en los siguientes y no con `gap`
   a secas, para que se lea que son bloques distintos y no una lista de campos
   sueltos: en un móvil, seis campos seguidos sin corte se leen como uno. */
.dia-selector-custom-intro {
  margin: 0;
  font-size: 12px;
  line-height: 1.4;
  color: var(--text-2);
}
.dia-selector-custom-grupo {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.dia-selector-custom-grupo + .dia-selector-custom-grupo {
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.dia-selector-custom-grupo-titulo {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}
.dia-selector-custom-inputs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.dia-selector-custom-input {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.dia-selector-custom-input span {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.1em;
}
.dia-selector-custom-input input[type="time"] {
  min-height: 44px;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg);
  font-family: var(--font-mono);
  font-size: 16px;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.dia-selector-custom-input input[type="time"]:focus {
  outline: 2px solid var(--terracotta);
  outline-offset: 1px;
  border-color: var(--terracotta);
}
/* Dos botones, uno por intención: el rango horario tampoco hereda un tipo
   por defecto. */
.dia-selector-custom-acciones {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.dia-selector-custom-aplicar {
  min-height: 44px;
  padding: 10px 14px;
  color: #fff;
  border-radius: var(--radius-md);
  cursor: pointer;
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.02em;
  transition: transform 0.08s ease, background 0.12s ease;
}
.dia-selector-custom-aplicar--apertura {
  background: var(--ochre, #c9821f);
  border: 1px solid #7a5310;
}
.dia-selector-custom-aplicar--apertura:hover { background: #7a5310; }
.dia-selector-custom-aplicar--cierre {
  background: var(--terracotta);
  border: 1px solid var(--terracotta-deep);
}
.dia-selector-custom-aplicar--cierre:hover { background: var(--terracotta-deep); }
.dia-selector-custom-aplicar:active {
  transform: scale(0.98);
}
.dia-selector-custom-nota {
  margin: 0;
  font-size: 11px;
  color: var(--muted);
  line-height: 1.4;
}
.dia-selector-custom-nota em {
  color: var(--text-2);
  font-style: normal;
  font-weight: 500;
}

/* ============================================================
   El panel de gestión B2B se rehízo con el vocabulario `.g-*` de
   `gestion.css`, y las ~200 líneas de `.gestion-*` que había aquí se
   quedaron sin una sola plantilla que las escribiese: 23 clases —lista,
   detalle, chips, totales y buscador— que viajaban en CADA petición del
   portal del colaborador, que además nunca fue quien las usaba.
   Retiradas el 2026-08-22; están en el historial de git.
   ============================================================ */

/* ============================================================
   RECRUITMENT B2B — Colaboraciones (público móvil)
   Añadido por la mini-app dentalpartners_recruitment.
   ============================================================ */

.recruit-public-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 20px;
  border-bottom: 1px solid var(--surface-3, #EDE5D7);
  background: var(--bg, #FFFFFF);
}
.recruit-public-brand {
  display: flex; align-items: center; gap: 10px;
  text-decoration: none; color: inherit;
}
.recruit-public-brand-mark {
  width: 32px; height: 32px; border-radius: 9px;
  background: linear-gradient(135deg, #B04A2E 0%, #C9821F 100%);
  color: #FFE9DA; display: grid; place-items: center;
  font-weight: 700; font-size: 14px;
}
.recruit-public-brand-text {
  font-weight: 600; font-size: 16px;
  font-family: "Host Grotesk", system-ui, sans-serif;
}
.recruit-public-claim {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.12em;
  color: #B04A2E;
}

.recruit-public-main {
  max-width: 720px; margin: 0 auto; padding: 24px 20px 80px;
}

.recruit-public-hero {
  padding: 24px 0 18px;
  border-bottom: 1px solid var(--surface-3, #EDE5D7);
}
.recruit-public-hero h1 {
  font-size: 28px; font-weight: 700; margin-bottom: 10px;
  color: #1A1412;
}
.recruit-public-lead {
  font-size: 16px; color: #5A4A42; line-height: 1.5;
}

.recruit-public-grid {
  display: grid; grid-template-columns: 1fr; gap: 12px;
  margin-top: 18px;
}
@media (min-width: 720px) {
  .recruit-public-grid { grid-template-columns: 1fr 1fr; }
}

.recruit-oferta-card {
  display: block; padding: 16px;
  background: var(--bg, #FFFFFF);
  border: 1px solid var(--surface-3, #EDE5D7);
  border-left: 3px solid #B04A2E;
  border-radius: 10px;
  text-decoration: none; color: inherit;
  transition: transform 0.1s ease, box-shadow 0.1s ease;
}
.recruit-oferta-card:active { transform: scale(0.99); }
.recruit-oferta-card-kicker {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em;
  color: #9B8B7D; margin-bottom: 6px;
}
.recruit-oferta-card h2 {
  font-size: 17px; font-weight: 600; margin-bottom: 6px;
  color: #1A1412;
}
.recruit-oferta-card-desc {
  font-size: 14px; color: #5A4A42; line-height: 1.45;
}
.recruit-oferta-card-cta {
  margin-top: 10px; font-size: 13px; font-weight: 600;
  color: #B04A2E;
}

.recruit-public-empty {
  margin-top: 30px; padding: 24px; text-align: center;
  color: #9B8B7D;
  background: var(--surface, #FBF8F3);
  border-radius: 10px;
}

/* --- Detalle / artículo --- */
.recruit-public-article h1 {
  font-size: 26px; font-weight: 700; margin: 8px 0 14px;
  color: #1A1412;
}
.recruit-public-back {
  display: inline-block; font-size: 13px; color: #B04A2E;
  text-decoration: none; margin-bottom: 8px;
}
.recruit-public-kicker {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em;
  color: #9B8B7D;
}
.recruit-public-section {
  padding: 16px 0; border-top: 1px solid var(--surface-3, #EDE5D7);
}
.recruit-public-section h2 {
  font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em;
  color: #2C5F5D; margin-bottom: 8px;
}
.recruit-public-section p {
  font-size: 15px; line-height: 1.6; color: #1A1412; margin-bottom: 8px;
}
.recruit-public-cta-section {
  margin-top: 24px; padding: 20px;
  background: var(--surface, #FBF8F3); border-radius: 10px;
  text-align: center;
}
.recruit-public-cta {
  display: inline-block; padding: 14px 28px;
  background: #B04A2E; color: #FFE9DA;
  border-radius: 999px; text-decoration: none;
  font-weight: 600; font-size: 15px;
  border: none; cursor: pointer; min-height: 48px;
  font-family: inherit;
}
.recruit-public-cta:hover { background: #8E3920; }
.recruit-public-cta--ghost {
  background: transparent; color: #B04A2E;
  border: 1px solid #B04A2E;
}
.recruit-public-cta-note {
  font-size: 12px; color: #9B8B7D; margin-top: 12px; line-height: 1.45;
}

/* --- Form de candidatura --- */
.recruit-form fieldset {
  border: 1px solid var(--surface-3, #EDE5D7);
  border-radius: 10px; padding: 16px;
  margin: 16px 0; background: var(--bg, #FFFFFF);
}
.recruit-form legend {
  padding: 0 8px; font-size: 13px; font-weight: 600;
  color: #2C5F5D; text-transform: uppercase; letter-spacing: 0.05em;
}
.recruit-field {
  display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px;
}
.recruit-field label {
  font-size: 13px; font-weight: 600; color: #1A1412;
}
.recruit-field small {
  font-size: 12px; color: #9B8B7D;
}
.recruit-field.has-error label { color: #B04A2E; }
.recruit-error { color: #B04A2E !important; }
.recruit-input,
.recruit-form input[type="text"],
.recruit-form input[type="email"],
.recruit-form input[type="url"],
.recruit-form input[type="tel"],
.recruit-form input[type="number"],
.recruit-form input[type="file"],
.recruit-form select,
.recruit-form textarea {
  padding: 10px 12px; font-size: 15px; min-height: 44px;
  border: 1px solid var(--surface-3, #EDE5D7);
  border-radius: 8px; background: var(--surface, #FBF8F3);
  color: #1A1412; font-family: inherit;
  -webkit-appearance: none; appearance: none;
  width: 100%;
}
.recruit-form input:focus, .recruit-form select:focus, .recruit-form textarea:focus {
  outline: none; border-color: #B04A2E;
  background: var(--bg, #FFFFFF);
}

.recruit-consent {
  background: rgba(176, 74, 46, 0.06);
  border-color: rgba(176, 74, 46, 0.18);
}
.recruit-consent-row {
  display: flex; gap: 10px; align-items: flex-start;
  font-size: 14px; line-height: 1.4; color: #1A1412;
  padding: 8px 0; cursor: pointer;
}
.recruit-consent-row input[type="checkbox"] {
  margin-top: 3px; min-width: 18px; min-height: 18px;
  accent-color: #B04A2E;
}

.recruit-public-confirmation { text-align: center; padding-top: 30px; }
.recruit-public-confirmation h1 {
  color: #5D8A2E;
}
.recruit-public-rgpd {
  font-size: 12px; color: #9B8B7D; line-height: 1.5;
  margin-top: 18px; padding: 14px;
  background: var(--surface, #FBF8F3); border-radius: 8px;
}

.recruit-public-messages { list-style: none; margin: 12px 0; padding: 0; }
.recruit-public-message {
  padding: 10px 14px; border-radius: 8px; margin-bottom: 6px;
  font-size: 14px; background: var(--surface, #FBF8F3);
}
.recruit-public-message--error {
  background: rgba(176, 74, 46, 0.12);
  color: #B04A2E;
  border-left: 3px solid #B04A2E;
}

/* ============================================================
   Utilidades — extraídas de inline style="..." en templates
   (Fase 1 calidad — 2026-04-27).
   ============================================================ */

/* Section padding patterns */
.dp-section          { padding: 0 20px 24px; }
.dp-section--sm      { padding: 0 20px 8px; }

/* Buttons */
.btn--block          { width: 100%; }
.btn--mt-10          { margin-top: 10px; }
.btn--mt-18          { margin-top: 18px; }
.btn--mt-20          { margin-top: 20px; }

/* Link rows below forms */
.dp-link-row         { text-align: center; margin-top: 14px; }
.dp-link-row--lg     { text-align: center; margin-top: 18px; }

/* Section head spacing */
.section-head--mt    { margin-top: 20px; }

/* Form errors */
.form-help--error    { color: var(--terracotta); }

/* Alert spacing */
.alert--mb           { margin-bottom: 18px; }

/* Mini KPIs (perfil) — strip de 2 columnas con label/valor apilados */
.mini-kpis {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin: 4px 0 18px;
}
.mini-kpi {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  min-width: 0;
}
.mini-kpi-label {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
.mini-kpi-value {
  font-family: var(--font-ui);
  font-feature-settings: "tnum", "lnum";
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
  letter-spacing: -0.01em;
  line-height: 1.15;
  overflow-wrap: break-word;
}
.mini-kpi-value--md { font-size: 16px; }

/* Definition list (perfil) — bloque por campo con separador hairline */
.dp-dl {
  margin: 0;
  padding: 4px 0 20px;
  display: flex;
  flex-direction: column;
}
.dp-dl dt {
  margin: 0;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}
.dp-dl > dt:first-of-type {
  padding-top: 6px;
  border-top: none;
}
.dp-dl-dd {
  margin: 6px 0 14px;
  font-size: 15px;
  line-height: 1.4;
  color: var(--text);
}
.dp-dl-dd--tight {
  margin: 4px 0 12px;
  font-size: 15px;
  line-height: 1.35;
  color: var(--text);
}
.dp-dl-dd--mono {
  font-family: var(--font-mono);
  font-size: 13.5px;
  letter-spacing: 0.02em;
}
.dp-text-muted { color: var(--muted); }
.badge--ml-sm  { margin-left: 6px; }

/* Hero CAE-bloqueado variant */
.hero--blocked                   { background: var(--terracotta-soft); }
.hero--blocked .hero-kicker,
.hero--blocked .hero-title       { color: var(--terracotta-deep); }
.hero--blocked .hero-sub         { color: var(--text); }
/* Rescatada del bloque `.gestion-*` retirado: viajaba de polizón en un
   selector agrupado con él, y es del hero. */
.hero-sub .mono { font-family: var(--font-mono); letter-spacing: 0.02em; }

/* CAE bloqueado — listado de documentos críticos */
.cae-doc-list { margin-top: 16px; }
.cae-doc-block {
  padding: 12px 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  margin-bottom: 8px;
  background: var(--surface);
}
.cae-doc-block .form-help { margin-top: 4px; }

/* Banner permanente de colaboración en cierre (EN_LIQUIDACION). Va entre el
   topbar y el contenido, en todas las pantallas a las que aún llega. */
.dp-banner-cierre {
  margin: 12px 20px 0;
  padding: 12px 16px;
  border: 1px solid var(--ochre);
  border-radius: var(--radius-md);
  background: var(--ochre-soft);
}
.dp-banner-cierre-titulo {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--terracotta-deep);
}
.dp-banner-cierre-texto {
  margin: 6px 0 0;
  font-size: 13px;
  line-height: 1.4;
  color: var(--text);
}
.dp-banner-cierre-lista {
  margin: 4px 0 0;
  padding-left: 18px;
  font-size: 13px;
  line-height: 1.4;
  color: var(--text);
}

/* Bloque informativo genérico (pantallas de acceso cerrado: fin de
   colaboración, avisos sin acción asociada). Mismo cuerpo que
   .cae-doc-block pero sin atarse al dominio CAE. */
.dp-info-block {
  padding: 12px 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  margin-bottom: 8px;
  background: var(--surface);
}
.dp-info-block .form-help { margin-top: 4px; }

/* Empty list (e.g. dashboard reservas) */
/* Enlace de liquidación caducado. Es una pantalla entera con una sola
   explicación dentro, y sin esto el párrafo salía pegado al borde de la
   ventana, fuera de la sangría que tiene el resto del portal. */
.token-invalido {
  padding: 14px 20px 24px;
  font-size: 14px;
  color: var(--text-2);
  line-height: 1.55;
}
.token-invalido p { margin: 0; }

.dp-empty {
  padding: 18px;
  text-align: center;
  color: var(--muted);
  font-size: 13px;
}

/* ============================================================
   Generic helpers used by documentos/auth/upload templates
   ============================================================ */

/* Small button modifier — used for inline / toolbar actions */
.btn-sm {
  min-height: 36px;
  padding: 8px 14px;
  font-size: 13px;
  border-radius: var(--radius-sm);
}

/* Danger badge variant (CAE crítico, alertas) */
.badge-danger {
  background: var(--terracotta-soft);
  color: var(--terracotta-deep);
}

/* Mensajes de Django (messages framework) */
.messages {
  list-style: none;
  margin: 0 20px 14px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.message {
  padding: 10px 14px;
  border-radius: var(--radius-md);
  font-size: 13px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
}
.message--success {
  background: rgba(93, 138, 46, 0.08);
  border-color: rgba(93, 138, 46, 0.28);
  color: var(--success-ink);
}
.message--error,
.message--warning {
  background: var(--terracotta-soft);
  border-color: rgba(176, 74, 46, 0.32);
  color: var(--terracotta-deep);
}
.message--info {
  background: var(--petrol-soft);
  border-color: rgba(44, 95, 93, 0.28);
  color: var(--petrol);
}

/* Empty state (genérico) */
.empty-state {
  margin: 0 20px;
  padding: 22px 18px;
  text-align: center;
  color: var(--muted);
  font-size: 13px;
  background: var(--surface);
  border: 1px dashed var(--border);
  border-radius: var(--radius-md);
}

/* ============================================================
   TARJETA GENÉRICA DE LISTA  (hoy solo sustituciones/lista.html)
   ============================================================
   Se llamaba `.doc-*` porque nació en la pantalla de documentos del
   colaborador. Esa pantalla ya no la usa —es el expediente de más abajo—, y
   con ella se fueron las reglas que solo pintaban aquello: los chips de
   estado, la rejilla de metadatos y la lista de «faltantes». Dos de esos
   chips, `--vigente` y `--proximo_vencer`, NUNCA existieron: el marcado los
   escribía y la hoja no los tenía, así que los dos estados que más manda el
   sistema salían sin color y nadie lo vio.

   El nombre se queda hasta que sustituciones se reconstruya; renombrarlo hoy
   sería tocar una pantalla que nadie ha pedido.
   ============================================================ */

.doc-toolbar {
  padding: 4px 20px 14px;
  display: flex;
  justify-content: flex-start;
}

.doc-list {
  padding: 14px 20px 24px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.doc-list .section-title {
  margin-bottom: 10px;
  display: block;
}

/* Tarjeta de documento subido */
.doc-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.doc-card-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 10px;
}
.doc-card-title {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.doc-card-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

/* Las cinco de abajo las escribe `sustituciones/lista.html` y no las tenía
   nadie: el cuerpo de la tarjeta salía como texto suelto, el motivo con el
   mismo peso que la fecha, el destacado sin destacar, el estado vacío como
   un párrafo normal y «Responder» como un botón sin fondo ni color. */
.doc-card-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 14px;
  color: var(--text-2);
  min-width: 0;
}
.doc-card-note {
  font-size: 13px;
  color: var(--muted);
  overflow-wrap: anywhere;
}
/* Lo que espera respuesta del colaborador. Es la única tarjeta que le pide
   algo, y hasta hoy se pintaba igual que las de solo lectura. */
.doc-card--highlight {
  border-color: var(--terracotta);
  border-left-width: 3px;
  background: var(--bg);
}
.doc-empty {
  margin: 0;
  padding: 16px 14px;
  text-align: center;
  color: var(--muted);
  font-size: 13px;
  background: var(--surface);
  border: 1px dashed var(--border);
  border-radius: var(--radius-md);
}
/* Acción secundaria dentro de una tarjeta: se lee como enlace pero conserva
   el área de toque de un botón. */
.btn-link {
  background: transparent;
  color: var(--terracotta);
  border: 1px solid transparent;
  padding: 6px 10px;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.btn-link:hover {
  background: var(--terracotta-soft);
  text-decoration: none;
}

/* ============================================================
   EXPEDIENTE CAE DEL COLABORADOR  (documentos/listado.html)
   ============================================================
   Una línea por documento EXIGIBLE, no una por fichero subido. La pantalla
   anterior tenía dos listas sin relación —tipos que faltan y ficheros
   subidos— y de un documento concreto no se podía saber en cuál estaba. Lo
   único que decía con claridad era «BLOQUEA TU AGENDA», y encima sobre
   documentos que aún no se han subido, que es justo el caso en el que no
   bloquea nada.

   El color va por FAMILIA DE URGENCIA, no por estado: caducado y rechazado
   son terracota, «sin subir» y «caduca pronto» son ocre, «en revisión» es
   petróleo y «vigente» verde. Distinguir dentro de la familia es trabajo del
   rótulo, que es texto y se lee igual sin color — la pantalla la abre gente
   al sol, en un móvil, y el daltonismo no es una hipótesis.
   ============================================================ */

.exp-estado {
  padding: 4px 20px 18px;
}
.exp-estado-titular {
  font-size: 17px;
  font-weight: 700;
  line-height: 1.25;
  color: var(--text);
}
.exp-estado-titular--bloqueado { color: var(--terracotta-deep); }
.exp-estado-titular--ok        { color: var(--success-ink); }
.exp-estado-titular--pendiente { color: var(--ochre-ink); }
.exp-estado-detalle {
  margin-top: 4px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-2);
}

/* Cuatro cifras, no una barra de progreso: «3 de 11» no dice cuál falta ni
   qué le pasa, y el colaborador que abre esto lo hace para saber qué tiene
   que hacer HOY. `auto-fit` porque en 320 px cuatro columnas dejan la cifra
   sin sitio. */
.exp-contadores {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(70px, 1fr));
  gap: 6px;
}
.exp-contador {
  padding: 8px 6px;
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: 3px solid var(--border-strong);
  border-radius: var(--radius-md);
}
.exp-contador--vigente     { border-top-color: var(--success); }
.exp-contador--en_revision { border-top-color: var(--petrol); }
.exp-contador--caducado    { border-top-color: var(--terracotta-deep); }
.exp-contador--sin_subir   { border-top-color: var(--ochre); }
.exp-contador-num {
  display: block;
  font-family: var(--font-mono);
  font-size: 19px;
  font-weight: 700;
  line-height: 1.1;
  color: var(--text);
}
.exp-contador-label {
  display: block;
  margin-top: 2px;
  font-size: 10.5px;
  line-height: 1.2;
  color: var(--text-2);
}

.exp-subir { margin-top: 14px; }

/* ============================================================
   ESPECIALIDADES DECLARADAS — solo lectura, y por eso no parece un control
   ------------------------------------------------------------
   Lo que trata el colaborador lo declara la clínica en OdontoHR: aquí se
   ENSEÑA, y es lo que explica por qué se le pide un título de capacitación y
   no otro. Sin este bloque, la petición del papel se lee como un error del
   portal — ya hay precedente.

   Píldoras y no una lista con casillas: una casilla, aunque esté
   deshabilitada, invita a pulsarla y promete una edición que aquí no existe.
   ============================================================ */

.exp-especialidades {
  padding: 4px 20px 14px;
}
.exp-especialidades-titulo {
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
}
.exp-especialidades-nota {
  margin-top: 3px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--text-2);
}
.exp-especialidades-lista {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.exp-especialidad {
  padding: 4px 10px;
  font-size: 12px;
  line-height: 1.3;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
}

.exp-lista {
  padding: 6px 20px 24px;
}
.exp-lista .section-title {
  display: block;
  margin-bottom: 10px;
}
.exp-items {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.exp-item {
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border-strong);
  border-radius: var(--radius-lg);
}
.exp-item--vigente     { border-left-color: var(--success); }
.exp-item--en_revision { border-left-color: var(--petrol); }
.exp-item--por_vencer  { border-left-color: var(--ochre); }
.exp-item--sin_subir   { border-left-color: var(--ochre); }
.exp-item--rechazado   { border-left-color: var(--terracotta); }
.exp-item--caducado {
  border-left-color: var(--terracotta-deep);
  background: var(--terracotta-soft);
}

/* Envuelve a propósito: «Certificado Delitos de Naturaleza Sexual» + el chip
   no caben en una línea de 320 px, y forzarlo con `nowrap` es lo que hacía
   que el rótulo se saliera de la tarjeta. */
.exp-item-cab {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 8px;
}
.exp-item-nombre {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--text);
}
.exp-item-chip {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 4px;
  background: var(--surface-2);
  color: var(--text-2);
  white-space: nowrap;
}
.exp-item-chip--vigente     { background: rgba(93, 138, 46, 0.14); color: var(--success-ink); }
.exp-item-chip--en_revision { background: var(--petrol-soft); color: var(--petrol); }
.exp-item-chip--por_vencer,
.exp-item-chip--sin_subir   { background: var(--ochre-soft); color: #7A5310; }
.exp-item-chip--rechazado,
.exp-item-chip--caducado    { background: var(--bg); color: var(--terracotta-deep); }

.exp-item-consecuencia {
  margin-top: 6px;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--text-2);
}
.exp-item-rechazo {
  margin-top: 8px;
  padding: 8px 10px;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--terracotta-deep);
  background: var(--terracotta-soft);
  border-radius: var(--radius-sm);
}
.exp-item-rechazo strong { font-weight: 600; }

.exp-item-datos {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px 16px;
  margin-top: 10px;
}
.exp-item-datos div { display: flex; flex-direction: column; gap: 2px; }
.exp-item-datos dt {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}
.exp-item-datos dd {
  font-size: 13px;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.exp-item-historial {
  margin-top: 8px;
  font-size: 11.5px;
  line-height: 1.4;
  color: var(--muted);
}

.exp-item-acciones {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 10px;
}
/* La acción que resuelve la línea manda: va la última en el flujo, que en
   una fila alineada a la derecha es la posición del pulgar. */
.exp-item-acciones:empty { display: none; }
/* `_pdf_actions.html` entra con `display: contents`, pero su
   `.pdf-actions .btn { flex: 1 1 auto }` sigue alcanzando a los botones —el
   wrapper desaparece del layout, no del árbol—, y «Ver el archivo» se
   estiraba a toda la línea con el texto centrado, como si fuera el botón
   principal de la tarjeta. Aquí manda la fila, no el partial. */
.exp-item-acciones .pdf-actions .btn { flex: 0 0 auto; }
/* Un botón que cuelga directo de la botonera (sin pasar por `.pdf-actions`)
   necesita la misma regla, o se estira a todo el ancho de la fila. */
.exp-item-accion { flex: 0 0 auto; }

/* ============================================================
   DOCUMENTOS / FACTURAS — formulario upload (compartido)
   ============================================================ */
.doc-form,
.fac-form {
  padding: 4px 20px 24px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.doc-form .form-row,
.fac-form .form-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.doc-form .form-row label,
.fac-form .form-row label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
}
.doc-form .form-row--2col,
.fac-form .form-row--2col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
.doc-form input[type="text"],
.doc-form input[type="number"],
.doc-form input[type="date"],
.doc-form input[type="file"],
.doc-form select,
.doc-form textarea,
.fac-form input[type="text"],
.fac-form input[type="number"],
.fac-form input[type="date"],
.fac-form input[type="file"],
.fac-form select,
.fac-form textarea {
  width: 100%;
  min-height: 44px;
  padding: 0 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 14px;
  letter-spacing: -0.005em;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.doc-form input[type="file"],
.fac-form input[type="file"],
.recruit-form input[type="file"] {
  padding: 8px 12px;
  line-height: 1.3;
}
/* El formulario público de candidatura tenía la caja pero no el botón: el
   selector de archivo salía con el gris nativo del navegador dentro de una
   caja crema, que es lo primero que ve quien nos manda su CV. */
.doc-form input[type="file"]::file-selector-button,
.fac-form input[type="file"]::file-selector-button,
.recruit-form input[type="file"]::file-selector-button,
.doc-form input[type="file"]::-webkit-file-upload-button,
.fac-form input[type="file"]::-webkit-file-upload-button,
.recruit-form input[type="file"]::-webkit-file-upload-button {
  margin-right: 12px;
  padding: 8px 14px;
  background: var(--terracotta);
  color: var(--terracotta-foreground);
  border: none;
  border-radius: var(--radius-sm);
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.01em;
  cursor: pointer;
  transition: background 0.15s ease;
}
.doc-form input[type="file"]::file-selector-button:hover,
.fac-form input[type="file"]::file-selector-button:hover,
.recruit-form input[type="file"]::file-selector-button:hover,
.doc-form input[type="file"]::-webkit-file-upload-button:hover,
.fac-form input[type="file"]::-webkit-file-upload-button:hover,
.recruit-form input[type="file"]::-webkit-file-upload-button:hover {
  background: var(--terracotta-deep);
}
.doc-form input:focus,
.doc-form select:focus,
.doc-form textarea:focus,
.fac-form input:focus,
.fac-form select:focus,
.fac-form textarea:focus {
  outline: none;
  border-color: var(--terracotta);
  background: var(--bg);
  box-shadow: 0 0 0 3px rgba(176, 74, 46, 0.12);
}
.doc-form .form-help,
.fac-form .form-help {
  font-size: 11.5px;
  color: var(--text-2);
  line-height: 1.4;
}
.doc-form .form-errors,
.doc-form .errorlist,
.fac-form .form-errors,
.fac-form .errorlist {
  list-style: none;
  margin: 0;
  padding: 8px 12px;
  font-size: 12.5px;
  color: var(--terracotta-deep);
  background: var(--terracotta-soft);
  border-radius: var(--radius-sm);
}
.doc-form .form-actions,
.fac-form .form-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 6px;
}
.fac-form .form-actions .btn { min-width: 110px; }

/* ============================================================
   Topbar dropdowns (campana + menú ⋮)
   ============================================================ */
.topbar-dropdown {
  position: relative;
  display: flex;
}
.topbar-dropdown[data-open="true"] .icon-btn {
  border-color: var(--border-strong);
  background: var(--bg);
}

.topbar-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 30;
  min-width: 280px;
  max-width: min(340px, calc(100vw - 32px));
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow:
    0 16px 40px -12px rgba(43, 36, 32, 0.22),
    0 4px 12px -4px rgba(43, 36, 32, 0.10);
  padding: 6px;
  overflow: hidden;
}
.topbar-panel[hidden] { display: none; }

.topbar-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 10px 10px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
}
.topbar-panel-title {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
}
.topbar-panel-count {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  color: var(--terracotta-foreground);
  background: var(--terracotta);
  padding: 2px 7px;
  border-radius: 999px;
  letter-spacing: 0.04em;
}

.topbar-panel-empty {
  padding: 18px 12px 16px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  color: var(--muted);
  font-size: 12.5px;
  text-align: center;
}
.topbar-panel-empty svg { color: var(--success-ink); }

/* --- Notificaciones --- */
.topbar-notif-list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 60vh;
  overflow-y: auto;
}
.topbar-notif {
  border-bottom: 1px solid var(--border);
}
.topbar-notif:last-child { border-bottom: none; }

.topbar-notif-link {
  display: grid;
  grid-template-columns: 8px 1fr;
  gap: 10px;
  align-items: start;
  padding: 10px 10px;
  text-decoration: none;
  color: inherit;
  border-radius: var(--radius-sm);
  transition: background 0.12s ease;
  min-height: var(--touch-target);
}
.topbar-notif-link:hover { background: var(--surface); }

.topbar-notif-mark {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-top: 7px;
  background: var(--muted);
}
.topbar-notif--warning .topbar-notif-mark { background: var(--ochre); }
.topbar-notif--danger  .topbar-notif-mark { background: var(--terracotta); }
.topbar-notif--info    .topbar-notif-mark { background: var(--petrol); }

.topbar-notif-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.topbar-notif-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  letter-spacing: -0.005em;
  line-height: 1.3;
}
.topbar-notif-sub {
  font-size: 11.5px;
  color: var(--text-2);
  line-height: 1.35;
}

/* --- Menú de acciones --- */
.topbar-menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px 10px;
  text-align: left;
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.005em;
  cursor: pointer;
  text-decoration: none;
  min-height: var(--touch-target);
  transition: background 0.12s ease, color 0.12s ease;
}
.topbar-menu-item:hover { background: var(--surface); }
.topbar-menu-item svg { flex-shrink: 0; color: var(--text-2); }
.topbar-menu-item--danger { color: var(--terracotta); }
.topbar-menu-item--danger:hover { background: var(--terracotta-soft); }
.topbar-menu-item--danger svg { color: var(--terracotta); }

.topbar-menu-form { margin: 0; padding: 0; }

.topbar-menu-sep {
  height: 1px;
  background: var(--border);
  margin: 4px 4px;
}

/* ============================================================
   Tarifario móvil (Bloque A — anexo dinámico del contrato)
   ============================================================ */

/* Variantes adicionales de CTA usadas en el tarifario */
.cta--secondary {
  background: transparent;
  color: var(--terracotta);
  border: 1px solid var(--terracotta);
}
.cta--secondary:hover { background: var(--terracotta-soft); }
.cta--ghost {
  background: transparent;
  color: var(--text-2);
  border: 1px solid var(--border);
}
.cta--ghost:hover { color: var(--text); background: var(--surface-2); }

/* Wrap con margen lateral para todo el contenido bajo el hero.
   Sin esto las cards llegaban flush al borde de la app card y se
   sentían apretadas en pantallas estrechas. */
.tarif-content {
  padding: 0 16px 16px;
}

/* Cabecera de metadatos de la versión vigente */
.tarif-meta {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 12px 14px;
  margin: 14px 0 12px;
  display: grid;
  gap: 6px;
}
.tarif-meta-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 13px;
}
.tarif-meta-row--ok { color: var(--success, #5d8a2e); }
.tarif-meta-row--pendiente { color: var(--ochre, #c9821f); font-weight: 600; }
.tarif-meta-hint {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-2);
  margin-left: 6px;
  text-transform: lowercase;
}
.tarif-banner-pendiente--vigencia {
  background: rgba(44, 95, 93, 0.08);
  border-left-color: var(--petrol, #2c5f5d);
  color: var(--text);
}
.tarif-meta-label {
  color: var(--text-2);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.tarif-meta-hash {
  font-family: var(--font-mono);
  font-size: 12px;
  background: var(--surface-2);
  padding: 1px 6px;
  border-radius: 3px;
}

/* Banner aceptación pendiente (no bloqueante) */
.tarif-banner-pendiente {
  background: rgba(201, 130, 31, 0.10);
  border-left: 3px solid var(--ochre, #c9821f);
  padding: 12px 14px;
  border-radius: var(--radius-md);
  margin: 10px 0 14px;
  font-size: 13.5px;
  color: var(--text);
}
.tarif-banner-detalle {
  margin-top: 6px;
  color: var(--text-2);
  font-size: 13px;
}
.tarif-banner-detalles-toggle {
  margin-top: 10px;
}
.tarif-banner-detalles-toggle summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--ochre, #c9821f);
  padding: 6px 0;
}
.tarif-form-aceptar {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 8px;
  padding: 10px;
  background: var(--bg);
  border-radius: var(--radius-md);
}
.tarif-check {
  font-size: 13px;
  display: flex;
  gap: 8px;
  align-items: flex-start;
  cursor: pointer;
}

/* Acciones bajo el bloque de metadatos */
.tarif-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin: 8px 0 14px;
}
.tarif-actions .cta { flex: 1; min-width: 0; font-size: 13px; padding: 10px 12px; }

/* Bloque de filtros: select de área + buscador de tratamiento.
   Stack en móvil (más cómodo para tocar), fila en PC (≥1024px,
   cuando la card es ya 680px y caben los dos). */
.tarif-filtros {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 12px;
}
.tarif-filtro {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.tarif-filtro-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
}
.tarif-select {
  width: 100%;
  padding: 10px 36px 10px 14px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--bg);
  font-family: var(--font-ui);
  font-size: 14px;
  min-height: 44px;
  color: var(--text);
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='%23766F66'><path d='M5 8l5 5 5-5H5z'/></svg>");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 16px;
}
.tarif-select:focus {
  outline: none;
  border-color: var(--terracotta);
  box-shadow: 0 0 0 3px rgba(176, 74, 46, 0.15);
}

/* Buscador */
.tarif-buscador {
  width: 100%;
  padding: 10px 14px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--bg);
  font-family: var(--font-ui);
  font-size: 14px;
  min-height: 44px;
}
.tarif-buscador:focus {
  outline: none;
  border-color: var(--terracotta);
  box-shadow: 0 0 0 3px rgba(176, 74, 46, 0.15);
}

/* Áreas plegables */
.tarif-area {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  margin-bottom: 10px;
  overflow: hidden;
}
.tarif-area-head {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 10px;
  align-items: center;
  padding: 12px 14px;
  cursor: pointer;
  font-size: 14px;
  list-style: none;
}
.tarif-area-head::-webkit-details-marker { display: none; }
.tarif-area-head::after {
  content: "▾";
  color: var(--text-2);
  transition: transform 0.2s;
}
.tarif-area[open] .tarif-area-head::after {
  transform: rotate(180deg);
}
.tarif-area-codigo {
  font-family: var(--font-mono);
  font-size: 11.5px;
  background: var(--surface-2);
  padding: 2px 6px;
  border-radius: 3px;
}
.tarif-area-desc { font-weight: 600; }
.tarif-area-count {
  color: var(--text-2);
  font-size: 12px;
}

/* Lista de tratamientos */
.tarif-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--border);
}
.tarif-item {
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
}
.tarif-item:last-child { border-bottom: none; }
.tarif-item-head {
  display: flex;
  gap: 10px;
  align-items: baseline;
  margin-bottom: 6px;
}
.tarif-item-codigo {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-2);
}
.tarif-item-nombre {
  font-weight: 600;
  font-size: 14px;
  color: var(--text);
}
/* Móvil: cada métrica ocupa toda la fila, label a la izquierda y
   valor a la derecha. Mucho más legible en pantalla estrecha que
   tres columnas con labels largos (`% coste asumido`) en vertical. */
.tarif-item-grid {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 0;
}
.tarif-cell {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  padding: 6px 10px;
  background: var(--surface);
  border-radius: 4px;
  margin: 0;
}
.tarif-cell-label {
  font-size: 12px;
  color: var(--text-2);
  letter-spacing: 0.02em;
  margin: 0;
}
.tarif-cell-value {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  margin: 0;
  text-align: right;
}

/* PC ≥1024px: volvemos al grid de 3 columnas, que ahí sí caben
   sin apretarse y permite escanear con vista los porcentajes. */
@media (min-width: 1024px) {
  .tarif-item-grid {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    gap: 8px;
  }
  .tarif-cell {
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    padding: 6px 8px;
  }
  .tarif-cell-label {
    font-size: 10.5px;
    text-transform: uppercase;
    letter-spacing: 0.03em;
  }
  .tarif-cell-value { text-align: left; }

  /* En PC los filtros caben lado a lado: select compacto a la
     izquierda y buscador ocupando el resto. */
  .tarif-filtros {
    flex-direction: row;
    align-items: flex-end;
  }
  .tarif-filtro { flex: 0 0 auto; min-width: 220px; }
  .tarif-filtro--grow { flex: 1 1 auto; min-width: 0; }
}

/* Aviso legal y estado vacío */
.tarif-aviso-legal {
  font-size: 11.5px;
  color: var(--text-2);
  margin-top: 16px;
  padding: 10px 12px;
  background: var(--surface);
  border-radius: 4px;
  line-height: 1.5;
}
.tarif-sin-version {
  text-align: center;
  padding: 30px 16px;
  color: var(--text-2);
}
.tarif-sin-version h2 {
  color: var(--text);
  font-size: 18px;
  margin-bottom: 8px;
}

/* Histórico */
.tarif-historico { list-style: none; margin: 0; padding: 0; }
.tarif-historico-item {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 12px 14px;
  margin-bottom: 10px;
}
.tarif-historico-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 6px;
}
.tarif-historico-meta {
  color: var(--text-2);
  font-size: 12px;
}
.tarif-historico-detalle {
  font-size: 13px;
  color: var(--text-2);
  margin-bottom: 8px;
}
.tarif-historico-notas {
  font-size: 12.5px;
  color: var(--text);
  margin: 6px 0;
  padding: 6px 8px;
  background: var(--bg);
  border-left: 2px solid var(--terracotta);
  border-radius: 2px;
}
.tarif-volver { display: block; margin-top: 16px; }

/* Login: el nombre de la clínica en la que se está entrando. Es el dato que
   distingue dos PWA idénticas para quien colabora con dos clínicas. */
.login-clinica {
  color: var(--terracotta-deep);
  font-weight: 600;
}

/* Banners en detalle de liquidación (Bloque B) */
.liq-banner-validacion,
.liq-banner-pago {
  margin: 10px 20px;
  padding: 12px 14px;
  border-radius: var(--radius-md);
  font-size: 13px;
  line-height: 1.4;
  color: var(--text);
}
.liq-banner-validacion {
  background: rgba(93, 138, 46, 0.10);
  border: 1px solid rgba(93, 138, 46, 0.28);
  border-left: 3px solid var(--success, #5d8a2e);
}
.liq-banner-pago {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-left: 3px solid var(--petrol, #2c5f5d);
}

/* ============================================================
   Liquidaciones — listado mensual (móvil colaborador)
   ============================================================ */
.liq-list {
  list-style: none;
  margin: 0;
  padding: 0 20px 24px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.liq-row {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  transition: border-color 0.2s ease, transform 0.2s ease;
}
.liq-row:hover { border-color: var(--border-strong); transform: translateX(2px); }
.liq-row--enviada_colaborador,
.liq-row--en_revision {
  border-color: rgba(176, 74, 46, 0.28);
  background:
    radial-gradient(circle at top right, rgba(176, 74, 46, 0.07), transparent 60%),
    var(--surface);
}
.liq-row--rechazada {
  border-color: rgba(176, 74, 46, 0.35);
}
.liq-row-link {
  display: block;
  padding: 14px 16px;
  text-decoration: none;
  color: inherit;
  min-height: var(--touch-target);
}
.liq-row-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
}
.liq-row-periodo {
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--text);
}
.liq-row-estado {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-2);
  white-space: nowrap;
}
.liq-row-estado--enviada_colaborador,
.liq-row-estado--en_revision {
  background: var(--terracotta-soft);
  color: var(--terracotta-deep);
}
.liq-row-estado--aceptada,
.liq-row-estado--facturada {
  background: var(--ochre-soft);
  color: var(--ochre-ink);
}
.liq-row-estado--pagada {
  background: rgba(93, 138, 46, 0.12);
  color: var(--success-ink);
}
.liq-row-estado--rechazada {
  background: rgba(176, 74, 46, 0.14);
  color: var(--terracotta-deep);
}
.liq-row-importe {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 6px;
  font-family: var(--font-ui);
  font-feature-settings: "tnum", "lnum";
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--text);
  line-height: 1.1;
  margin-bottom: 4px;
}
.liq-row-importe strong { font-weight: 600; }
.liq-row-importe small {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 400;
  color: var(--muted);
  letter-spacing: 0.04em;
  text-transform: lowercase;
}
.liq-row-fecha {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--muted);
  letter-spacing: 0.04em;
}
/* Llamada a subir factura en las liquidaciones ya aceptadas: fuera del
   enlace de la fila (no se pueden anidar dos <a>). */
.liq-row-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 12px 16px 14px;
  border-top: 1px solid var(--border);
}
.liq-row-cta-texto {
  font-size: 12px;
  line-height: 1.35;
  color: var(--text-2);
  flex: 1 1 140px;
}
.liq-row-cta .btn { flex: 0 0 auto; }

/* ============================================================
   Liquidaciones — detalle (desglose, líneas, acciones)
   ============================================================ */
.liq-desglose,
.liq-lineas,
.liq-factura,
.liq-acciones { padding: 0 20px 24px; }

/* Acciones de PDF (compartir + descargar) — reutilizable en el portal
   colaborador (liquidaciones, adjuntos, documentos, tarifario). */
.pdf-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 14px;
}
.pdf-actions .btn { flex: 1 1 auto; }
.pdf-actions [aria-busy="true"] { opacity: 0.6; pointer-events: none; }
/* Variante para embeber los botones en un flex ya existente (tarifario):
   el wrapper desaparece y sus hijos participan del layout del contenedor. */
.pdf-actions--contents { display: contents; }
/* Histórico de tarifario: fila de acciones (compartir + descargar) por versión. */
.tarif-historico-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 8px;
}
.tarif-historico-actions [aria-busy="true"] { opacity: 0.6; pointer-events: none; }

/* Detalle: factura pendiente de subir (liquidación aceptada, sin factura). */
.liq-factura-pendiente {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-left: 3px solid var(--ochre);
  border-radius: var(--radius-md);
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.liq-factura-pendiente--vencida {
  border-left-color: var(--terracotta);
  background: rgba(176, 74, 46, 0.07);
}
.liq-factura-texto {
  margin: 0;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text);
}

.liq-desglose .section-title,
.liq-lineas .section-title,
.liq-factura .section-title,
.liq-acciones .section-title { padding: 18px 0 10px; }

.liq-desglose-dl {
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 12px 14px;
}
.liq-desglose-dl > div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  font-size: 13.5px;
}
.liq-desglose-dl dt { color: var(--text-2); margin: 0; }
.liq-desglose-dl dd {
  margin: 0;
  font-family: var(--font-ui);
  font-feature-settings: "tnum", "lnum";
  color: var(--text);
}
.liq-desglose-total {
  margin-top: 4px !important;
  padding-top: 8px;
  border-top: 1px solid var(--border-strong);
  font-size: 15px !important;
}
.liq-desglose-total dt { font-weight: 600; color: var(--text) !important; }
.liq-desglose-total dd strong { color: var(--terracotta-deep); font-size: 17px; }

.liq-lineas-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.liq-linea {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 10px 12px;
}
.liq-linea-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 4px;
}
.liq-linea-fecha {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--terracotta);
  letter-spacing: 0.04em;
  flex-shrink: 0;
}
.liq-linea-tratamiento {
  font-size: 14px;
  font-weight: 500;
  color: var(--text);
  line-height: 1.25;
}
.liq-linea-sub {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--muted);
  margin-bottom: 6px;
}
.liq-linea-importes {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  font-family: var(--font-ui);
  font-feature-settings: "tnum", "lnum";
  font-size: 12.5px;
  color: var(--text-2);
}
/* El código de paciente es un identificador anonimizado —no un nombre— y el
   de tratamiento el que aparece en el tarifario: los dos se leen en la
   tipografía de datos y el segundo algo más marcado, que es el que el
   colaborador coteja contra su tarifa. */
.liq-linea-paciente { color: var(--muted); }
.liq-linea-codigo {
  color: var(--text-2);
  background: var(--surface-2);
  border-radius: 3px;
  padding: 0 4px;
}
.liq-linea-neto { color: var(--text); }
.liq-linea-neto strong { color: var(--terracotta-deep); }

.liq-form-aceptar,
.liq-form-rechazar {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 8px;
}
.liq-form-aceptar label,
.liq-form-rechazar label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
}
.liq-rechazar-details {
  margin-top: 14px;
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.liq-rechazar-details summary {
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--terracotta-deep);
  font-weight: 600;
}

/* ============================================================
   Ajustes de la app en el Perfil — instalar / avisos / biometría
   ============================================================ */
.dp-settings {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 12px;
}
.dp-setting-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--text);
  text-decoration: none;
  min-height: var(--touch-target);
}
a.dp-setting-row:hover { border-color: var(--border-strong); }
.dp-setting-row--block { flex-direction: column; align-items: stretch; }
.dp-setting-head { display: flex; align-items: center; gap: 12px; }
.dp-setting-ico {
  flex: 0 0 auto;
  width: 22px; height: 22px;
  color: var(--terracotta);
}
.dp-setting-ico svg { width: 100%; height: 100%; }
.dp-setting-text { display: flex; flex-direction: column; gap: 2px; flex: 1 1 auto; min-width: 0; }
.dp-setting-label { font-weight: 600; font-size: 14px; }
.dp-setting-sub { font-size: 12px; color: var(--muted); }
.dp-setting-chev { color: var(--muted); font-size: 20px; line-height: 1; }

/* Switch tipo iOS para los avisos */
.dp-switch {
  flex: 0 0 auto;
  width: 46px; height: 28px;
  border-radius: 999px;
  border: none;
  background: var(--border-strong);
  position: relative;
  cursor: pointer;
  transition: background .18s ease;
}
.dp-switch::after {
  content: "";
  position: absolute;
  top: 3px; left: 3px;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,.25);
  transition: transform .18s ease;
}
.dp-switch.on { background: var(--success); }
.dp-switch.on::after { transform: translateX(18px); }
.dp-switch:disabled { opacity: .5; cursor: not-allowed; }

/* Lista de passkeys registradas */
.dp-passkey-list { list-style: none; margin: 12px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.dp-passkey-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.dp-passkey-label { font-weight: 600; font-size: 13px; flex: 1 1 auto; min-width: 0; }
.dp-passkey-date { font-size: 11px; color: var(--muted); }
.dp-passkey-revoke {
  flex: 0 0 auto;
  border: none; background: none;
  color: var(--danger);
  font-size: 12px; font-weight: 600;
  cursor: pointer; padding: 4px 6px;
}
.dp-passkey-revoke:hover { text-decoration: underline; }

.dp-btn-secondary {
  margin-top: 12px;
  width: 100%;
  padding: 12px;
  border: 1px solid var(--terracotta);
  background: var(--terracotta-foreground);
  color: var(--terracotta-deep);
  border-radius: var(--radius-md);
  font-weight: 600; font-size: 14px;
  cursor: pointer;
  font-family: var(--font-ui);
}
.dp-btn-secondary:hover { background: var(--terracotta-soft); }
.dp-btn-secondary:disabled { opacity: .5; cursor: not-allowed; }

.dp-setting-status { margin: 10px 2px 0; font-size: 12px; color: var(--text); }
.dp-setting-status[data-kind="error"] { color: var(--danger); }
.dp-setting-status[data-kind="ok"] { color: var(--success-ink); }

/* Banda de bienvenida por instancia (cabecera dashboard) */
.dp-instance-band {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 14px;
  background: var(--accent, var(--terracotta));
  color: #fff;
  font-size: 12px; font-weight: 600;
  letter-spacing: .02em;
}
.dp-instance-band .dp-instance-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: rgba(255,255,255,.85);
}

/* ============================================================
   Guía de instalación de la PWA (/instalar/)
   ============================================================ */
.dp-install-already {
  padding: 14px;
  background: var(--petrol-soft);
  border-radius: var(--radius-md);
  font-size: 13px;
  margin-bottom: 14px;
}
.dp-install-platform {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 16px;
  margin-top: 12px;
}
.dp-install-head {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 700;
  color: var(--terracotta);
  text-transform: uppercase;
  letter-spacing: .04em;
  margin-bottom: 10px;
}
.dp-install-steps {
  margin: 0;
  padding-left: 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: 14px;
  line-height: 1.4;
}
.dp-install-steps li { padding-left: 4px; }
.dp-install-switch {
  margin-top: 18px;
  font-size: 12px;
  color: var(--muted);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.dp-install-switch button {
  border: 1px solid var(--border-strong);
  background: var(--bg);
  border-radius: 999px;
  padding: 5px 12px;
  font-size: 12px;
  color: var(--text);
  cursor: pointer;
}
.dp-install-switch button:hover { border-color: var(--terracotta); color: var(--terracotta); }

/* ============================================================
   Pantalla de desbloqueo biométrico (/desbloquear/)
   ============================================================ */
.dp-unlock-card {
  margin-top: 18px;
  padding: 28px 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}
.dp-unlock-ico {
  width: 56px; height: 56px;
  color: var(--terracotta);
  display: flex; align-items: center; justify-content: center;
  background: var(--terracotta-foreground);
  border-radius: 50%;
  padding: 12px;
}
.dp-unlock-ico svg { width: 100%; height: 100%; }
.dp-unlock-text { font-size: 14px; color: var(--text); line-height: 1.45; margin: 0; max-width: 32ch; }
.dp-unlock-card .dp-btn-secondary { margin-top: 4px; max-width: 280px; }
.dp-unlock-foot { margin-top: 18px; text-align: center; font-size: 13px; }
.dp-unlock-foot a { color: var(--muted); text-decoration: underline; }

/* ------------------------------------------------------------------
   Utilidades de espaciado
   Sustituyen a los `style="margin-top:Npx"` inline de las plantillas
   del portal (regla de proyecto: nada de CSS inline; guard en
   tests/test_calidad_20260427.py).
   ------------------------------------------------------------------ */
.u-mt-12 { margin-top: 12px; }
.u-mt-24 { margin-top: 24px; }

/* ============================================================
   COBERTURAS — detalle y solicitud  (sustituciones/*.html)
   ============================================================
   Siete clases que el marcado escribía y ninguna hoja declaraba. Sin ellas
   la ficha de una cobertura salía como un volcado: el `<dl>` en el flujo
   por defecto del navegador (cada `dd` en su línea, sangrado 40px), los
   formularios sin separación entre sí, la nota legal como un párrafo más
   —y es la que dice que no hay «alta exprés para sustituir»— y el botón de
   cancelar con el mismo aspecto que el de aceptar.
   ============================================================ */

.info-grid {
  display: grid;
  grid-template-columns: minmax(9rem, 34%) 1fr;
  gap: 8px 14px;
  margin: 0;
  padding: 14px 20px;
  font-size: 14px;
}
.info-grid dt {
  color: var(--muted);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  align-self: baseline;
}
.info-grid dd {
  margin: 0;
  color: var(--text);
  overflow-wrap: anywhere;
}
@media (max-width: 480px) {
  /* En móvil dos columnas dejan el valor en una tira de 4 caracteres. */
  .info-grid { grid-template-columns: 1fr; gap: 2px 0; }
  .info-grid dd { margin-bottom: 10px; }
}

.form-stack {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 0 20px;
}
/* Un solo botón: no necesita apilar nada y no debe ocupar el ancho. */
.form-stack--inline {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

.info-banner {
  margin: 0 20px 14px;
  padding: 12px 14px;
  border-radius: var(--radius-md);
  border-left: 3px solid var(--petrol);
  background: var(--surface);
  color: var(--text-2);
  font-size: 13px;
  line-height: 1.5;
}
.info-banner strong { color: var(--text); }
/* Lo legal no es un consejo: se distingue del resto de avisos. */
.info-banner--legal {
  border-left-color: var(--ochre);
  background: var(--ochre-soft);
  color: var(--text);
}
.info-banner--legal strong { color: var(--ochre-ink); }

/* Acción destructiva. `.cta` es terracota de marca; esta va más oscura para
   que no se confunda con «Aceptar cobertura», que está justo encima. */
.cta--danger {
  background: var(--terracotta-deep);
  border-color: var(--terracotta-deep);
  color: var(--terracotta-foreground);
}
.cta--danger:hover { filter: brightness(1.08); }

/* ------------------------------------------------------------------
   Impersonación: el acto declarativo no se pinta
   Franja que ocupa el sitio del botón cuando el gestor ve el portal
   "como el colaborador" (`_partials/_impersonando_bloqueado.html`).
   Misma familia visual que `.borrador-aviso-impersonando` del
   calendario: borde discontinuo = "esto no es tuyo, es de él".
   ------------------------------------------------------------------ */
/* --- Mis días habituales (patrón declarado) + ratificación --- */
.dp-patron {
  margin-top: 10px;
  padding: 14px;
  background: #FDF8EE;
  border: 1px solid rgba(201, 130, 31, 0.22);
  border-left-width: 4px;
  border-radius: var(--radius-md);
}
.dp-patron-texto {
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  line-height: 1.35;
}
.dp-patron-origen {
  margin-top: 8px;
  font-size: 13px;
  color: var(--text-2);
  line-height: 1.45;
}
.dp-patron-acciones {
  margin-top: 12px;
}

.dp-aviso-impersonando {
  margin: 12px 0 0;
  padding: 10px 12px;
  border-radius: var(--radius-md);
  border: 1px dashed var(--ochre, #c9821f);
  background: var(--ochre-soft);
  font-size: 13px;
  line-height: 1.45;
  color: var(--text);
}
.dp-aviso-impersonando strong { color: #7a5310; display: block; }

/* ============================================================
   MIS DÍAS RESERVADOS  (calendario/_reservas_overlay.html)
   ============================================================
   Esta pantalla se escribió sin hoja. Ninguna de sus nueve clases tenía una
   sola regla, así que lo único que la pintaba era `.reserva` —del componente
   del DASHBOARD, con `grid-template-columns: 48px 1fr auto` para otra
   estructura—, y la fecha caía en la columna de 48 px y se partía letra a
   letra. El marcado no fallaba: no lo pintaba nadie, que es el fallo mudo de
   siempre.

   El bloque se llama `.dia-reservado` y no `.reserva` a propósito: dos
   componentes con el mismo nombre en la misma cascada era el defecto, y
   pelearlo con más especificidad lo habría escondido.

   Todo apilado y sin columnas fijas: se lee en un móvil de 360 px, que es el
   único sitio donde esta pantalla se abre. */
/* ⚠️ `.app-main` NO tiene padding lateral: cada sección se lo pone. Esta no
   lo hacía, así que sus tarjetas llegaban pegadas al borde de la card
   mientras el título —que sí heredaba el suyo— quedaba a otra sangría. Los
   20 px son los mismos de `.hero` y `.calendario-mes`, que es con lo que
   tiene que alinearse: es la misma pantalla. */
.dias-reservados {
  margin-top: 24px;
  padding: 0 20px 8px;
}
.dias-reservados-titulo {
  margin: 0;
  font-size: 18px;
  font-weight: 700;
  color: var(--text);
}
.dias-reservados-sub {
  margin: 4px 0 12px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-2);
}
.dias-reservados-lista {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.dia-reservado {
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  /* El filete dice el estado del día de un vistazo; el texto exacto va en
     cada franja, que es donde el dato es cierto — un día puede tener la
     mañana confirmada y la tarde pendiente. */
  border-left: 3px solid var(--border-strong);
  border-radius: var(--radius-lg);
}
.dia-reservado--confirmada            { border-left-color: var(--success); }
.dia-reservado--pendiente_aprobacion  { border-left-color: var(--ochre); }
.dia-reservado--sin_apoyo,
.dia-reservado--asistira_sin_apoyo    { border-left-color: var(--terracotta); }
.dia-reservado--cancelada_colaborador,
.dia-reservado--cerrada_por_colaborador,
.dia-reservado--rechazada_admin       { border-left-color: var(--muted); }

.dia-reservado-cab {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}
/* `first-letter` y no `text-transform`: «mar 25 ago» con la inicial en alta se
   lee como fecha; en versales enteras compite con los rótulos mono. */
.dia-reservado-fecha {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
  white-space: nowrap;
}
.dia-reservado-fecha::first-letter { text-transform: uppercase; }
.dia-reservado-tag {
  font-size: 11px;
  color: var(--text-2);
  white-space: nowrap;
}

.dia-reservado-franjas {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
/* Envuelve a propósito: en 360 px, «Tarde · 16:00–20:00 · Pendiente de
   aprobación» no cabe en una línea, y forzarlo con `nowrap` es lo que
   producía el desbordamiento que se venía viendo. */
.franja {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 8px;
  font-size: 13px;
  line-height: 1.4;
}
.franja-turno { font-weight: 600; color: var(--text); }
.franja-horas {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-2);
  white-space: nowrap;
}
.franja-estado {
  font-size: 11px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-2);
  white-space: nowrap;
}
.franja-estado--confirmada           { background: rgba(93, 138, 46, 0.14); color: var(--success-ink); }
.franja-estado--pendiente_aprobacion { background: var(--ochre-soft); color: var(--ochre-ink); }
.franja-estado--sin_apoyo,
.franja-estado--asistira_sin_apoyo   { background: var(--terracotta-soft); color: var(--terracotta-deep); }

.franja-apoyo { font-size: 11px; color: var(--text-2); white-space: nowrap; }
.franja-apoyo--ok      { color: var(--success-ink); }
.franja-apoyo--ko      { color: var(--terracotta-deep); }
.franja-apoyo--parcial { color: var(--ochre-ink); }
.franja-nota {
  flex-basis: 100%;
  margin: 2px 0 0;
  font-size: 12px;
  line-height: 1.4;
  color: var(--text-2);
}

.dia-reservado-decidir { margin-top: 8px; }

/* ============================================================
   DECISIÓN SOBRE UN DÍA SIN APOYO  (calendario/decision_sin_apoyo.html)
   ============================================================
   La otra mitad de la misma pantalla sin hoja: once clases `decision-*` sin
   una sola regla. Hoy no se ve porque ninguna reserva está en `sin_apoyo`
   —medido en CDT: 178 pendientes, 26 confirmadas, 2 canceladas—, pero es a
   donde lleva el botón «Decidir» de «Mis días reservados», así que estaba a
   un estado de distancia de salir así.

   Los radios son tarjetas y no una lista de puntos: esto se toca con el pulgar
   y la respuesta no es obvia — hay que poder leer las dos consecuencias antes
   de elegir. */
.decision-card {
  margin: 0 20px 24px;
  padding: 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.decision-resumen {
  padding-bottom: 12px;
  margin-bottom: 14px;
  border-bottom: 1px solid var(--border);
}
.decision-fecha {
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  line-height: 1.3;
}
.decision-fecha::first-letter { text-transform: uppercase; }
.decision-franja {
  margin-top: 2px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-2);
}
.decision-tag {
  display: inline-block;
  margin-top: 6px;
  font-size: 11px;
  color: var(--text-2);
}

.decision-form { display: block; }
.decision-opciones {
  border: 0;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* `grid` de dos columnas con el radio a la izquierda: así el sub-texto queda
   alineado con el título y no debajo del control, que es lo que convierte
   una lista de opciones en un párrafo. */
.decision-opcion {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 2px 10px;
  align-items: start;
  padding: 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
}
.decision-opcion:hover { border-color: var(--border-strong); }
.decision-opcion input[type="radio"] {
  grid-row: 1 / span 2;
  margin: 2px 0 0;
  width: 18px;
  height: 18px;
  accent-color: var(--terracotta);
}
.decision-opcion:has(input:checked) {
  border-color: var(--terracotta);
  background: var(--terracotta-soft);
}
.decision-opcion-titulo {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.3;
}
.decision-opcion-sub {
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--text-2);
}

.decision-nota {
  display: block;
  margin-top: 14px;
  font-size: 13px;
  color: var(--text-2);
}
.decision-nota textarea {
  display: block;
  width: 100%;
  box-sizing: border-box;
  margin-top: 6px;
  padding: 10px;
  font: inherit;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  resize: vertical;
}
.decision-nota textarea:focus {
  outline: none;
  border-color: var(--terracotta);
}

/* Enviar a la derecha y cancelar a la izquierda: el destructivo nunca cae
   bajo el pulgar por inercia. */
.decision-actions {
  display: flex;
  gap: 10px;
  margin-top: 18px;
}
.decision-actions .cta { flex: 1; text-align: center; }

/* Ficha pública: su retrato para la web, como saldrá en la página del equipo. */
.dp-ficha-foto {
  display: block;
  width: 128px;
  height: 160px;
  margin: 6px 0;
  object-fit: cover;
  border-radius: var(--radius-md);
}
