/* Public rental calculator — /calculadora-alquileres
 *
 * 🔴 ONE stylesheet, TWO hosts, and they do not share a token layer.
 *
 *   1. The Valoris landing (`base_public.html`) loads `landing-system.min.css`, so `--vs-*` exists
 *      and `.vs-cta` exists. It does NOT load `valoris-design-system.css`: `.v-card`, `.v-input`,
 *      `.v-btn`, `.v-table`, `.v-badge` and `.v-alert` are all UNSTYLED here, and a first version of
 *      this page used them and rendered as raw HTML. `CLAUDE.md` lists the landing surfaces as
 *      deliberately excluded, so that is the base being right, not the base being wrong.
 *
 *   2. An agency's own website (`themes/<id>/base.html`) loads its per-theme Tailwind build and this
 *      file, and NOTHING else. `--vs-*` is undefined there — measured in a browser, `grep -c -- --vs-
 *      app/crm/static/css/theme-*.css` is 0 for all five themes. Every `var(--vs-…)` therefore went
 *      "invalid at computed-value time", which does NOT fall back to the previous declaration: it
 *      unsets the property. The measured damage was `<h1>` at 16px, cards with no border and no
 *      background, a 44-row table with no row separators,
 *      "EL QUE VIENE" as white text on a transparent chip (1,09:1) and the headline's big number as
 *      white text on a white page (1,05:1) — the answer, invisible.
 *
 * So the rule for this file: NOTHING reads `--vs-*` directly. Everything reads a local `--rc-*`
 * token that takes the landing value when it is there and a literal when it is not. That keeps the
 * Valoris page byte-identical in appearance and makes the agency page exist at all.
 *
 * Contrast: text ≥4,5:1 and UI borders ≥3:1 (WCAG 2.2 AA, SC 1.4.3 / 1.4.11). The literals below are
 * the ones that clear it — several of the landing tokens do not at these sizes, and each of those is
 * commented where it is replaced.
 */

.rc-page {
  /* ---- surface-agnostic token layer ------------------------------------- */
  --rc-font: var(--vs-font, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif);

  --rc-text: var(--vs-text, #1e293b);
  --rc-text-secondary: var(--vs-text-secondary, #64748b);
  /* 🔴 NOT `--vs-text-muted` (#94a3b8): 2,45:1 on the page background. It carried the legal
     disclaimer, the "(opcional)" marker and the "UN EJEMPLO" label — the one line that tells a
     visitor the big number below is not their contract. 5,28:1 here. */
  --rc-text-muted: #5b6a7d;
  /* Uppercase micro-labels and chips, which sit on tinted surfaces where #64748b lands at 3,9–4,3:1. */
  --rc-text-label: #475569;
  --rc-text-on-dark: var(--vs-text-light, #cbd5e1);
  --rc-heading: var(--vs-dark-hero, #0f172a);

  --rc-surface: var(--vs-bg-alt, #ffffff);
  --rc-surface-sunken: var(--vs-border-light, #f1f5f9);
  --rc-border: var(--vs-border, #e2e8f0);
  /* An interactive control needs 3:1 against its surround (SC 1.4.11); the hairline divider is 1,2:1. */
  --rc-border-interactive: #8b95a1;

  --rc-primary: var(--vs-primary, #2563eb);
  /* The button follows the HOST's brand: the agency themes publish `--primary-color` and style their
     own `.btn-primary` with it, so the calculator's CTA matches the site it is embedded in. The
     Valoris landing does not define it (verified in-browser) and falls through to the landing blue. */
  --rc-brand: var(--primary-color, var(--rc-primary));
  --rc-on-brand: #ffffff;
  /* Text on a known dark or saturated fill (the headline gradient, the accent chip, the error
     glyph). Not a theme choice — the paired ink for a fill this file controls. */
  --rc-ink-inverse: #ffffff;

  --rc-accent-soft: #eff6ff;
  --rc-accent-ink: #1d4ed8;
  --rc-warn-soft: #fef3c7;
  --rc-warn-ink: #92400e;
  --rc-danger-soft: #fee2e2;
  --rc-danger-line: var(--vs-danger, #ef4444);
  --rc-danger-ink: #b91c1c;

  --rc-headline-from: var(--vs-dark-hero, #0f172a);
  --rc-headline-to: var(--vs-dark-mid, #1e3a5f);

  --rc-radius: var(--vs-radius, 10px);
  --rc-h1: var(--vs-h2, 2rem);
  /* How much sticky chrome the host page pins above the content. Overwritten at runtime by
     rental-calculator.js, which measures it: the Valoris navbar is 56px and the five theme headers
     are 64–80px, so a single constant would either tuck the frozen table header under the host's
     header or leave a gap under it. This value is only the pre-measurement default. */
  --rc-sticky-top: 64px;

  max-width: 1080px;
  margin: 0 auto;
  padding: 48px 20px 72px;
  font-family: var(--rc-font);
  color: var(--rc-text);
}

/* 🔴 Neither host ships a rule for it — enumerated `document.styleSheets` on both and found zero
   `[x-cloak]` rules — so every `x-cloak` in the two templates was inert. Measured with JavaScript
   off: an empty 666×28 red error bar painted at the top of the answer column on every load, and
   stayed there for anyone whose Alpine request from the CDN was slow or failed. Scoped to the
   calculator so it cannot change how the host page's own Alpine components boot. */
.rc-page [x-cloak] {
  display: none !important;
}

.rc-hero h1 {
  font-size: var(--rc-h1);
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--rc-heading);
  margin: 0 0 10px;
  line-height: 1.2;
}

.rc-lede {
  color: var(--rc-text-secondary);
  font-size: 1.05rem;
  line-height: 1.65;
  max-width: 62ch;
  margin: 0 0 32px;
}

.rc-grid {
  display: grid;
  grid-template-columns: 350px 1fr;
  gap: 24px;
  align-items: start;
}

.rc-card {
  background: var(--rc-surface);
  border: 1px solid var(--rc-border);
  border-radius: var(--rc-radius);
  overflow: hidden;
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06);
}

.rc-cardhead {
  padding: 13px 18px;
  border-bottom: 1px solid var(--rc-border);
  background: var(--rc-surface-sunken);
  /* Rounded here and not only clipped by the card, because the table card gives up `overflow: hidden`
     on desktop so its header row can freeze (see the sticky block at the bottom). */
  border-radius: calc(var(--rc-radius) - 1px) calc(var(--rc-radius) - 1px) 0 0;
  font-size: 0.78rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--rc-text-label);
}

.rc-cardbody {
  padding: 18px;
}

/* --- form controls: the landing language has none, so they live here -------- */

.rc-field {
  margin-bottom: 16px;
}

.rc-label {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--rc-text);
  margin-bottom: 6px;
}

.rc-optional {
  font-weight: 400;
  color: var(--rc-text-muted);
}

/* Required AND optional are both marked, because marking only the optional ones is the case that
   tests worst (Baymard/NN-g on required-field marking): a visitor reads "(opcional)" on one field and
   concludes the unmarked ones are optional too. */
.rc-req {
  color: var(--rc-danger-ink);
  font-weight: 700;
  margin-left: 2px;
}

.rc-legend {
  font-size: 0.78rem;
  color: var(--rc-text-muted);
  margin: 0 0 14px;
  line-height: 1.45;
}

.rc-input {
  width: 100%;
  box-sizing: border-box;
  border: 1px solid var(--rc-border-interactive);
  border-radius: 8px;
  padding: 11px 12px;
  font-family: var(--rc-font);
  font-size: 1rem;
  color: var(--rc-text);
  background: var(--rc-surface);
}

.rc-input:focus-visible,
.rc-input:focus {
  outline: 2px solid var(--rc-primary);
  outline-offset: 1px;
  border-color: var(--rc-primary);
}

.rc-hint {
  display: block;
  font-size: 0.78rem;
  color: var(--rc-text-secondary);
  margin-top: 5px;
  line-height: 1.45;
}

/* --- buttons ---------------------------------------------------------------
 * The landing has `.vs-cta`; the agency themes do not, and their Tailwind preflight resets a
 * <button> to a transparent, zero-padding, weight-400 box. Measured on the agency site before this
 * existed: "Calcular" was 314×24 of plain text and "Contactanos" was an unstyled, undecorated link
 * — the only conversion element on the page, indistinguishable from the paragraph above it.
 */

.rc-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 14px 32px;
  border: none;
  border-radius: var(--rc-radius);
  background: var(--rc-brand);
  color: var(--rc-on-brand);
  font-family: var(--rc-font);
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.2s, box-shadow 0.2s, filter 0.2s;
}

.rc-btn:hover {
  color: var(--rc-on-brand);
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}

/* Neither host defines a focus ring for its buttons — landing-system.css has no `focus` rule at all
   — so the calculator brings its own rather than leaning on the UA default over a coloured fill. */
.rc-btn:focus-visible {
  outline: 3px solid var(--rc-primary);
  outline-offset: 2px;
}

.rc-btn[disabled] {
  filter: grayscale(0.35);
  transform: none;
  box-shadow: none;
  cursor: progress;
}

.rc-submit {
  width: 100%;
  justify-content: center;
  margin-top: 4px;
}

/* --- the answer ------------------------------------------------------------ */

.rc-example-tag {
  font-size: 0.72rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--rc-text-muted);
  margin-bottom: 6px;
}

.rc-example-lede {
  font-size: 0.95rem;
  color: var(--rc-text-secondary);
  line-height: 1.6;
  margin: 0 0 18px;
}

.rc-headline {
  background: var(--rc-headline-from);
  background: linear-gradient(135deg, var(--rc-headline-from), var(--rc-headline-to));
  border-radius: 14px;
  padding: 26px 28px;
  margin-bottom: 18px;
  color: var(--rc-ink-inverse);
}

.rc-k {
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--rc-text-on-dark);
  margin-bottom: 6px;
}

.rc-n {
  font-size: 2.9rem;
  font-weight: 800;
  letter-spacing: -0.03em;
  /* Tabular figures so a column of rents lines up digit over digit. */
  font-variant-numeric: tabular-nums;
  line-height: 1.05;
  color: var(--rc-ink-inverse);
}

.rc-d {
  font-size: 0.95rem;
  color: var(--rc-text-on-dark);
  margin-top: 10px;
  line-height: 1.5;
}

.rc-d strong {
  color: var(--rc-ink-inverse);
}

.rc-table-wrap {
  overflow-x: auto;
}

.rc-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}

.rc-table th {
  background: var(--rc-surface-sunken);
  text-align: left;
  padding: 10px 14px;
  font-size: 0.72rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--rc-text-label);
  white-space: nowrap;
}

.rc-table td {
  padding: 11px 14px;
  border-top: 1px solid var(--rc-border);
  color: var(--rc-text);
}

/* --- the frozen header, at EVERY width (decided 2026-08-29) -----------------
 * It used to freeze only from 769px up. On a phone the header row scrolled away after the sixth
 * row, and a 2018 contract adjusting quarterly is 35 rows: from there down the visitor read three
 * columns of numbers with no titles, and "which one was the rent" cost a scroll back to the top.
 *
 * 🔴 These two rules are ONE change. `position: sticky` resolves against the nearest scrollport, and
 * there were two in the chain: `.rc-table-wrap`'s `overflow-x: auto` makes `overflow-y` compute to
 * `auto` as well, and `.rc-card`'s `overflow: hidden` is a scrollport too. Pinned to a box that
 * never scrolls vertically, the header does not freeze — it just sits there. Shipping the sticky
 * rule without this one looks done and does nothing.
 *
 * 🔴 What opening the wrap costs, measured at 320px (track 288px), by the digits of the largest
 * rent in the schedule: 7 digits → 275px, 8 → 284px, 9 → 293px. So up to 8 digits the table fits
 * and nothing spills; from 9 it draws past the card instead of scrolling inside it. That is not a
 * regression the freeze introduced — the wrap is a grid item with `min-width: auto`, so today it
 * GROWS past its track rather than scrolling, and the page scrolls sideways by the same amount
 * (measured: 324px of document in a 320px viewport). Capping it with `min-width: 0` would make the
 * wrap scroll again and kill the freeze; the two cannot both be true on this layout.
 */
.rc-table-card,
.rc-table-card .rc-table-wrap {
  overflow: visible;
}

.rc-table thead th {
  position: sticky;
  top: var(--rc-sticky-top);
  z-index: 2;
  /* `border-collapse: collapse` drops a sticky cell's own border, so the rule under the frozen
     header is drawn as an inset shadow. */
  box-shadow: inset 0 -1px 0 var(--rc-border);
}

/* The browser's own scroll-into-view (a tab stop, an anchor) does not know about the host's sticky
   header — SC 2.4.11 Focus Not Obscured. The offset is published by the page's JS on load and on
   resize with no width test, so a phone that pins nothing gets 0 and the header parks at the top. */
.rc-page :is(input, select, button, a, [tabindex]) {
  scroll-margin-top: calc(var(--rc-sticky-top) + 16px);
}

/* The card stops clipping so the header can freeze, so the last row has to round itself. */
.rc-table tbody tr:last-child td:first-child {
  border-bottom-left-radius: calc(var(--rc-radius) - 1px);
}

.rc-table tbody tr:last-child td:last-child {
  border-bottom-right-radius: calc(var(--rc-radius) - 1px);
}

.rc-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  /* 600, not 700: every rent in the column was bold, so nothing was. The row that matters is bolder
     (`tr.rc-next td` below wins on specificity). */
  font-weight: 600;
  white-space: nowrap;
}

.rc-table tr.rc-now td {
  background: var(--rc-surface-sunken);
}

.rc-table tr.rc-next td {
  background: var(--rc-accent-soft);
  font-weight: 700;
}

/* A 44-tranche schedule is 1.800px tall and the two rows a visitor came for — what they pay now and
   what they pay next — are somewhere in the middle of it. A tinted row is a colour-only cue and it is
   the first thing lost when the sheet meets a host that overrides backgrounds; the bar is the
   redundant one, and it reads at a glance while scrolling. */
.rc-table tr.rc-now td:first-child {
  box-shadow: inset 3px 0 0 var(--rc-text-label);
}

.rc-table tr.rc-next td:first-child {
  box-shadow: inset 3px 0 0 var(--rc-primary);
}

.rc-pct {
  /* 🔴 Body ink, not green (decided 2026-08-29). It passed AA in green; contrast was never the
     question. Green codes "good news", and half of this page's audience is the tenant who arrived
     by googling how much their rent goes up — the same number is the same fact for them and for the
     administrator, so the sheet states it and leaves the reading to whoever is looking. The weight,
     the alignment and the tinted row carry the emphasis the colour used to. */
  color: var(--rc-text);
  font-weight: 700;
  /* Right-aligned inside a fixed box so the "%" signs stack in a column: +7,27 and +70,72 are read
     against each other, and a ragged left edge is the one thing that stops that. */
  display: inline-block;
  min-width: 5.6ch;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.rc-tag {
  display: inline-block;
  font-size: 0.68rem;
  font-weight: 800;
  border-radius: 5px;
  padding: 2px 8px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  vertical-align: 1px;
}

.rc-tag--now {
  background: var(--rc-border);
  color: var(--rc-text-label);
}

.rc-tag--next {
  /* Deliberately the fixed accent and NOT `--rc-brand`: this is a data state, and a pale agency
     brand behind white 0,68rem text is how it stops being readable. */
  background: var(--rc-primary);
  color: var(--rc-ink-inverse);
}

.rc-tag--pending {
  background: var(--rc-warn-soft);
  color: var(--rc-warn-ink);
}

.rc-note {
  border-radius: 10px;
  padding: 13px 16px;
  font-size: 0.9rem;
  line-height: 1.55;
  margin-bottom: 18px;
}

.rc-note--info {
  background: var(--rc-accent-soft);
  border: 1px solid var(--rc-primary);
  color: var(--rc-accent-ink);
}

.rc-note--error {
  background: var(--rc-danger-soft);
  border: 1px solid var(--rc-danger-line);
  color: var(--rc-danger-ink);
  /* Never red alone (SC 1.4.1): the icon and the weight say "error" without the colour. */
  font-weight: 600;
  display: flex;
  gap: 10px;
  align-items: flex-start;
}

.rc-note--error::before {
  content: "!";
  flex: 0 0 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--rc-danger-ink);
  color: var(--rc-ink-inverse);
  font-weight: 800;
  font-size: 0.8rem;
  line-height: 20px;
  text-align: center;
}

.rc-note ul {
  margin: 8px 0 0;
  padding-left: 20px;
}

.rc-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;
}

/* --- pitch and disclaimer -------------------------------------------------- */

.rc-pitch {
  margin-top: 24px;
  border-radius: 14px;
  padding: 22px 24px;
  background: var(--rc-surface);
  border: 1px solid var(--rc-border);
  display: flex;
  gap: 20px;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
}

.rc-pitch h2 {
  margin: 0 0 6px;
  font-size: 1.15rem;
  font-weight: 800;
  color: var(--rc-heading);
}

.rc-pitch p {
  margin: 0;
  font-size: 0.92rem;
  color: var(--rc-text-secondary);
  max-width: 48ch;
  line-height: 1.6;
}

.rc-disclaimer {
  margin-top: 22px;
  font-size: 0.78rem;
  color: var(--rc-text-muted);
  line-height: 1.7;
  max-width: 76ch;
}

/* --- desktop ---------------------------------------------------------------
 * 769px is the desktop side of the codebase's single phone breakpoint (768/769); nothing here
 * invents another one. The height query is not a breakpoint — it asks whether the form fits above
 * the fold before pinning it, because a sticky element taller than the viewport has its bottom
 * (here: the Calcular button) permanently cut off.
 */
@media (min-width: 769px) and (min-height: 820px) {
  /* The schedule is the long half of this page and the form column is 350px of nothing beside it.
     Pinning it means the second and third calculation cost a keystroke instead of a scroll back to
     the top — this page has two audiences and the one that runs 40 contracts is the one that pays. */
  .rc-form {
    position: sticky;
    top: calc(var(--rc-sticky-top) + 16px);
  }
}

/* --- phone -----------------------------------------------------------------
 * 768px is the single phone breakpoint in this codebase; do not invent another.
 *
 * Everything colour- and surface-related is already right at both widths (see the `--rc-*` layer at
 * the top of this file). What is left here is what is only true on a phone: one column, thumb-sized
 * targets, the iOS input quirks, and a schedule that has to earn its vertical space.
 */
@media (max-width: 768px) {
  .rc-page {
    /* Nothing on this page is position:fixed, but the agency themes park a chat bubble at
       bottom:20px and the last thing in the column is the legal disclaimer. */
    padding: 28px 16px calc(56px + env(safe-area-inset-bottom));
  }

  .rc-hero h1 {
    font-size: 1.65rem;
  }

  .rc-lede {
    font-size: 0.95rem;
    margin-bottom: 24px;
  }

  /* One column, FORM first: on a phone the visitor arrives with a question, not
     with an answer to read. The worked example sits underneath it. */
  .rc-grid {
    grid-template-columns: 1fr;
    gap: 18px;
  }

  /* --- controls -------------------------------------------------------------
   * 48px is the cross-platform target: M3 asks 48dp, HIG 44pt, and the KB's rule is to take the
   * larger (docs/mobile-ux-kb.md §1). Measured before: text 48, date 50, select 44 — three heights
   * down one form, and the shortest was under both floors.
   */
  .rc-input {
    min-height: 48px;
    /* 16px exactly. Under it, iOS Safari zooms the viewport on focus and leaves the page off-centre
       for the rest of the form (§5). `1rem` already computes to 16px on both hosts, but stating it
       in px means a host that ever scales its root cannot silently drop under the threshold. */
    font-size: 16px;
    /* Kills the ~300ms double-tap-to-zoom wait before a select opens its picker (§4). */
    touch-action: manipulation;
  }

  /* iOS ≤17 shrink-wraps a date field and ignores `width: 100%` on it; iOS 18 fixed the width and
     not the padding. `display: block` + `min-width` is the form that survives both. */
  input.rc-input[type="date"] {
    display: block;
    min-width: 100%;
  }

  /* Two more iOS-only date quirks, and both bite here: the value is centred inside the field while
     every other control on this form is left-aligned, and the line box COLLAPSES while the field is
     empty (WebKit 198959) — which is the state both date fields start in. */
  input.rc-input[type="date"]::-webkit-date-and-time-value {
    text-align: left;
    min-height: 1.2em;
  }

  /* --- buttons --------------------------------------------------------------
   * `.rc-btn` is 47.2px tall (14px padding + a 19.2px line box), just under the target, and on the
   * Valoris surface the submit button also carries `.vs-cta`, which caps itself at `max-width:
   * 300px` on mobile — measured 300px inside a 305px card body, so the button sat 5px short of its
   * own card and off-centre. The `.rc-page` prefix (0,3,0) settles it against `.vs-cta` (0,1,0)
   * without depending on which sheet the host loaded last.
   */
  .rc-page .rc-btn,
  .rc-page .vs-cta {
    display: flex;
    box-sizing: border-box;
    width: 100%;
    max-width: none;
    min-height: 48px;
    /* Kills the ~300ms tap delay (§4). */
    touch-action: manipulation;
  }

  /* A touch device latches :hover after the tap, so the lift and the drop shadow stay on until the
     visitor taps somewhere else — the button reads as still pressed while the answer loads. */
  .rc-page .rc-btn:hover,
  .rc-page .vs-cta:hover {
    transform: none;
    box-shadow: none;
  }

  /* Press feedback, and it has to be a filter rather than a colour: `--rc-brand` is the agency's own
     brand on four of the six surfaces, so no fixed "pressed" hex is right for all of them. Filter is
     not motion, so it needs no prefers-reduced-motion escape hatch; the delegated touchstart in
     rental-calculator.js is what makes iOS honour :active at all (§4). */
  .rc-page .rc-btn:active,
  .rc-page .vs-cta:active {
    filter: brightness(0.9);
  }

  /* --- the answer ------------------------------------------------------------ */

  .rc-headline {
    padding: 20px;
  }

  /* 2.1rem is the ceiling, not the size: "$ 1.234.567,00" is 14 characters and a seven-figure rent
     is not rare in 2026 — at a flat 2.1rem it wraps the hero number onto two lines at 375px. */
  .rc-n {
    font-size: clamp(1.6rem, 7.6vw, 2.1rem);
  }

  /* --- the schedule ----------------------------------------------------------
   * A 2018 contract adjusting quarterly is 35 rows, and it is shown whole (decided). Measured
   * before: 35 x 69px = 2457px of table on a 667px screen, because EVERY row wrapped onto two lines
   * — "03/2018 –" / "05/2018" in the period cell, and the percentage split from its own unit
   * ("+16,65" / "%"). The columns fit inside the 341px wrap; what did not fit was the text in them.
   */
  .rc-table {
    font-size: 0.82rem;
  }

  .rc-table th,
  .rc-table td {
    padding: 9px 8px;
    line-height: 1.35;
  }

  /* A number and its unit are one word. */
  .rc-pct {
    white-space: nowrap;
  }

  /* --- pitch ------------------------------------------------------------------ */

  .rc-pitch {
    flex-direction: column;
    align-items: stretch;
  }
}
