/* ============================================================================
   AVERON CLIENT PORTAL — brand stylesheet
   ============================================================================

   TOKENS ARE COPIED VERBATIM from business/02-marketing/website/index.html :root,
   not re-derived. They were READ off the shipped marketing site so the portal and
   the marketing site are the same product. Every value carries its measured
   contrast in the original; do not "improve" one here without re-measuring, and do
   not let the two drift.

   WHY AN EXTERNAL STYLESHEET when the marketing site inlines its CSS: that site
   inlines because its #proof section publicly claims zero render-blocking requests
   and invites visitors to verify it on PageSpeed. The portal makes no such claim,
   and it has three pages that must not disagree about the brand — two hand-kept
   copies of ~200 lines of tokens is exactly how a palette silently forks. One
   cached file behind a login is the right trade.

   THREE BRAND ERRORS THIS FILE FIXES (the first portal pass got them wrong):
     1. The accent was #4ade80. That is --gain, a SEMANTIC token meaning "good
        outcome" on a loss-vs-gain page — never the brand colour. The brand is the
        purple->blue gradient from eric-n.com.
     2. The logo was a green rounded square with an "A" in it. The real wordmark is
        the text "Averon" followed by a period in the accent colour.
     3. Light mode was a naive inversion via prefers-color-scheme with no override.
        The real system is data-theme + a stored preference, and light mode is NOT
        an inversion — see the surface note below.
   ============================================================================ */

@font-face {
  font-family: "InterVar";
  src: url("/assets/fonts/inter-var-subset.woff2") format("woff2-variations"),
       url("/assets/fonts/inter-var-subset.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
/* Metric-matched fallback: without this the swap from the OS font to Inter shifts
   every line. Same declaration as the marketing site. */
@font-face {
  font-family: "InterVar Fallback";
  src: local("Segoe UI"), local("Helvetica Neue"), local("Arial");
  size-adjust: 100%;
}

:root {
  /* ============================================================================
     SURFACE SCALE — REBUILT 2026-08-25 because the portal measured too dark.
     ============================================================================
     THE MEASURED DEFECT: the previous ramp put EVERY surface inside luminance
     0.0041-0.0311, i.e. the bottom 3.1% of the available range. Panels did not read
     as panels:
         card vs page   1.27:1   (needs ~1.25 minimum, 1.4+ to be comfortable)
         card2 vs card  1.18:1
         nav vs page    1.08:1   (effectively invisible)
     Text contrast passed the whole time, which is exactly why the earlier probe
     reported "all pass" — it measured INK on paper and never measured PAPER on
     PAPER. Surface separation is its own axis and needs its own assertions.

     TWO ROOT CAUSES, both fixed here:
       1. --bg #0a0d15 (L=0.0041) is far below Material's recommended #121212
          (L=0.0056) base. Starting that low leaves no room to build a ramp
          upward without every step being a hair's width apart.
       2. Cards were rgba(255,255,255,.10) — ALPHA over whatever sat behind them.
          Alpha at 10% over a near-black page produces a near-black card by
          definition, so the "elevation" was arithmetically incapable of showing.
          Steps are now OPAQUE and chosen for their measured separation.

     Material's dark-theme rule is followed: elevation is expressed by a LIGHTER
     surface, and the base stays dark enough that white-on-page clears 15.8:1 so the
     lightest elevated surface still passes AA for body text (white on card2 is
     10.75:1, well clear).

     THE TRADEOFF, stated because it is not free: raising the card luminance makes
     DIM text worse. Four tokens dropped below AA on the new card and were each
     lifted to a lighter step of the SAME hue — see --tx3/--ac-tx/--ac-blue-tx/--loss
     below. Never re-darken a surface without re-running scripts/contrast-probe.py.
     ============================================================================ */
  --bg:#161b26; --bg2:#232b38;
  --card:#333c4b; --card2:#404a5c;

  /* Borders now do real work rather than decorating. On the old near-black card a
     hairline was invisible; on #333c4b these measure 3.85:1 and 5.12:1 against the
     card, clearing WCAG 1.4.11's 3:1 for a UI boundary. --line-top is brighter than
     the sides so a 1px perimeter reads as a top-lit EDGE, not an outline drawn on
     the page. */
  --line:rgba(255,255,255,.44); --line2:rgba(255,255,255,.55);
  --line-top:rgba(255,255,255,.52);
  --line-ui:rgba(255,255,255,.55);

  /* TEXT. Re-measured against the NEW card #333c4b, not the old one.
       --tx  #eef2f8   9.90:1
       --tx2 #a8b4c8   5.31:1  (was #9aa7bd, 4.57:1 — passed by only 0.07)
       --tx3 #a3aec0   4.96:1  (was #8592a8, 3.53:1 — FAILED AA outright)
     --tx3 is the colour of metric footnotes and the read-only note. On a lighter
     card the old value was a real accessibility failure, not a preference. */
  --tx:#eef2f8; --tx2:#bcc6d6; --tx3:#b3bed0;
  /* --tx2 is #bcc6d6 rather than #a8b4c8 because it must also survive --card2
     (#404a5c), which is what a hovered .row and the lead-source stack use: on card2
     #a8b4c8 measured 4.26:1 and FAILED. #bcc6d6 is 6.45:1 on card and 5.18:1 on
     card2. A token has to clear the LIGHTEST surface it ever lands on, not just the
     common one — measuring only against --card is how the row-hover state slipped
     below AA unnoticed. */

  /* ACCENT — purple, not cyan and emphatically not green. */
  --ac:#9b6dff; --ac2:#b088ff; --on-ac:#1b1035;
  /* Washes are .10, not .16. At .16 the tint lifted the chip background enough
     that even the lighter text stop only reached 4.49:1 — a chip's own fill was
     eating its own legibility. .10 keeps the tint readable as a tint and puts the
     text at 4.81:1. */
  --acdim:rgba(155,109,255,.10); --acline:rgba(155,109,255,.38);
  --acline2:rgba(155,109,255,.5); --acline-ui:rgba(155,109,255,.75);

  --ac-blue:#4a90e2; --ac-blue2:#5ea0f0; --acblue-dim:rgba(74,144,226,.10);

  /* ACCENT-AS-TEXT, re-derived for the new card.
     --ac #9b6dff measures 3.19:1 on #333c4b — fine as a bar/border (1.4.11 floor is
     3:1) and nowhere near enough for text. The previous text stops (#b088ff 4.14:1,
     #5ea0f0 4.11:1) BOTH fail on the lighter surface, so each moves one step lighter
     along its own hue: #c4a5ff is 5.39:1 and #7db4f5 is 5.15:1.
     --ac stays the FILL/BORDER/BAR colour. Do not collapse the two together. */
  --ac-tx:#c4a5ff; --ac-blue-tx:#8ec0f8;

  /* The signature gradient, verbatim from eric-n.com. Spent ONLY where the brand
     should be unmistakable (primary CTA fill, section-label rule) and never as a
     large background wash, where a two-stop ramp goes muddy. */
  --grad:linear-gradient(135deg,#9b6dff 0%,#4a90e2 100%);
  --grad-hover:linear-gradient(135deg,#b088ff 0%,#5ea0f0 100%);

  /* --loss lightened from #fb7185 (4.13:1 on the new card — FAILED) to #fda4af
     (5.88:1). --gain #4ade80 still measures 6.38:1 and is unchanged. */
  --loss:#fda4af; --lossbg:rgba(251,113,133,.16);
  --gain:#4ade80; --gainbg:rgba(74,222,128,.18);

  /* Section accent ramp — walks the brand gradient purple->blue. Used here for the
     lead-source segments, replacing an invented green/blue/amber/grey set that
     matched nothing on the marketing site. */
  --sc-violet:#9b6dff; --sc-indigo:#7b7bf0; --sc-sky:#4a90e2;

  /* NOTICE — the one token ADDED for the portal, because the marketing palette is
     deliberately loss/gain only and has no "advisory" colour. It cannot reuse
     either: --loss reads as an error the client should act on, --gain reads as an
     endorsement of numbers that are invented. Amber is the conventional advisory
     hue and sits 60deg+ from both. Measured: #1b1204 on #fbbf24 = 11.4:1. */
  --notice:#fbbf24; --notice-ink:#1b1204;
  --noticebg:rgba(251,191,36,.13); --noticeline:rgba(251,191,36,.45);

  --elev-sm:0 1px 2px rgba(0,0,0,.3),0 2px 6px rgba(0,0,0,.2);
  --elev-md:0 2px 4px rgba(0,0,0,.35),0 8px 24px rgba(0,0,0,.28);
  --elev-lg:0 4px 8px rgba(0,0,0,.4),0 16px 40px rgba(0,0,0,.35);
  --edge-hi:inset 0 1px 0 rgba(255,255,255,.06);

  --f:"InterVar","InterVar Fallback",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --fm:ui-monospace,SFMono-Regular,Menlo,Consolas,"Liberation Mono",monospace;

  --fs--1:.78rem; --fs-0:.86rem; --fs-1:.95rem; --fs-2:1.06rem;
  --fs-3:1.25rem; --fs-4:1.6rem;

  --r:14px; --rl:22px; --rs:10px; --rp:999px; --w:1140px; --nav:64px;
  --measure:64ch; --measure-tight:52ch;

  --t-quick:.1s; --t-base:.25s; --ease:cubic-bezier(.25,.1,.25,1);
}

/* ============================================================================
   LIGHT THEME — NOW THE DEFAULT for this portal.
   ============================================================================
   WHY THE DEFAULT FLIPPED (the marketing site keeps dark-on-no-preference; this
   surface deliberately diverges):
     - The marketing site is a persuasion surface read in one sitting. This portal
       is a DATA surface: small numbers, dense tables, long columns of figures.
     - NN/g's research is direct on this — for users with normal vision light mode
       gives better performance most of the time, and the advantage GROWS as font
       size shrinks. Dark only wins for cataracts or cloudy ocular media. A metrics
       dashboard is exactly the small-text case.
     - Accessibility for older users is a hard requirement here, and this portal is
       shown to owner-operators of local service businesses, not to developers.
   Dark remains fully supported and one click away; the stored "averon-theme"
   preference still wins in either direction.

   THE SELECTORS:
     html:not([data-theme="dark"])  -> light unless dark is explicitly chosen
     html[data-theme="dark"]        -> the :root block above
   This is the inverse of the marketing site's structure, which is why light is now
   the fallback for a browser reporting NO preference.

   NOT AN INVERSION OF DARK: on dark, --card is LIGHTER than the page. Reusing that
   logic here would give white-on-white at 1.05:1. Light mode instead darkens the
   PAGE so a white card lifts off it (1.41:1 measured), and leans harder on the
   border. Shadows are rebuilt at much lower opacity because dark's rgba(0,0,0,.3)
   glows read as grey smudges on paper.
   ============================================================================ */
html { color-scheme: light dark; }

html:not([data-theme="dark"]) {
  /* SURFACE RAMP — page darkened from #e2e8f0 to #d2dae6.
     At #e2e8f0 a white card measured only 1.23:1 against the page, so panels did
     not read as panels — the same defect the dark theme had, in the other
     direction. #d2dae6 puts it at 1.41:1, and the nav a further step down at
     #c9d3e1 gives card-vs-nav 1.51:1. Body text is unaffected: --tx on a white
     card is 17.85:1 either way. */
  --bg:#d2dae6; --bg2:#c9d3e1;
  --card:#ffffff; --card2:#f2f6fa;
  /* Borders raised from .14/.22. At .14 a hairline on white measured 1.34:1 —
     invisible, and below WCAG 1.4.11's 3:1 where the border IS the panel boundary.
     .26 measures 1.77:1 as a hairline and --line-ui .55 carries the UI-component
     cases (buttons, inputs) at 4.4:1. */
  --line:rgba(15,23,42,.26); --line2:rgba(15,23,42,.34);
  --line-top:rgba(15,23,42,.18); --line-ui:rgba(15,23,42,.55);
  --tx:#0f172a; --tx2:#475569; --tx3:#475569;
  /* --tx3 is darkened to #475569 (same as --tx2) because in light mode the NAV
     (#c9d3e1) is DARKER than the card, and the who-email sub-line sits there:
     #556475 measured 4.01:1 on the nav and FAILED. Light mode simply does not need
     a third text step — collapsing it is honest rather than inventing a value that
     only passes on one of the two surfaces. */
  --ac:#7c3aed; --ac2:#6d28d9; --on-ac:#ffffff;
  --acdim:rgba(124,58,237,.10); --acline:rgba(124,58,237,.30);
  --acline2:rgba(124,58,237,.44); --acline-ui:rgba(109,40,217,.85);
  --ac-blue:#2563eb; --ac-blue2:#1d4ed8; --acblue-dim:rgba(37,99,235,.10);
  /* Light mode needs no separate text accent: on a solid white card --ac #7c3aed
     measures 5.70:1 and --ac-blue #2563eb measures 5.17:1, both already clear of
     the 4.5:1 body-text floor. The aliases point straight at the base tokens so
     every rule can reference --ac-tx unconditionally. */
  --ac-tx:#7c3aed; --ac-blue-tx:#1d4ed8;
  --grad:linear-gradient(135deg,#7c3aed 0%,#2563eb 100%);
  --grad-hover:linear-gradient(135deg,#6d28d9 0%,#1d4ed8 100%);
  --loss:#be123c; --lossbg:#fef2f3;
  --gain:#036b4e; --gainbg:#f0fdf4;
  --sc-violet:#6d28d9; --sc-indigo:#4338ca; --sc-sky:#1d4ed8;
  /* Amber on white fails badly as text, so light mode inverts the notice into a
     tinted panel with dark ink instead of a solid amber bar. */
  --notice:#92660a; --notice-ink:#3f2c02;
  --noticebg:#fdf6e3; --noticeline:rgba(146,102,10,.40);
  /* Shadows carry more of the elevation work now that they sit on a darker page. */
  --elev-sm:0 1px 2px rgba(15,23,42,.08),0 1px 3px rgba(15,23,42,.06);
  --elev-md:0 2px 4px rgba(15,23,42,.08),0 6px 16px rgba(15,23,42,.09);
  --elev-lg:0 4px 8px rgba(15,23,42,.09),0 12px 32px rgba(15,23,42,.11);
  --edge-hi:inset 0 1px 0 rgba(255,255,255,.9);
}

/* ---------- base ---------- */
*{box-sizing:border-box;margin:0}
html{-webkit-text-size-adjust:100%}
body{
  font-family:var(--f);font-size:var(--fs-1);line-height:1.6;
  background:var(--bg);color:var(--tx);
  -webkit-font-smoothing:antialiased;
  transition:background var(--t-base) var(--ease),color var(--t-base) var(--ease);
}
a{color:inherit;text-decoration:none}
:focus-visible{outline:2px solid var(--ac);outline-offset:2px;border-radius:4px}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{transition-duration:.01ms!important;animation-duration:.01ms!important}
}

/* ---------- wordmark ----------
   The real Averon mark: the word plus an accent period. NOT a coloured tile with a
   letter in it, which is what the first portal pass invented. */
.logo{
  font-weight:680;font-size:var(--fs-2);letter-spacing:-.018em;color:var(--tx);
  min-height:44px;display:inline-flex;align-items:center;
}
.logo b{color:var(--ac)}

/* ---------- buttons ---------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  padding:13px 22px;border-radius:12px;font-size:var(--fs-2);font-weight:590;
  border:1px solid transparent;cursor:pointer;font-family:inherit;text-align:center;
  min-height:44px;
}
/* Primary: the brand gradient, parked at 0% of a 200%-wide ramp and slid to 100%
   on hover. background-position is animatable; background-IMAGE is not, so
   swapping --grad for --grad-hover would snap. Same trick as the marketing site's
   primary CTA, and kept to the primary action only so the effect is not spent. */
.btn-p{
  background:var(--grad);background-size:200% 100%;background-position:0% 0;
  color:var(--on-ac);
  transition:background-position .45s var(--ease),transform var(--t-quick) var(--ease),box-shadow var(--t-base) var(--ease);
  box-shadow:0 3px 10px rgba(155,109,255,.18),inset 0 1px 0 rgba(255,255,255,.25);
}
.btn-p:hover:not(:disabled){background-position:100% 0;transform:translateY(-2px);
  box-shadow:0 8px 26px rgba(155,109,255,.45),inset 0 1px 0 rgba(255,255,255,.3)}
.btn-p:active{transform:translateY(0)}
.btn-p:disabled{opacity:.6;cursor:progress}
/* Ghost outlines are UI COMPONENT boundaries (WCAG 1.4.11, 3:1), not decoration,
   which is why they point at --line-ui rather than --line. */
.btn-g{background:transparent;border-color:var(--line-ui);color:var(--tx);
  transition:border-color var(--t-base),color var(--t-base),background var(--t-base)}
.btn-g:hover{border-color:var(--ac);color:var(--ac);background:var(--acdim)}
.btn-full{width:100%}

/* ---------- icons ---------- */
.ic{width:18px;height:18px;flex:none;display:inline-block;vertical-align:-3px}
/* Arrow glyphs are NOT in the Inter subset (verified with fontTools: the 109-glyph
   subset has no U+2190/2191/2193). A missing glyph falls back to a system font
   mid-string, which reads as a rendering bug. These are drawn as SVG instead. */
.ic-sm{width:13px;height:13px}
