/* Safe4Seniors brand tokens — the single source of truth for colour.
 *
 * TWO RULES, and the tests in tests/test_brand_tokens.py enforce both:
 *
 *   1. The `-rgb` triples are AUTHORITATIVE. Hex appears only in comments.
 *      Space-separated triples (not `rgb()`) so Tailwind's `<alpha-value>` can
 *      slot an alpha in: `rgb(var(--s4s-trust-rgb) / 0.4)`.
 *   2. Anything not in the Brand Book is marked DERIVED with a doc reference.
 *      Those are ours, not the brand's, and are the first things to reconcile if
 *      the brand author later supplies real values.
 *
 * `tailwind.config.js` REFERENCES these variables and contains no hex, so a value
 * never lives in two places. That is deliberate: two sources of truth is the drift
 * this repo has already paid for once (`__version__` in two files, 2026-06-06).
 *
 * Compiled into admin.css via an `@import` at the top of tools/tailwind_input.css,
 * so admin + portal need no extra <link> — the existing /static/admin.css tags
 * keep working. auth/templates/_base.html is plain CSS and can consume the
 * convenience aliases at the bottom directly.
 *
 * Phase 0: nothing consumes these yet. See docs/design/dashboard-styling.md §3.4.
 */

/* ── Typefaces ─────────────────────────────────────────────────────────
 * Playfair Display + DM Sans, named by Ali (designer) 2026-08-01.
 *
 * Self-hosted rather than CDN-loaded: it keeps a third party from seeing the
 * IP of every senior who opens a login page, works offline, and is a net
 * REDUCTION — 73.6 KB for both families at every weight, against the three
 * families auth previously pulled from Google.
 *
 * Variable fonts, so "DM Sans in different weights" costs one file.
 *
 * src: URLs are ROOT-ABSOLUTE deliberately. This file is consumed from two
 * URL paths — directly at /static/brand.css (auth) and inlined into
 * /static/admin.css (admin + portal, via tools/tailwind_input.css). A
 * relative URL resolves against whichever stylesheet loaded it, so it would
 * render on one surface and 404 on the other. That exact bug shipped once
 * already, in admin/routes_calls.py (fixed in #320).
 *
 * Both faces are SIL Open Font License 1.1; each ships its own notice beside
 * the woff2, because their copyright lines differ and Playfair additionally
 * carries a Reserved Font Name. See fonts/OFL-*.txt.
 */
@font-face {
  font-family: "Playfair Display";
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url("/static/fonts/playfair-display-latin.woff2") format("woff2");
}

@font-face {
  font-family: "DM Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/static/fonts/dm-sans-latin.woff2") format("woff2");
}

:root {
  /* ── Palette — confirmed by Ali (designer) 2026-08-01 ─────────────────
   * Values below come direct from the designer and OUTRANK the Brand Book
   * PDF, the palette JPG, and anything we sampled from swatch pixels.
   * Where they differ from the printed book, the designer is right. */
  --s4s-canyon-rgb:  3 76 82;      /* Canyon Teal   #034C52  deepest; dividers, body ink */
  --s4s-river-rgb:   37 90 97;     /* River Teal    #255A61  mid; secondary surfaces */
  --s4s-trust-rgb:   1 112 117;    /* Trust Teal    #017075  PRIMARY brand colour */
  --s4s-sunrise-rgb: 229 146 126;  /* Sunrise Coral #E5927E  lead accent */
  --s4s-hand-rgb:    253 168 152;  /* Hand Coral    #FDA898  soft accent */
  --s4s-porch-rgb:   255 192 180;  /* Porch Coral   #FFC0B4  lightest tint */

  /* River Teal: the Brand Book prints #034C52 for both Canyon and River while
   * rendering two visibly different swatches. We shipped #015C63 (sampled) as a
   * documented override; Ali confirms the printed swatch was simply a TYPO and
   * the value is #255A61. Adopting it is contrast-neutral — white text is
   * 7.7425:1 on #015C63 and 7.7384:1 on #255A61 — so this costs no a11y. */

  /* ── DERIVED — not in the Brand Book (design doc §1.2, §2.3, §9.2) ── */
  /* Cream is now specified: Ali gives #F5F0E8. Supersedes the sampled #F9F2EB
   * and the two other creams found in the assets (#F3ECE1 in a LinkedIn file,
   * #FBF8F3 previously shipping in auth). Ink holds at 12.84:1, was 13.13:1. */
  --s4s-paper-rgb:   245 240 232;  /* #F5F0E8  page ground */
  /* Trust Teal, the primary brand colour, is only 5.18:1 on paper — AA but not
   * AAA, so it cannot carry senior body text. This is Canyon darkened until it
   * clears AAA. */
  --s4s-ink-rgb:     2 46 51;      /* #022E33  body ink, 12.84:1 on paper */
  /* All three corals still fail 3:1 against paper on Ali's corrected values
   * (Sunrise 2.12:1, Hand 1.65:1, Porch 1.38:1), so none can be text, a border,
   * or a focus ring — they work only as SURFACES under dark ink, which is how
   * the Brand Book itself uses them. Note the corrected Sunrise #E5927E is still
   * only 2.40:1 under white, so it STILL cannot be a button; under ink it is
   * 6.07:1. This is a coral dark enough to be text when coral must carry
   * meaning inline. */
  --s4s-coral-ink-rgb: 180 68 44;  /* #B4442C  coral legible as text on light, 4.87:1 */

  /* ── Convenience aliases ──────────────────────────────────────────── */
  /* For plain-CSS consumers (auth/_base.html) that want a colour, not a triple.
   * Tailwind does not use these — it composes rgb(var(--*-rgb) / <alpha-value>)
   * itself so opacity modifiers keep working. */
  --s4s-canyon:    rgb(var(--s4s-canyon-rgb));
  --s4s-river:     rgb(var(--s4s-river-rgb));
  --s4s-trust:     rgb(var(--s4s-trust-rgb));
  --s4s-sunrise:   rgb(var(--s4s-sunrise-rgb));
  --s4s-hand:      rgb(var(--s4s-hand-rgb));
  --s4s-porch:     rgb(var(--s4s-porch-rgb));
  --s4s-paper:     rgb(var(--s4s-paper-rgb));
  --s4s-ink:       rgb(var(--s4s-ink-rgb));
  --s4s-coral-ink: rgb(var(--s4s-coral-ink-rgb));

  /* ── Type ─────────────────────────────────────────────────────────── */
  /* Playfair is DISPLAY-ONLY. It is a high-contrast didone whose hairlines
   * thin at small sizes, so it carries titles and never body text — a
   * deliberate constraint on a senior-facing surface, pinned by
   * tests/test_typography.py.
   *
   * Mono is the system stack. Ali named only two families, and admin +
   * portal already used the system stack; JetBrains Mono was ours. Codes,
   * org slugs, E.164 numbers and the OTP field stay monospaced either way. */
  --s4s-display: "Playfair Display", "Iowan Old Style", Palatino, Georgia, serif;
  --s4s-body:    "DM Sans", -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
  --s4s-mono:    ui-monospace, SFMono-Regular, Menlo, monospace;

  /* ── Dashboard ground + warm neutral ramp ─────────────────────────
   * The dashboards ran on Tailwind's bg-slate-50 (#F8FAFC) — a COOL
   * near-white with a blue cast — while the brand is warm. This is the
   * replacement, chosen from four mocked candidates.
   *
   * DELIBERATE DEPARTURE from Ali (designer), who said "the base should
   * remain white or cream". Sage is neither. Rich's call, made knowingly:
   * the dashboards are not the brand's public face — safe4seniors.ai keeps
   * the cream, and --s4s-paper above is unchanged for the auth surface.
   * Fallback if it is ever reversed: tan #E2D8C8, inside the cream family,
   * which gives 1.41:1 panel separation against sage's 1.47:1.
   *
   * The real gain is depth, not hue: a white panel separates from this
   * ground at 1.47:1, against 1.13:1 on cream, where cards nearly vanish.
   *
   * The ramp is anchored on safe4seniors.ai's own neutrals (#52605D,
   * #3F4F4D) rather than invented — those green-greys are what Ali meant
   * by "we don't use greys". Step 500 was DERIVED, not picked: the first
   * candidate (#6B7C79) measured 4.39:1 on a white panel and would have
   * regressed `text-slate-500` (93 uses) below AA. See
   * tests/test_dashboard_ground.py, which pins the floors. */
  --s4s-ground-rgb: 200 216 215;      /* #C8D8D7  page ground, dashboards only */
  --s4s-neutral-50-rgb:  244 246 245; /* #F4F6F5  subtle panel fill */
  --s4s-neutral-100-rgb: 231 236 234; /* #E7ECEA  hairline */
  --s4s-neutral-200-rgb: 210 219 217; /* #D2DBD9  default border, 62 uses */
  --s4s-neutral-300-rgb: 180 194 191; /* #B4C2BF  strong border, 39 uses */
  --s4s-neutral-400-rgb: 120 136 133; /* #788885  3.71:1 on white — see the step-400 caveat */
  --s4s-neutral-500-rgb: 99 115 111;  /* #63736F  4.99:1 on white; muted text, 93 uses */
  --s4s-neutral-600-rgb: 76 90 87;    /* #4C5A57  7.22:1 on white, 4.90:1 on ground */
  --s4s-neutral-700-rgb: 59 74 72;    /* #3B4A48  9.30:1 on white */
  --s4s-neutral-800-rgb: 44 58 56;    /* #2C3A38  11.87:1 on white */
  --s4s-neutral-900-rgb: 28 39 38;    /* #1C2726  15.36:1 on white; body ink on dashboards */

  --s4s-ground: rgb(var(--s4s-ground-rgb));

  /* ── Status — DERIVED, not in the Brand Book ───────────────────────
   * The call page's status dot. NOT repainted brand-teal: green/amber/rose
   * carry meaning (connected / in progress / problem) and consistency is not
   * worth erasing it — the same call the button swap made in the accent pass.
   *
   * Measured against a WHITE panel, because that is where the dot now sits.
   * The pale Tailwind defaults these replace failed on white too (amber-400
   * 1.67:1, emerald-500 2.28:1), which is why moving the dot onto a card was
   * never going to be the fix on its own. Pinned by
   * tests/test_call_page_status.py, which also pins the old values AS FAILING
   * so a revert cannot be quiet. */
  --s4s-status-idle-rgb:    120 136 133; /* #788885  3.71:1 — same as neutral-400 */
  --s4s-status-pending-rgb: 180 83 9;    /* #B45309  5.02:1 */
  --s4s-status-live-rgb:    4 120 87;    /* #047857  5.48:1 */
  --s4s-status-problem-rgb: 190 18 60;   /* #BE123C  6.29:1 */

  --s4s-status-idle:    rgb(var(--s4s-status-idle-rgb));
  --s4s-status-pending: rgb(var(--s4s-status-pending-rgb));
  --s4s-status-live:    rgb(var(--s4s-status-live-rgb));
  --s4s-status-problem: rgb(var(--s4s-status-problem-rgb));
}
