/* ==========================================================================
   Del Rio Source — delriosource.com
   Design system v1 (2026-10-10)

   Built to one rule set. Every choice below maps to a named principle so the
   system can be audited rather than merely admired:

     [KJ]  Kole Jain — affordances/signifiers, visual hierarchy via contrast,
           4pt spacing grid, ONE typeface (-2% tracking, 110-120% leading on
           headings), colour ramp + semantic colours, dark mode depth via a
           lighter card on a darker ground, low-opacity/high-blur shadows with
           stronger elevation reserved for floating layers, icons matched to
           line-height, ghost buttons for secondary actions, four button
           states, micro-interactions, gradients/progressive blur for text over
           images.
     [TG]  Tim Gabe — strategy of subtraction, three-tap rule, deliberate
           spacing, 60-30-10 colour, no flashy gradients, no 45-layer shadows,
           design the flow not the screen, retention lever at peak intent.
     [AP]  Apple HIG — physics-based feedback (rubber-band ease, press states),
           subtraction, consistency and spatial continuity.
     [W3C] WCAG 2.2 AA: 4.5:1 normal text, 3:1 large text and UI boundaries,
           24px minimum target size (we ship 44-48px), reduced-motion support.

   Audit notes: body is 18px minimum [W3C older-users], no horizontal scroll at
   320px, every interactive control is >=44px, and all text/background pairs
   below were computed for contrast, not eyeballed.
   ========================================================================== */

/* ---------- self-hosted type -------------------------------------------
   ONE family [KJ]. Two subsets, normal style only, no italics shipped —
   italic files were dropped to protect the LCP budget. Variable axis 400-700
   means one file covers every weight, so nothing render-blocks a second face.
   ---------------------------------------------------------------------- */
@font-face {
  font-family: 'Figtree';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../fonts/figtree-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Figtree';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../fonts/figtree-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---------- tokens ----------------------------------------------------- */
:root {
  /* ONE appearance, by owner decision 2026-10-18. The stylesheet no longer
     branches on prefers-color-scheme. Two palettes meant every colour pair had
     to be measured twice and could drift apart silently; one warm-light palette
     is measured once and cannot disagree with itself. `color-scheme: light` is
     part of the fix, not decoration: without it the browser still paints form
     controls, scrollbars and the canvas chrome in its OWN dark theme for a
     visitor whose computer is set to dark, which is how a "light-only" site
     ends up with dark input boxes and unreadable placeholders.
     ops/check_design_rules.mjs asserts both halves — no prefers-color-scheme
     branch, and an explicit color-scheme. */
  color-scheme: light;

  /* 60-30-10 [TG]: neutral ground dominates, surfaces support, brand accents.
     The ground is warmed rather than grey-on-white: it is the difference
     between paper and a spreadsheet, and it is what keeps a mostly-text page
     from reading as plain. The cards are warm white (not #fff) so the page has
     a ground and a surface instead of one flat field of glare. */
  --paper:      #f6f2ea;   /* warm bone — never sterile white */
  --surface:    #fffdf9;
  --surface-2:  #efe9de;
  --line:       #e2dbcd;
  --line-soft:  rgba(16, 27, 36, .08);

  /* Colour ramp built from ONE brand hue [KJ], sampled from the owner's mark
     (ops/make_brand_assets.py): the navy of the N and R, the red of the D and
     the orbit, the blue of the globe. The mark replaced a green monogram on
     2026-10-21, so nothing in this file is green any more except two things
     that are deliberately NOT brand: --wa (WhatsApp's own colour, and the
     reason the button reads as "WhatsApp" at a glance) and --ok (a success
     state; green means "yes" in every interface). */
  --brand:      #00377f;   /* mark navy · 9.80:1 on paper · white on this = 9.55:1 */
  --brand-700:  #002b63;
  --brand-800:  #00214b;
  --brand-100:  #d9e3f4;
  --brand-050:  #eef3fb;

  /* The mark's red (#e20515), deepened just enough to clear AA as text. It is
     the second half of the identity, not a warning: the AEP band and the icon
     tiles wear it. --warn stays a warmer, more orange red so a field error
     never reads as brand decoration. */
  --accent:     #a00412;   /* 5.60:1 on paper · 6.85:1 on --accent-100 */
  --accent-100: #fbe4e6;
  --accent-200: #f2c6ca;

  /* WhatsApp green lives with its button, not as a general token: it is the
     platform's colour, and nothing else on the site may borrow it. */

  /* Inverted (dark) surfaces. These deliberately DO NOT flip with the theme —
     an editorial dark band should stay dark in both. The semantic tokens are
     re-pointed inside .panel and .site-foot instead, so no .note or <p> can
     inherit a light-theme grey onto a dark ground. */
  --panel-bg:    #0b1c33;   /* deep navy — the mark's blue, not a neutral */
  --panel-fg:    #dbe4e9;   /* 13.6:1 on --panel-bg */
  --panel-muted: #b9c6ce;   /* 10.0:1 on --panel-bg */
  --panel-link:  #a8c8f7;   /* 9.9:1 on --panel-bg */

  /* The TPMO notice is rendered on TWO grounds: the plain page ground (the
     capture page) and inside a dark band (the footer). Its dark-band pair is
     therefore stable in both themes, exactly like the --panel-* set — the
     translucent fill keeps it reading as a slip ON the band. */
  --tmo-band-bg: rgba(255, 255, 255, .06);
  --tmo-band-bd: rgba(255, 255, 255, .14);
  --tmo-band-fg: #dbe6eb;   /* 12.4:1 on --tmo-band-bg over --panel-bg */

  /* Ghost controls inside a dark band. Same reasoning: the band is dark in
     BOTH themes, so these are stable values, not theme tokens. The light
     theme's near-black ghost label measured 1:1 on --panel-bg — an invisible
     button — and its white hover fill would then swallow a light label. */
  --band-ghost-fg:    #dbe4e9;   /* 13.5:1 on --panel-bg */
  --band-ghost-bd:    #7c8a93;   /* 4.9:1 boundary on --panel-bg */
  --band-ghost-hover: rgba(255, 255, 255, .10);

  /* Filled-button tokens. The fill and its foreground are paired PER THEME,
     because the dark theme's accent is a light mint and white-on-mint is only
     2.45:1. Every pair below was computed, not chosen by eye. */
  --btn-primary-bg: #00377f; --btn-primary-bg-hover: #002b63; --btn-primary-fg: #ffffff;
  --btn-wa-bg:      #0e6e5f; --btn-wa-bg-hover:      #0a564a; --btn-wa-fg:      #ffffff;
  --btn-danger-bg:  #9c0a14; --btn-danger-fg:        #ffffff;
  --btn-ghost-fg:    #101b24;
  --btn-ghost-bd:    var(--line);
  --btn-ghost-hover: var(--surface);

  /* semantic [KJ] — meaning, not decoration */
  --ok:         #0b6b3a;   /* 6.13:1 */
  --warn:       #b3261e;   /* 6.06:1 — warmer and more orange than --accent, so a
                              field error never reads as brand decoration */
  --ok-100:     #e3f4ea;
  --warn-100:   #fceceb;

  --ink:        #101b24;   /* ~15.8:1 — headings */
  --body:       #35424e;   /* ~9.5:1  — body copy */
  --muted:      #56626e;   /* 5.69:1  — meta, captions. AA for normal text */

  /* spacing: strict 4pt scale [KJ]. Nothing in this file uses an off-scale gap. */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px; --s5: 20px;
  --s6: 24px; --s7: 32px; --s8: 40px; --s9: 48px; --s10: 64px; --s11: 80px;

  --r-sm: 10px; --r-md: 14px; --r-lg: 20px; --r-xl: 28px; --r-pill: 999px;

  /* shadows: low opacity, high blur [KJ]; elevation reserved for floating layers */
  --sh-1: 0 1px 2px rgba(16, 27, 36, .05), 0 8px 24px -14px rgba(16, 27, 36, .18);
  --sh-2: 0 2px 4px rgba(16, 27, 36, .06), 0 20px 44px -18px rgba(16, 27, 36, .26);

  --font: 'Figtree', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto,
          'Helvetica Neue', Arial, sans-serif;

  --wrap: 1100px;
  --tap: 48px;             /* >=44px everywhere [W3C]; 48 is our floor for CTAs */
}

/* ---------- the one appearance -----------------------------------------
   There is no prefers-color-scheme branch here, and there must not be one.
   What replaces it is not "no design for dark-mode visitors" but a palette that
   is already comfortable in a dark room: a warm, low-glare ground, body text at
   9.5:1 rather than black on white, and depth from a lighter surface rather than
   from borders. The dark BANDS (.panel, .site-foot, the skip link) are unchanged
   and stay dark — they are part of the identity, not a theme.
   ---------------------------------------------------------------------- */

/* ---------- reset ------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

/* `[hidden]` must actually hide. The user-agent rule is `[hidden]{display:none}`
   at zero specificity, so ANY class that sets `display` out-specifies it — and
   `.card` sets `display: flex`. Measured 2026-10-11: that silently un-hid the
   fail-closed "disclaimer incomplete" guard on the capture page, so the warning
   rendered under a complete, confirmed disclaimer. A guard that cannot be
   hidden is not a guard. */
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  font-family: var(--font);
  /* 18px floor, fluid to 20px — older readers are the primary audience [W3C] */
  font-size: clamp(1.125rem, 1.05rem + .35vw, 1.25rem);
  line-height: 1.6;                 /* body leading stays loose */
  color: var(--body);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;                 /* no horizontal scroll at 320px */
  min-height: 100vh;
}
img, svg, video { display: block; max-width: 100%; }
img { height: auto; }
button, input, select, textarea { font: inherit; color: inherit; }
a { color: var(--brand); text-underline-offset: 2px; }
ul, ol { padding-inline-start: 1.25em; }

/* headings: -2% tracking, 110-120% leading [KJ]. Tight leading is headings
   ONLY — body copy above deliberately keeps 1.6. */
h1, h2, h3, h4 {
  color: var(--ink);
  font-weight: 650;
  letter-spacing: -.02em;
  line-height: 1.12;
  text-wrap: balance;
}
h1 { font-size: clamp(2rem, 1.5rem + 2.6vw, 3.25rem); }
h2 { font-size: clamp(1.55rem, 1.3rem + 1.1vw, 2.15rem); }
h3 { font-size: clamp(1.2rem, 1.1rem + .4vw, 1.4rem); line-height: 1.2; }
p { max-width: 68ch; text-wrap: pretty; }

/* focus: ONE consistent visible ring on everything, keyboard-only [W3C] */
:focus-visible {
  outline: 3px solid var(--brand);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}
::selection { background: var(--brand-100); color: var(--ink); }

/* ---------- layout ------------------------------------------------------ */
.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--s5); }
section { padding-block: var(--s10); }
.section--tight { padding-block: var(--s8); }
/* optical rhythm [TG]: a little more room below a block than above it */
.stack > * + * { margin-top: var(--s4); }
.stack-lg > * + * { margin-top: var(--s6); }
.center { text-align: center; }
.center p { margin-inline: auto; }
.center .head { margin-inline: auto; }

.head { max-width: 62ch; margin-bottom: var(--s7); }

/* eyebrow: a small tell that says "this is a label", not content [KJ] */
.eyebrow {
  display: inline-flex; align-items: center; gap: var(--s2);
  font-size: .82rem; font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase; color: var(--brand);
  margin-bottom: var(--s3);
}
.eyebrow::before {
  content: ""; inline-size: 22px; block-size: 2px;
  background: var(--accent); border-radius: 2px;
}
.lede { font-size: 1.08em; color: var(--muted); max-width: 60ch; }
.note { font-size: .88em; color: var(--muted); }

/* ---------- buttons ----------------------------------------------------
   Four states minimum [KJ]: default, hover, active(pressed), disabled — plus
   focus-visible from the global rule. Press = a physical nudge with a
   rubber-band-ish ease [AP], never a bounce.
   ----------------------------------------------------------------------- */
.btn {
  --btn-bg: var(--btn-primary-bg);
  --btn-bg-hover: var(--btn-primary-bg-hover);
  --btn-fg: var(--btn-primary-fg);
  --btn-bd: transparent;
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--s2);
  min-height: var(--tap);
  padding: var(--s3) var(--s6);
  border: 1.5px solid var(--btn-bd);
  border-radius: var(--r-md);
  background: var(--btn-bg); color: var(--btn-fg);
  font-weight: 650; text-decoration: none; text-align: center;
  cursor: pointer;
  transition: background-color .18s ease, border-color .18s ease,
              transform .12s cubic-bezier(.2, .8, .3, 1.2), box-shadow .18s ease;
}
.btn svg { inline-size: 1.05em; block-size: 1.05em; flex: none; }
.btn:hover { background: var(--btn-bg-hover); }        /* hover */
.btn:active { transform: scale(.975); }               /* active / pressed */
.btn[disabled], .btn[aria-disabled="true"] {
  opacity: .55; cursor: not-allowed; transform: none;
}
.btn--wa {
  --btn-bg: var(--btn-wa-bg);
  --btn-bg-hover: var(--btn-wa-bg-hover);
  --btn-fg: var(--btn-wa-fg);
}
.btn--danger { --btn-bg: var(--btn-danger-bg); --btn-fg: var(--btn-danger-fg); }
/* ghost button for SECONDARY actions only [KJ]
   Inside a dark band the control flips with the BAND, not with the theme: the
   light theme's near-black ghost label was invisible on --panel-bg (measured
   1:1 on the home page), and its white hover fill would swallow a light label.
   The hover fill therefore comes from a token the band can re-point. */
.site-foot, .panel {
  --btn-ghost-fg:    var(--band-ghost-fg);
  --btn-ghost-bd:    var(--band-ghost-bd);
  --btn-ghost-hover: var(--band-ghost-hover);
}
.btn--ghost {
  --btn-bg: transparent;
  --btn-bg-hover: var(--btn-ghost-hover);
  --btn-fg: var(--btn-ghost-fg);
  --btn-bd: var(--btn-ghost-bd);
}
.btn--ghost:hover { border-color: var(--btn-ghost-fg); }
.btn--wide { width: 100%; }
.btn--lg { min-height: 56px; font-size: 1.05em; padding-inline: var(--s7); }
/* a real, non-fake affordance: the link that looks like a link */
.btn--plain {
  min-height: 44px; padding: var(--s2) 0; background: none; color: var(--brand);
  border: 0; border-radius: 0; text-decoration: underline; font-weight: 600;
}
.btn--plain:hover { background: none; color: var(--brand-700); }

.row { display: flex; flex-wrap: wrap; gap: var(--s3); align-items: center; }
.row--end { justify-content: flex-end; }

/* ---------- chips (trust tells, non-interactive) ------------------------ */
.chips { display: flex; flex-wrap: wrap; gap: var(--s2); }
.chip {
  display: inline-flex; align-items: center; gap: var(--s2);
  padding: var(--s1) var(--s4);
  border-radius: var(--r-pill);
  background: var(--brand-100); color: var(--brand-700);
  border: 1px solid var(--line-soft);
  font-size: .84em; font-weight: 600;
}
.chip svg { inline-size: 1em; block-size: 1em; }

/* ---------- cards ------------------------------------------------------- */
.grid { display: grid; gap: var(--s5); grid-template-columns: 1fr; min-width: 0; }
.grid > * { min-width: 0; }
@media (min-width: 768px) {                 /* tablet checkpoint */
  .grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1024px) {                /* laptop checkpoint */
  .grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .grid--split { grid-template-columns: 1.1fr .9fr; align-items: center; }
}

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--s7);
  box-shadow: var(--sh-1);
  display: flex; flex-direction: column;
  min-width: 0;
}
.card > h3 { margin-bottom: var(--s2); }
.card p { color: var(--muted); }
.card .card__foot { margin-top: auto; padding-top: var(--s5); }
.card--quiet { box-shadow: none; background: var(--surface-2); }
.card--brand { background: var(--brand-050); border-color: var(--brand-100); }

/* icon tile: icon size tied to the text line-height, not a magic number [KJ] */
.tile {
  inline-size: 46px; block-size: 46px; flex: none;
  display: grid; place-items: center;
  border-radius: var(--r-md);
  background: var(--brand-100); color: var(--brand-700);
  margin-bottom: var(--s5);
}
.tile svg { inline-size: 24px; block-size: 24px; }
.tile--accent { background: var(--accent-100); color: var(--accent); }

/* ---------- panels (dark bands for rhythm) ------------------------------ */
.panel {
  background: var(--panel-bg); color: var(--panel-fg);
  /* Re-point the semantic tokens for anything INSIDE the dark ground. This is
     the systemic fix: .note, <p>, <ul> and headings each resolve to a readable
     colour here without needing a selector for every combination. */
  --ink: #ffffff;
  --body: var(--panel-fg);
  --muted: var(--panel-muted);
  border-radius: var(--r-xl);
  padding: clamp(28px, 5vw, 56px);
}
.panel h2, .panel h3 { color: #fff; }
.panel p { color: var(--panel-fg); }
/* :not(.btn) matters — without it this rule outranks .btn and repaints button
   text mint-on-teal at 4.0:1. Buttons keep their own verified pair. */
.panel a:not(.btn):not(.chip) { color: var(--panel-link); }

/* ---------- hero -------------------------------------------------------
   Text-first by design: no hero bitmap means the LCP element is text, which
   is what keeps LCP under budget on a 4G phone. The one decorative layer is a
   soft gradient scrim, not a flat overlay [KJ].
   ----------------------------------------------------------------------- */
.hero { position: relative; padding-block: clamp(32px, 6vw, 72px) clamp(40px, 7vw, 80px); }
.hero::before {                      /* decorative only, never above text */
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(42rem 24rem at 88% -12%, rgba(0, 55, 127, .10), transparent 62%),
    radial-gradient(34rem 22rem at -8% 110%, rgba(226, 5, 21, .06), transparent 60%);
}
.hero > .wrap { position: relative; z-index: 1; }

/* AEP band: highest-contrast strip on the page, used once [KJ] */
.band {
  background: var(--accent-100);
  border-block: 1px solid var(--accent-200);
  color: var(--accent);
  padding-block: var(--s3);
  text-align: center; font-weight: 650; font-size: .95em;
}
.band strong { font-weight: 800; }

/* ---------- steps (three-tap rule made literal) ------------------------- */
.steps { list-style: none; padding: 0; counter-reset: step; }
.steps li {
  counter-increment: step;
  position: relative;
  padding: var(--s2) 0 var(--s5) 3.1rem;
}
.steps li::before {
  content: counter(step);
  position: absolute; inset-inline-start: 0; inset-block-start: 0;
  inline-size: 2.1rem; block-size: 2.1rem;
  display: grid; place-items: center;
  border-radius: var(--r-pill);
  background: var(--brand-100); color: var(--brand-700);
  font-weight: 700; font-size: .95rem;
}

/* ---------- media + gradient scrim ------------------------------------- */
.figure { margin: 0; }
.figure img {
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  box-shadow: var(--sh-1);
  inline-size: 100%;
}
.figure figcaption { margin-top: var(--s2); font-size: .84em; color: var(--muted); }
.media-grid { display: grid; gap: var(--s5); grid-template-columns: 1fr; }
@media (min-width: 640px) { .media-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ---------- carrier logo wall ------------------------------------------ */
/* Six marks, normalised by HEIGHT and allowed to keep their own width. That
   is how a logo wall is supposed to work: a 5.8:1 wordmark and a 1:1 symbol
   both get 40px of cap height, so they read as peers instead of as one giant
   logo and five shrimps. HEIGHT rules also mean the widest mark (HealthSpring)
   is the one that gets clamped first on a narrow screen, never the other way
   round — a logo that is shrunk is still legible, a logo that is squashed is
   a brand violation.

   `object-fit: contain` is the guard, not the decoration: it letterboxes an
   aspect mismatch instead of stretching it. Every source file's real aspect is
   also declared on the <img> as width/height, so the tile reserves its space
   before the image loads and nothing on the page jumps (CLS 0). */
.logo-grid {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: var(--s4);
  grid-template-columns: 1fr;
}
@media (min-width: 480px) { .logo-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 820px) { .logo-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.logo-tile {
  display: grid; place-items: center;
  min-block-size: 84px;
  padding: var(--s4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.logo-tile img {
  inline-size: auto; block-size: 34px;
  max-inline-size: 100%;
  object-fit: contain;
}
@media (min-width: 820px) {
  .logo-tile { min-block-size: 104px; padding: var(--s5) var(--s6); }
  .logo-tile img { block-size: 40px; }
}

/* Symbol-only marks get a name. Five of the six are wordmarks that identify
   themselves; Devoted Health publishes a symbol (the two-tone block) with no
   public logotype, and a lone coloured shape in a wall of names identifies
   nobody. The label is TYPESET TEXT, not a redrawn logo — it never pretends to
   be their lettering — and it is why the symbol can also be given more optical
   height than the wordmarks around it. */
.logo-tile--named { gap: var(--s2); align-content: center; }
.logo-tile--named img { block-size: 44px; }
.logo-tile__name {
  font-size: .78rem; font-weight: 600;
  letter-spacing: .01em; color: var(--muted);
  text-align: center; line-height: 1.2;
}

/* The ownership line under the wall. It is not fine print for legal reasons
   alone: a carrier mark on an independent agent's site can read as endorsement
   in both directions (that the carrier backs us, or that we speak for it). */
.logo-ownership { max-width: 72ch; }

/* text over an image: a gradient scrim, never a flat wash [KJ] */
.scrim { position: relative; border-radius: var(--r-lg); overflow: hidden; }
.scrim img { inline-size: 100%; }
.scrim figcaption {
  position: absolute; inset-inline: 0; inset-block-end: 0;
  padding: var(--s8) var(--s6) var(--s5);
  color: #fff; font-weight: 600; font-size: .95em;
  background: linear-gradient(to top, rgba(6, 18, 24, .88), rgba(6, 18, 24, .55) 55%, transparent);
}

/* ---------- forms ------------------------------------------------------ */
.form { display: grid; gap: var(--s5); }
.field { display: grid; gap: var(--s2); }
.field > label, .label {
  font-weight: 650; color: var(--ink); font-size: .96em;
  /* labels are always visible — never placeholder-only [W3C older users] */
}
.field .hint { font-size: .85em; color: var(--muted); font-weight: 400; }
.req { color: var(--warn); font-weight: 700; }

input[type="text"], input[type="tel"], input[type="email"], input[type="number"],
select, textarea {
  inline-size: 100%;
  min-height: var(--tap);
  padding: var(--s3) var(--s4);
  border: 1.5px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink);
  transition: border-color .18s ease, box-shadow .18s ease;
}
input:hover, select:hover, textarea:hover { border-color: var(--muted); }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 4px rgba(0, 55, 127, .16);
}
input[aria-invalid="true"], select[aria-invalid="true"] {
  border-color: var(--warn);
  box-shadow: 0 0 0 4px rgba(179, 38, 30, .14);
}
textarea { min-height: 7rem; resize: vertical; }

/* consent block: a boundary and a tint, so it reads as legal text [KJ] */
.consent {
  display: flex; gap: var(--s3); align-items: flex-start;
  padding: var(--s4);
  border: 1.5px dashed var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
  font-size: .88em; color: var(--muted); font-weight: 400;
}
.consent input[type="checkbox"] {
  inline-size: 1.4rem; block-size: 1.4rem; margin-top: .15rem;
  flex: none; accent-color: var(--brand); min-height: 0;
}
.consent strong { color: var(--ink); }

/* honeypot: hidden from people, present for bots.
   It is anchored to the top-left of its containing block because a 1px box left
   at its static position sat a few pixels past the right edge of the form — 3px
   of horizontal scroll at 320, 85px at 1280 — which is a real sideways drag on a
   phone. Clipped and 1px, so anchoring it changes nothing a person can see. */
.hp {
  position: absolute !important; inset-block-start: 0; inset-inline-start: 0;
  inline-size: 1px; block-size: 1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* status: colour PLUS an icon and text — never colour alone [W3C] */
.status { font-weight: 600; min-height: 1.5em; }
.status[data-kind="ok"]   { color: var(--ok); }
.status[data-kind="err"]  { color: var(--warn); }
.status[data-kind="ok"]::before  { content: "✓ "; }
.status[data-kind="err"]::before { content: "! "; }

/* loading: hold the thread with a visible state, never an inert button [TG] */
.btn[data-loading="true"] { pointer-events: none; opacity: .85; }
.btn[data-loading="true"]::after {
  content: ""; inline-size: 1em; block-size: 1em; margin-inline-start: var(--s2);
  /* currentColor, so the spinner works on a light fill with dark text too */
  border: 2px solid currentColor; border-top-color: transparent; opacity: .55;
  border-radius: 50%; animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- header / nav ----------------------------------------------- */
.skip {
  position: absolute; inset-inline-start: -9999px; inset-block-start: 0;
  background: var(--panel-bg); color: #fff; padding: var(--s3) var(--s5);
  border-radius: 0 0 var(--r-sm) 0; z-index: 100;
}
.skip:focus { inset-inline-start: 0; }

.site-head {
  position: sticky; inset-block-start: 0; z-index: 50;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-block-end: 1px solid var(--line-soft);
}
.site-head__in {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s3); flex-wrap: wrap;
  padding-block: var(--s3);
}
.brand { display: inline-flex; align-items: center; gap: var(--s3); text-decoration: none; }
.brand__mark {
  /* The owner's lockup, not a square tile: it is 1.77:1, so the height is the
     only dimension worth pinning and the width follows. 44px keeps it clear of
     the 72px header and still legible on a phone. */
  block-size: 44px; inline-size: auto; flex: none;
}
.brand__txt { display: grid; line-height: 1.1; }
.brand__name { color: var(--ink); font-weight: 700; font-size: 1.06rem; letter-spacing: -.015em; }
.brand__sub { color: var(--muted); font-size: .76rem; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; }

.nav { display: flex; flex-wrap: wrap; gap: var(--s1); }
.nav a {
  display: inline-flex; align-items: center;
  min-height: 44px; padding: 0 var(--s3);        /* 44px target [W3C] */
  /* 12px, not 16px: the owner's lockup is 1.77:1, so the brand block is ~30px
     wider than the old square tile was. Without this the 1100px header row
     overflowed by 5px at 1280 and the language toggle wrapped to a second line.
     The tap target is the 44px min-height, not the horizontal padding. */
  border-radius: var(--r-sm);
  color: var(--body); text-decoration: none;
  font-size: .96em; font-weight: 550;
}
.nav a:hover { background: var(--line-soft); color: var(--ink); }
.nav a[aria-current="page"] { color: var(--brand); font-weight: 700; background: var(--brand-050); }

.head-tools { display: flex; align-items: center; gap: var(--s2); }
/* On a page with no navigation the tools are the only thing in that row, and
   `justify-content: space-between` puts a single wrapped child at the START of
   its line — so on a 320px phone the language toggle dropped under the brand and
   sat hard left, looking like a stray control rather than the corner it is.
   Scoped to the funnel header so no other page's layout moves. */
.site-head--funnel .head-tools { margin-inline-start: auto; }
.lang { display: inline-flex; border: 1.5px solid var(--line); border-radius: var(--r-pill); overflow: hidden; }
.lang button {
  min-height: 44px; padding: 0 var(--s4); border: 0; background: transparent;
  color: var(--body); font-size: .86rem; font-weight: 650; cursor: pointer;
  transition: background-color .16s ease, color .16s ease;
}
.lang button:hover { background: var(--line-soft); }
/* --paper is the inverse of --ink in BOTH themes, so this pair stays readable
   when the theme flips (dark theme: light fill, dark text). Hard-coding #fff
   here produced white-on-white at 1.12:1. */
.lang button[aria-pressed="true"] { background: var(--ink); color: var(--paper); }

.nav-toggle {
  display: none;
  min-height: 44px; min-inline-size: 44px;
  align-items: center; justify-content: center; gap: 4px; flex-direction: column;
  border: 1.5px solid var(--line); border-radius: var(--r-sm);
  background: transparent; cursor: pointer;
}
.nav-toggle span { display: block; inline-size: 18px; block-size: 2px; background: var(--ink); border-radius: 2px; transition: transform .2s ease, opacity .2s ease; }
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

@media (max-width: 899px) {
  .nav-toggle { display: inline-flex; }
  .nav {
    display: none; order: 3; inline-size: 100%;
    flex-direction: column; gap: 0;
    padding-block: var(--s2);
    border-block-start: 1px solid var(--line-soft);
  }
  .site-head[data-open="true"] .nav { display: flex; }
  .nav a { min-height: 48px; font-size: 1.02em; }
  #main { scroll-margin-top: 5rem; }        /* sticky head must not eat anchors */
}

/* ---------- sticky mobile action bar -----------------------------------
   Never covers the submit button: JS adds [data-hide] while the form is in
   view, and the bar reserves its own space via body padding so nothing is
   hidden underneath it.
   ----------------------------------------------------------------------- */
.sticky {
  position: fixed; inset-inline: max(var(--s3), env(safe-area-inset-left))
                          max(var(--s3), env(safe-area-inset-right));
  /* safe-area inset so notched phones don't clip the buttons */
  inset-block-end: max(var(--s3), env(safe-area-inset-bottom));
  z-index: 45;
  display: none; gap: var(--s2);
  padding: var(--s2);
  border-radius: var(--r-lg);
  background: color-mix(in srgb, var(--surface) 94%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid var(--line);
  box-shadow: var(--sh-2);                 /* floating layer -> stronger shadow */
}
.sticky .btn { flex: 1 1 0; padding-inline: var(--s3); }
@media (max-width: 767px) {
  .sticky { display: flex; }
  .sticky[data-hide="true"] { display: none; }
  body { padding-block-end: calc(72px + env(safe-area-inset-bottom)); }
}

/* ---------- footer ----------------------------------------------------- */
.site-foot {
  background: var(--panel-bg); color: var(--panel-muted);
  /* same systemic re-point as .panel */
  --ink: #ffffff;
  --body: var(--panel-fg);
  --muted: var(--panel-muted);
  padding-block: var(--s9) var(--s8); font-size: .84em;
}
.site-foot a { color: #cfe0e6; }
.site-foot strong { color: #eef4f7; }
.site-foot__grid { display: grid; gap: var(--s7); grid-template-columns: 1fr; }
@media (min-width: 768px) { .site-foot__grid { grid-template-columns: 1.3fr 1fr; } }
.site-foot h2 { color: #fff; font-size: 1rem; letter-spacing: 0; margin-bottom: var(--s3); }
.site-foot .legal { border-block-start: 1px solid rgba(255, 255, 255, .14); margin-block-start: var(--s7); padding-block-start: var(--s5); }
.site-foot .legal p { max-width: none; margin-bottom: var(--s3); }
/* The notice appears on the plain page ground (capture page) AND inside the
   dark footer band. A hard-coded light foreground is only readable on the
   band: on the page ground it measured 1.18:1 — invisible. So the box defaults
   to theme tokens and the dark-band look is scoped to the bands explicitly. */
.tmo {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: var(--s4) var(--s5);
  color: var(--body);
}
.site-foot .tmo, .panel .tmo {
  background: var(--tmo-band-bg);
  border-color: var(--tmo-band-bd);
  color: var(--tmo-band-fg);
}
/* The notice names the product line it is about, out loud. It sits in a footer
   that also carries real-estate and non-Medicare notices, so without this the
   sentence "we represent 6 organizations" reads as a claim about every line of
   insurance on the site. A label, not content [KJ signifier]. */
.tmo__tag {
  display: inline-flex; align-items: center; gap: var(--s2);
  margin-bottom: var(--s3);
  font-size: .76rem; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--brand);
}
.tmo__tag::before {
  content: ""; inline-size: 20px; block-size: 2px;
  background: currentColor; border-radius: 2px;
}
.site-foot .tmo__tag, .panel .tmo__tag { color: var(--panel-link); }
/* Uses the semantic tokens rather than a literal light grey, so the badge is
   readable wherever it is placed: on the page ground the tokens resolve dark,
   and inside a dark band .panel/.site-foot has already re-pointed them light. */
.fairhousing {
  display: inline-block; border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: var(--s1) var(--s3); font-weight: 650; color: var(--body);
}

/* ---------- micro-interaction: reveal on scroll ------------------------
   Confirms arrival, subtracts nothing, and disappears entirely for anyone
   who asked for reduced motion [W3C].
   ----------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  .reveal { opacity: 0; transform: translateY(14px); transition: opacity .6s cubic-bezier(.2, .6, .2, 1), transform .6s cubic-bezier(.2, .6, .2, 1); }
  .reveal.is-in { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }
}

/* ---------- bilingual engine (contract: unchanged from the previous site) */
.es, .en { display: none; }
body[data-lang="es"] .es { display: revert; }
body[data-lang="en"] .en { display: revert; }

/* ---------- utilities -------------------------------------------------- */
.visually-hidden {
  position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}
.mt0 { margin-top: 0; }
.mt4 { margin-top: var(--s4); }
.mt5 { margin-top: var(--s5); }
.mt6 { margin-top: var(--s6); }
.mt8 { margin-top: var(--s8); }
.mb0 { margin-bottom: 0; }
.prose > * + * { margin-top: var(--s4); }
.prose h2 { margin-top: var(--s8); }
.prose h3 { margin-top: var(--s6); }
.prose ul { margin-top: var(--s3); }
.prose li + li { margin-top: var(--s2); }
.prose { max-width: 72ch; }
.address { font-style: normal; }

/* legacy aliases — the previous markup keeps working while pages migrate */
a.button { display: inline-flex; align-items: center; gap: var(--s2); min-height: var(--tap); padding: var(--s3) var(--s6); background: var(--btn-primary-bg); color: var(--btn-primary-fg); text-decoration: none; border-radius: var(--r-md); font-weight: 650; }

/* ==========================================================================
   Page ground — the wash that keeps a text-heavy page from reading as a
   blank document

   It is a PSEUDO-ELEMENT on purpose, for two reasons that matter:
     * it is never in the ancestor chain, so it cannot tint text — every layer
       is <= 7% alpha, a fraction of one contrast step;
     * a background-image on <body> would defeat the rendered-contrast sweep,
       which treats anything with an ancestor background-image as
       text-over-an-image and skips it. The sweep has to keep working, so the
       decoration stays out of the box model's ancestry.
   ========================================================================== */
main { position: relative; }
main > * { position: relative; z-index: 1; }
main::before {
  content: ""; position: absolute; inset: 0;
  z-index: 0; pointer-events: none;
  background:
    radial-gradient(64rem 32rem at 10% -6%, rgba(0, 55, 127, .07), transparent 62%),
    radial-gradient(52rem 30rem at 96% 4%, rgba(226, 5, 21, .045), transparent 58%),
    linear-gradient(180deg, rgba(255, 255, 255, .40), rgba(255, 255, 255, 0) 320px);
}

/* ==========================================================================
   Qualifier — /empezar

   ONE question per view, and every question earns its place by changing the
   route [TG: design the flow, not the screen]. Subtraction is the point: the
   flow carries no progress meter, because the number of questions depends on
   the branch. "Paso 2 de 3" would be a number someone made up; this flow
   shows a question, then the next question, and says nothing it cannot prove.

   Two things here are structural rather than stylistic:
     * `.opt` is a real <button>, not a styled radio. Radio groups advance on
       arrow keys, so auto-advancing on `change` would fight the keyboard. A
       button advances on Enter/Space only, which is what a person expects.
     * the option label/hint split creates rank with weight and size, not
       with a border or an icon [KJ: hierarchy via contrast].
   ========================================================================== */
.wrap--read { max-width: 760px; }
/* The qualifier's hero is a signpost, not a poster: on a 320px phone the first
   question has to be visible without a scroll, so this page spends its
   vertical budget on the flow instead of on the headline's margins. */
.hero--compact { padding-block: clamp(24px, 4vw, 48px) clamp(16px, 3vw, 32px); }
/* The lede on this page is a promise, not a paragraph: body size keeps the
   first question inside the fold on a 320px phone. */
.lede--tight { font-size: 1em; }

.qs { display: flex; flex-direction: column; gap: var(--s6); }
.qs__step {
  border: 0; padding: 0; margin: 0; min-inline-size: 0;
  display: grid; gap: var(--s5);
  scroll-margin-top: 6rem;          /* the sticky head must not eat the focus */
}
/* A legend cannot hold an <h2>, so it carries the heading treatment itself:
   same -2% tracking and 110-120% leading as every other heading [KJ]. */
.qs__q {
  display: block; padding: 0;
  font-size: clamp(1.2rem, 1.1rem + .6vw, 1.5rem);
  font-weight: 700; letter-spacing: -.02em; line-height: 1.15;
  color: var(--ink);
}
.qs__opts { display: grid; gap: var(--s3); }

.opt {
  display: grid; gap: var(--s1);
  inline-size: 100%; min-height: 56px;
  padding: var(--s4) var(--s5);
  border: 1.5px solid var(--line); border-radius: var(--r-md);
  background: var(--surface); color: var(--ink);
  font: inherit; text-align: start; cursor: pointer;
  transition: border-color .18s ease, background-color .18s ease,
              transform .12s cubic-bezier(.2, .8, .3, 1.2);
}
.opt__label { font-weight: 650; }
.opt__hint { font-size: .82em; font-weight: 400; color: var(--muted); }
.opt:hover { border-color: var(--brand); background: var(--brand-050); }
.opt:active { transform: scale(.99); }
.opt[disabled] { opacity: .55; cursor: not-allowed; }

.qs__foot { display: flex; flex-wrap: wrap; gap: var(--s3); align-items: center; justify-content: space-between; }
/* the contact step is a form, and an outcome is a card, so each needs the same
   landing room as a question: without it the sticky header covers the heading
   that was just announced. */
.qs form,
.card[data-outcome] { scroll-margin-top: 6rem; }

/* Outcome panels. The accent is a 4px edge in a SEMANTIC token — no tinted
   fill, because a tint is a new colour pair that then has to be contrast-
   checked in both themes, and every tinted pair so far has eventually drifted. */
.card--ok    { border-inline-start: var(--s1) solid var(--ok); }
.card--limit { border-inline-start: var(--s1) solid var(--accent); }

/* ---------- transitions between questions ------------------------------
   The step that ARRIVES is what moves. Animating the departing step would
   delay the next question behind an exit nobody is watching, and the leaving
   step has already lost focus and its place in the tab order.

   Direction is a reading cue, not decoration: forward lifts from below, back
   descends from above, so "Atrás" reads as the same journey in reverse rather
   than as the same animation replayed. site.js sets data-dir; nothing here
   animates anything on its own.

   `backwards` fill, never `both`. With `both`, the closing keyframe keeps
   `transform: none` applied for the rest of the element's life — which silently
   kills `.opt:active { transform: scale(.99) }`, the press-state feedback on
   every answer. An animation that outlives itself and overrides the interaction
   states below it is exactly the kind of bug that survives review.

   The whole block sits inside no-preference: for a visitor who asked for
   reduced motion there is no animation to disable, and the page is a plain
   swap of one question for the next. */
@media (prefers-reduced-motion: no-preference) {
  .qs[data-dir="fwd"]  .qs__step:not([hidden]) { animation: step-in-fwd  .28s cubic-bezier(.22, .61, .36, 1) backwards; }
  .qs[data-dir="back"] .qs__step:not([hidden]) { animation: step-in-back .28s cubic-bezier(.22, .61, .36, 1) backwards; }
  .qs[data-dir="fwd"]  .form:not([hidden])     { animation: step-in-fwd  .3s  cubic-bezier(.22, .61, .36, 1) backwards; }
  .card[data-outcome]:not([hidden])            { animation: step-in-fwd  .32s cubic-bezier(.22, .61, .36, 1) backwards; }

  /* Answers arrive in a short stagger, so a new question reads as being laid
     out in front of the person instead of as the screen replacing itself.
     40ms apart, five steps: the last option lands inside the length of one
     breath and nothing feels slow to tap. */
  .qs__step:not([hidden]) .opt { animation: opt-in .3s cubic-bezier(.22, .61, .36, 1) backwards; }
  .qs__step:not([hidden]) .opt:nth-child(2) { animation-delay: .04s; }
  .qs__step:not([hidden]) .opt:nth-child(3) { animation-delay: .08s; }
  .qs__step:not([hidden]) .opt:nth-child(4) { animation-delay: .12s; }
  .qs__step:not([hidden]) .opt:nth-child(5) { animation-delay: .16s; }
}

@keyframes step-in-fwd  { from { opacity: 0; transform: translateY(10px); } }
@keyframes step-in-back { from { opacity: 0; transform: translateY(-8px); } }
@keyframes opt-in       { from { opacity: 0; transform: translateY(6px); } }

/* The booking button rides the global [hidden] rule above: while BOOKING_URL
   in site.js is empty it stays out of the page entirely, rather than being
   shown as a button that goes nowhere. */

/* ---------- newsletter signup (in the footer) --------------------------- */
/* Sits on the dark footer band, so it re-points text colours the same way the
   rest of .site-foot does. It is deliberately one field: this is an audience
   list, not a lead form, and there is nowhere to type anything sensitive. */
.site-foot .signup {
  border-block-start: 1px solid rgba(255, 255, 255, .14);
  margin-block-start: var(--s7);
  padding-block-start: var(--s5);
  display: grid;
  gap: var(--s2);
}
/* Every rule is scoped to .site-foot: that is the dark band, and a literal
   light foreground is only correct inside it. */
.site-foot .signup h2 { color: #fff; font-size: 1rem; letter-spacing: 0; margin: 0; }
.site-foot .signup > p { color: #cfe0e6; margin: 0; font-size: .95em; max-inline-size: 52ch; }
.site-foot .signup form {
  display: flex; flex-wrap: wrap; gap: var(--s3); align-items: center;
  margin-block: var(--s2) 0;
}
/* On the dark band the input keeps a white field: a tinted field would fail
   contrast for its own text and would read as disabled. */
.site-foot .signup input[type="email"] {
  inline-size: auto; flex: 1 1 15rem; min-inline-size: 0;
  background: #fff; color: var(--ink); border-color: rgba(0, 0, 0, .25);
}
.site-foot .signup .btn { flex: 0 0 auto; }
.site-foot .signup .status { flex: 1 1 100%; min-height: 0; font-size: .95em; }
.site-foot .signup .status[data-kind="ok"] { color: #9fe0b4; }
.site-foot .signup .status[data-kind="err"] { color: #ffb4a8; }
.site-foot .signup .signup__fine { font-size: .82em; color: #a9bcc6; }

