/* ==========================================================================
   Sovana by SanLiving — design tokens
   Source: Figma aM5nJO5xdgKx568jf881cp (variables) + General Brief §03
   Extracted 2026-09-21
   Type system v7 (2026-09-25): Source Serif 4 (headings) + Lato (functional).
   Source Serif 4 replaces LT Remark on every heading and eyebrow, by request.
   Lato replaces Jost, which replaced Inter Tight, which replaced Arsenal.
   DM Sans and LT Soul retired earlier.
   ONE WEIGHT: 400. Regular is the floor — nothing is set lighter, so the
   300/400 split inherited from v5 is gone. Lato has no 500 either (it ships
   100 / 300 / 400 / 700 / 900), so the whole functional family now runs on a
   single weight token and the §03 ceiling is unreachable by construction.
   The 1.7 prose leading is the one thing carried over from v5, measured off
   the client's own all-Jost build
   (beige-woodpecker-644839.hostingersite.com, 2026-09-22, 1920px).
   Heading scale re-cut against wilde.com, measured live 2026-09-22 at 1441:
     hero 102 / section 84 / sub 62 / minor 42 / 32, every one weight 400,
     leading 1.0 at 84-102px, sentence case, no uppercase display.
   Sovana maps that onto its four heading steps as 104 / 84 / 64 / 40.
   TODO from DESIGN.md: exact spring curve

   SOURCE OF TRUTH — read before touching anything below
   Design source is frame 80:9814 "Sovana — Home · Desktop 1441" ONLY.
   The boards on page 67:9887 (01 General Brief, 02 Sitemap, 03 Flowchart,
   04 Wireframes) are BRIEF DOCUMENTS, not design. Their header/body text is
   styled for the brief itself and is not a spec — e.g. node 69:3 still serves
   Jost ExtraLight 80px. Never read type off those boards.
   Figma type in general is STALE (Jost / LT Soul). Take layout, spacing,
   colour and structure from Figma; take type ONLY from the .t-* classes here.
   ========================================================================== */

/* Both families from Google, one weight each, roman + italic, and nothing
   else. Requesting exactly what is used means an unavailable weight cannot
   be reached for by accident.
   · Lato 400 — functional type only (body, price, labels, buttons).
   · Source Serif 4 — replacing LT Remark (2026-09-25): LIGHT 300 roman for
     the headings, REGULAR 400 italic for the eyebrows, both by request. Only
     those two faces are requested.
     Loaded with its optical-size axis (opsz 8–60): font-optical-sizing is
     auto, so a 104px display heading draws the display cut and an 11px
     eyebrow the caption cut, from the same file. */
@import url("https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;1,400&family=Source+Serif+4:ital,opsz,wght@0,8..60,300;1,8..60,400&display=swap");

:root {
  /* ── Ground ─────────────────────────────────────────────── */
  /* TWO grounds only (2026-09-25, the client): white about 65%, ivory 35%.
     The darker ivories — ivory-2 #EFE9DB, sand #E4DCC7 — and plan-paper
     #F8F4EF are gone; everything they carried is ivory now. */
  --ivory:        #FCFBF8;  /* the 35%: alternate sections, the funnel's page
                               ground, frames, placeholders, notices.
                               #F5F1E7 until 2026-09-25, then #F9F7F1; now 70%
                               toward white, same hue, by request. ink 15.3:1,
                               muted 6.3:1, gold-700 4.9:1 on it. */
  --white:        #FFFFFF;  /* the 65%: the page. A white CARD still carries
                               hairline + shadow so it reads above the page.
                               ink 16:1, muted 6.4:1, gold-700 5.0:1 on it. */

  /* ── Shade (structure) ──────────────────────────────────── */
  --green:        #0E2B21;
  --ink:          #24241F;  /* body text   13.8:1 on ivory */
  --muted:        #5F5F55;  /* secondary    5.7:1 on ivory */

  /* ── Light (accent) — never structure, never a large fill ─ */
  --gold:         #C8A461;  /* rules, borders, tags. NOT text on light (2.1:1) */
  --gold-700:     #8A6A2C;  /* gold text on light — 4.46:1, uppercase/small only */

  /* ── Reserved ───────────────────────────────────────────── */
  --maroon:       #7A1F2B;  /* Resident (12-mo) tier + error text ONLY */

  /* ── Edges & elevation ──────────────────────────────────── */
  --hairline-color: rgba(14, 43, 33, 0.09);
  --hairline:       1px solid var(--hairline-color);
  --shadow-rgb:     14, 43, 33;           /* rgba(var(--shadow-rgb), a) — never black */
  --shadow-card:    0 22px 50px -28px rgba(var(--shadow-rgb), .08), 0 6px 16px -10px rgba(var(--shadow-rgb), .04);  /* Figma Shadow/Card */
  --shadow-soft:    0 24px 60px -20px rgba(var(--shadow-rgb), .09), 0 8px 20px -12px rgba(var(--shadow-rgb), .06);  /* Figma Shadow/Soft */

  /* ── Shape lock ─────────────────────────────────────────── */
  --radius-shell: 24px;
  --radius-core:  17px;
  --radius-image: 18px;
  --radius-input: 12px;
  --radius-pill:  999px;   /* anything clickable */

  /* ── Type · primitives ─────────────────────────────────── */
  /* Two families. Source Serif 4 = headings (LT Remark until 2026-09-25).
     Lato = everything functional, in Jost's place. */
  --font-display: "Source Serif 4", Georgia, serif;
  --font-sans:    "Lato", system-ui, sans-serif;

  /* ONE functional weight: 400. Decided 2026-09-22 — regular is the floor
     for Lato, nothing is set lighter.
     --weight-light (300) is gone with that decision, and --weight-medium
     (500) went earlier because Lato has no 500 at all. Neither is kept as an
     alias: two tokens resolving to the same number is how a "light" style
     quietly stops being light, which is exactly what Arsenal did in v3.
     The headings are the one exception, by request (2026-09-25): Source
     Serif 4 roman is loaded at 300 ONLY and every heading reads
     --weight-display. Eyebrows are Source Serif 4 italic at 400 (regular).
     --weight-display is not an alias of anything and Lato never uses it. */
  --weight-regular: 400;   /* Lato everywhere + the Source Serif 4 italic eyebrows */
  --weight-display: 300;   /* Source Serif 4 Light — headings only */

  /* Prose + UI — unchanged. */
  --size-10: 10px;  --size-11: 11px;  --size-12: 12px;  --size-13: 13px;
  --size-14: 14px;  --size-16: 16px;  --size-18: 18px;  --size-20: 20px;  --size-24: 24px;
  --size-28: 28px;  --size-32: 32px;
  /* Headings (Source Serif 4; LT Remark when cut) — re-cut 2026-09-22 against the Wilde measurement in
     the header. Was 30 / 48 / 64 / 96. Those four are gone, not kept as
     aliases: an orphan size is how a stale 48px heading survives a rescale. */
  /* 32 added 2026-09-23 for the Location point headings: 28 sat too close to
     the 16px body under it and 40 competed with the 64px section head above.
     It is a REAL step, not a one-off — the gap from 28 to 40 is +43%, the
     coarsest jump left in the scale. Same reasoning that put 48 between 40
     and 64. If nothing uses it, delete it. */
  --size-40: 40px;  --size-44: 44px;  --size-48: 48px;  --size-56: 56px;
  --size-64: 64px;  --size-84: 84px;  --size-104: 104px;
  /* 56: the section headline's desktop size (.t-h2, 2026-09-29, by request
     — 44 after Raffles for a moment first). 72 went with the old larger
     headline, orphaned. */
  /* 48 fills the gap between 40 and 64, which is +60% and too coarse for a
     heading that has to sit between them. It briefly was 56 — same purpose,
     different number, replaced rather than kept alongside so the scale does
     not collect one-off steps. */

  /* Every heading from .t-h2-sm up runs at 1.0 (2026-09-25, by request: the
     two lines of a section headline sat too far apart at 1.1). --lh-heading
     was merged into this rather than kept at the same value. */
  --lh-display: 1;      /* .t-display, .t-h1, .t-h2, .t-h2-sm — all widths */
  --lh-title:   1.2;    /* .t-h3 40, .t-h4 */
  --lh-price:   1.2;
  /* --lh-body (1.5) retired: the reference build set ALL prose at 1.7, so
     .t-body shares --lh-relaxed with the other three prose styles.
     The reason first written here was Jost's short x-height — that argument
     left with Jost. 1.7 is kept because it is the measured reference value,
     not because Lato needs it; Lato's larger x-height could carry less. */
  --lh-relaxed: 1.7;

  /* ── Tracking — three UI values + one display tightening ── */
  --tracking-eyebrow: 0.28em;   /* FINAL — decided 2026-09-21, do not re-open.
                                   Source: Figma 80:9814 → Eyebrow component 39:1348
                                   ("Eyebrow / On light", used 43x), style Label/11.2
                                   Medium = 3.136px @ 11.2px = exactly 0.28em.
                                   Brief §03 says 0.34em; the brief is wrong here.
                                   Do not "correct" this from the brief boards. */
  --tracking-ui:      0.16em;   /* buttons, nav, chips, tags */
  --tracking-prose:   normal;
  /* Unchanged at -0.02em even though the scale went up — set for LT Remark
     and carried to Source Serif 4 (2026-09-25), whose display optical size
     is already tighter; re-check by eye before changing. It is optical
     tightening, and the reference runs its own display type at normal
     tracking, so the larger sizes are no argument for tightening further.
     Headings only — never prose, never UI labels. */
  --tracking-display: -0.02em;  /* headings at 40px+ */

  /* ── Motion ─────────────────────────────────────────────── */
  --duration:      450ms;
  /* A plain decelerate that never passes its target. --ease-spring (retired
     2026-09-23) overshot
     (the 1.56) and that reads as a bounce on anything that travels — the
     underline wipes were the third thing it bit, after the amenity frames
     and the marker. Use this wherever a move should just arrive. */
  --ease-out:      cubic-bezier(0.22, 1, 0.36, 1);
}

@media (prefers-reduced-motion: reduce) {
  :root { --duration: 0ms; }
}

/* ── Text styles — composites of the primitives above ─────────
   Use these classes, never raw sizes. 16 styles total.          */

/* text-wrap: balance — added 2026-09-22. Every heading wraps into lines of
   roughly equal length instead of one full line plus a short one. It is the
   right tool here and not for prose: browsers cap balancing at about six
   lines, and headings never reach that. Falls back to normal wrapping where
   it is unsupported, so nothing depends on it. */
.t-display, .t-h1, .t-h2, .t-h2-sm, .t-h3, .t-h4 {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  letter-spacing: var(--tracking-display);
  text-wrap: balance;
}
/* ── RESPONSIVE TYPE SCALE (2026-09-24, by request) ─────────────────────
   Each style reads a --fs-* role, and the role steps down the SAME size
   scale at two breakpoints — no new numbers:

     style        desktop   tablet ≤1080   mobile ≤720
     .t-display     104         84            64
     .t-h1           84         64            48
     .t-h2           56         32            32   (28 for a moment, 2026-09-29)   (2026-09-29, by request: after
                     raffles.com's 44/54 → 28/36 treatment — small on tablet
                     and phone, line height 1.2 — then 56 on desktop and the
                     -0.02em display tracking back; 72/56/44 at 1.0 before)
     .t-h2-sm        48         24            24   (40/32 until 2026-09-29)
     .t-h3           40         24            24   (32/28 until 2026-09-29)
     .t-h4           28         20            20   (28 everywhere until 2026-09-29)
     .t-price        28         28            28
     .t-lead         20         20            18
     .t-body-lg      18         16            14   (18 everywhere until 2026-09-29; 16 on phones until 2026-10-01)
     .t-body         16         16            14   (16 everywhere until 2026-10-01)
     .t-body-sm      16         14            14
     .t-caption      16         13            13

   Body text is never below 16 on desktop (2026-09-25, by request): .t-body-sm
   and .t-caption step UP to 16 above 1080 and keep 14 / 13 below it. The
   uppercase labels (.t-button 12, .t-eyebrow 11, .t-micro 10) are labels,
   not body, and do not move.

   Line height is 1.0 for .t-display, .t-h1, .t-h2 and .t-h2-sm.
   Change a size HERE, never with a one-off font-size in page CSS. */
:root {
  --fs-display: var(--size-104); --fs-h1: var(--size-84); --fs-h2: var(--size-56);
  --fs-h2-sm: var(--size-48);    --fs-h3: var(--size-40); --fs-h4: var(--size-28); --fs-lead: var(--size-20);
  --fs-body-lg: var(--size-18); --fs-body: var(--size-16);
  --fs-body-sm: var(--size-16);  --fs-caption: var(--size-16);
}
@media (max-width: 1080px) {
  /* IN-CONTENT TITLES stay BELOW the section headline (32 here) — 2026-09-29,
     by request: tier names, residence names, place names, FAQ questions
     step down to 24 / 24 / 20 */
  :root { --fs-display: var(--size-84); --fs-h1: var(--size-64); --fs-h2: var(--size-32);
          --fs-h2-sm: var(--size-24);   --fs-h3: var(--size-24); --fs-h4: var(--size-20);
          /* the 18 body under a 24 LIGHT serif title read LARGER than it —
             body steps to 16 here, below its titles (2026-09-29, by request) */
          --fs-body-lg: var(--size-16);
          --fs-body-sm: var(--size-14); --fs-caption: var(--size-13); }
}
@media (max-width: 720px) {
  :root { --fs-display: var(--size-64); --fs-h1: var(--size-48); --fs-h2: var(--size-32);
          --fs-h2-sm: var(--size-24);   --fs-h3: var(--size-24); --fs-lead: var(--size-18);
          /* body text 14 on phones (2026-10-01, by request) — form fields
             stay 16, see styles-alt.css */
          --fs-body: var(--size-14); --fs-body-lg: var(--size-14); }
}
.t-display { font-size: var(--fs-display); line-height: var(--lh-display); }
.t-h1      { font-size: var(--fs-h1);      line-height: var(--lh-display); }
.t-h2      { font-size: var(--fs-h2);      line-height: var(--lh-display); } /* back to 1.0 (2026-10-01, by request — 1.2 read loose); the display tracking (-0.02em) */
.t-h2-sm   { font-size: var(--fs-h2-sm);   line-height: var(--lh-display); }
.t-h3      { font-size: var(--fs-h3);      line-height: var(--lh-title); }
/* .t-h4 — added 2026-09-22 for the amenities list, where .t-h3 at 40px was
   too loud for six stacked names in a 35% column. 28px is an existing step
   (it is what .t-price runs at); no new size is invented for it. */
.t-h4      { font-size: var(--fs-h4);    line-height: var(--lh-title); }

/* Two price sizes. 28 is the one a price is the loudest thing in the block;
   20 is for a price sitting UNDER a name that already carries the weight —
   the collection cards, added 2026-09-22 by request. There is no step
   between them: the scale goes 20 -> 28. (--size-24 exists since
   2026-09-29, but for the in-content titles at ≤1080, not for prices.) */
.t-price, .t-price-sm {
  font-family: var(--font-sans);
  font-weight: var(--weight-regular);
  line-height: var(--lh-price);
  font-variant-numeric: tabular-nums lining-nums;
}
.t-price    { font-size: var(--size-28); }
.t-price-sm { font-size: var(--size-20); }
.t-lead, .t-body, .t-body-lg, .t-body-sm, .t-caption {
  font-family: var(--font-sans);
  font-weight: var(--weight-regular);
  letter-spacing: var(--tracking-prose);
}
/* .t-lead IS the subhead style, so it balances with the headings. The three
   prose styles get `pretty` instead: it kills the one-word last line without
   re-flowing the whole block, and unlike `balance` it has no line cap.
   But a subhead does not always wear .t-lead — plenty are .t-body-sm sitting
   directly under a heading. The element rule below catches those by ROLE
   rather than by class, so a new one is balanced the day it is written. */
:is(h1, h2, h3, h4, h5, h6) + p { text-wrap: balance; }
.t-lead    { font-size: var(--fs-lead); line-height: var(--lh-relaxed); text-wrap: balance; }
/* One step between .t-body (16) and .t-lead (20) — for a supporting line
   carrying more than a caption but sitting under a heading, not beside it. */
.t-body-lg { font-size: var(--fs-body-lg); line-height: var(--lh-relaxed); text-wrap: pretty; }
.t-body    { font-size: var(--fs-body); line-height: var(--lh-relaxed); text-wrap: pretty; }
.t-body-sm { font-size: var(--fs-body-sm); line-height: var(--lh-relaxed); text-wrap: pretty; }
.t-caption { font-size: var(--fs-caption); line-height: var(--lh-relaxed); text-wrap: pretty; }

/* .on-media — the weight step is GONE (2026-09-22). It lifted the three
   light prose styles to 400 over photography; with 400 as the floor there is
   nothing to lift. The class stays on the markup as a grouping hook and is
   inert; the rule comes back the day a sub-400 weight does.
   ──────────────────────────────────────────────────────────── */

.t-button, .t-micro {
  font-family: var(--font-sans);
  line-height: var(--lh-relaxed);
  text-transform: uppercase;
}
.t-button, .t-micro { font-weight: var(--weight-regular); }
.t-button  { font-size: var(--size-12); letter-spacing: var(--tracking-ui); }
.t-micro   { font-size: var(--size-10); letter-spacing: var(--tracking-ui); }

/* EYEBROW — display italic (Source Serif 4 since 2026-09-25; LT Remark
   before), 2026-09-22 by request. The only style in the
   system not set in the functional family, and the only one that is italic:
   it brings back the roman/italic pairing that was retired on 2026-09-21,
   now carried by the labels rather than the headings.
   Weight is --weight-regular, like everything else now.
   Case and tracking are unchanged — uppercase at 0.28em, the Figma value
   marked FINAL below. That pairing is a sans-serif convention and this is
   now a display italic; if it reads as too tight or too shouty, the fix is
   lowercase and looser tracking, which is a separate decision. */
.t-eyebrow {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: var(--weight-regular);   /* italic REGULAR, by request */
  font-size: var(--size-11);
  line-height: var(--lh-relaxed);
  text-transform: uppercase;
  letter-spacing: var(--tracking-eyebrow);
}

/* ── Rule helpers (encode the hard rules so they can't drift) ─ */

/* Two variants, both taken from Figma 80:9814.
   On light — component 39:1348 "Eyebrow / On light", used 43x
   On dark  — component 39:1481 "Eyebrow / On dark",  used 4x
   The 26x1 GOLD RULE both components draw before the label is GONE
   (2026-09-22, by request) — every eyebrow on the page is now the label
   alone. Its three tokens (--eyebrow-rule-w / -h, --eyebrow-gap) and the
   per-variant rule ink and opacity went with it rather than being left
   as dead values. The label colours are all that still differ between the
   two variants. Default is on-light (the 43x case). */
.eyebrow {
  --eyebrow-ink: var(--gold-700);

  display: inline-block;
  font-family: var(--font-display);   /* Source Serif 4 italic — see .t-eyebrow */
  font-style: italic;
  font-weight: var(--weight-regular); /* 400: Source Serif 4 italic regular */
  font-size: var(--size-11);
  line-height: var(--lh-relaxed);
  text-transform: uppercase;
  letter-spacing: var(--tracking-eyebrow);
  color: var(--eyebrow-ink);
}
/* On dark ground (green sections, image bands). gold on green = 6.4:1. */
.eyebrow--on-dark { --eyebrow-ink: var(--gold); }

.surface-lifted {          /* a white card: hairline + shadow */
  background: var(--white);
  border: var(--hairline);
  box-shadow: var(--shadow-card);
  border-radius: var(--radius-shell);
}

.btn {                     /* pill rule */
  border-radius: var(--radius-pill);
  font-family: var(--font-sans);
  font-weight: var(--weight-regular);
  font-size: var(--size-12);
  letter-spacing: var(--tracking-ui);
  text-transform: uppercase;
  /* Named properties, not `all`. `all` animated every property a button ever
     changes — width, padding, opacity — so any layout tweak became a
     transition. And --ease-spring overshoots (the 1.56), which is the bounce
     that was rejected three times elsewhere; a button that settles past its
     own colour reads as a wobble. */
  transition: background-color var(--duration) var(--ease-out),
              color var(--duration) var(--ease-out),
              border-color var(--duration) var(--ease-out);
}
.btn--primary { background: var(--green); color: var(--ivory); }
