/* ============================================================================
   PORTAL SKIN SHAPE — the handful of things a --g-* token cannot carry.
   Wave: wave-portal-skins (.agents/mission/wave-portal-skins/PLAN.md). Lane L2.
   LOAD ORDER: after css/portal-skins.css (the token sheet, lane L1), which is
   itself after css/legacy-bridge.css. This file declares COMPONENTS, not tokens
   — it is the wave's only intentional reach into .cpd-*/.cp-* and therefore the
   only stylesheet in the wave that can leak onto the shipped studio baseline.
   It does not leak, and here is the mechanism that guarantees it.

   ---------------------------------------------------------------------------
   WHY EVERY SELECTOR IS PINNED, AND TO EXACTLY (0,3,2)
   ---------------------------------------------------------------------------
   The portal paints itself from a single <style id="cp-style"> that js/client-
   portal.js INJECTS INTO <head> at render — i.e. AFTER any <link>, so on source
   order alone #cp-style's own rules (`.cpd-card-val` = (0,1,0), `.cpd-c-ok
   .cpd-card-val` = (0,2,0)) would win over anything a linked sheet says. So a
   shape rule here cannot rely on order; it must out-SPECIFY the injected rule.
   Every rule below is prefixed:

       html[data-ui-theme="portal-X"] body.cl-app <selector>

   The prefix alone is (0,2,2) — [data-ui-theme] + .cl-app in the class column,
   html + body in the element column — and every <selector> adds at least one
   class, so the floor is (0,3,2). That beats #cp-style's (0,1,0)/(0,2,0) rules
   at every mode and every source order, WITHOUT a single !important (banned).
   And because the prefix carries `[data-ui-theme="portal-*"]`, none of these
   rules can match a client on studio/baseline or a staff seat on any of the 11
   house themes: absent the attribute, the whole sheet is inert. That is the
   baseline guarantee, stated as a selector invariant rather than asserted.

   ---------------------------------------------------------------------------
   SCOPE — deliberately tiny. Tokens do the rest.
   ---------------------------------------------------------------------------
   A "look" in this app is a --g-* token set (css/themes.css header). Colour,
   glass, radii, shadow, blur, ground — all of it is L1's token sheet. This file
   exists ONLY for the two things the 122-token contract has no vocabulary for:

     • portal-bold : a DISPLAY/METRIC TYPE SCALE. Bold's identity is oversized
       numerals (mockup variant-b-bold.html:228-230 --fs-display / --fs-metric /
       --fs-metric-tx), and there is no --g-fs-* contract to carry a type ramp.
       So the greeting, the result numerals, the KPI numerals and the taller
       result-card box are set here — for portal-bold ONLY.
     • portal-calm : NEUTRALISED NUMERALS. #cp-style hard-codes the numeral
       colour to var(--g-green)/var(--g-amber)/var(--g-accent) by tone; a token
       cannot say "paint this numeral with --g-text instead of --g-green". Calm's
       mockup (variant-a-calm.html:410-412) paints EVERY numeral in plain ink —
       that is the "three green numbers = slot machine" fix — so this file
       repoints those numerals to --g-text for portal-calm ONLY.
     • portal-balanced : NOTHING. It is a pure token skin (PLAN §3 coverage map);
       its smallest-delta identity is fully expressible in --g-* and it owns no
       rule in this file by design. The block below is a comment, not code.

   Calm's "flat divider" was evaluated and is NOT here: the portal's dividers all
   read from --g-hairline / --g-edge-* / --g-shadow-* (the only hard-coded borders
   in client-portal.js are dashed empty-state boxes and two unrelated status tints),
   so L1's calm tokens flatten them with zero component reach. Adding a divider rule
   would have spent leak-risk for no gain.

   BANS honoured: no !important; no display/grid-template edits (nothing here can
   hide content — only font-size, letter-spacing, line-height, color, min-height
   move); no overflow-x swipe rows; every selector contains body.cl-app AND
   [data-ui-theme="portal-.

   NAMING NOTE (see the lane report): the brief named the KPI numeral ".cp-stat-v".
   No such class exists — the KPI value is emitted as <b class="cp-num"> inside
   .cp-stat (client-portal.js:2559-2560), styled by `.cp-stat b` (:4903). These
   rules therefore target `.cp-stat b`, the real element.
   ============================================================================ */


/* ============================================================================
   PORTAL-BOLD — the type scale. "The numbers are the design."
   Values lifted from variant-b-bold.html; the mockup's --fs-display /
   --fs-metric / --fs-metric-tx clamps and their letter-spacing / line-height.
   Type only — no colour is touched here, so one rule serves light AND dark.
   ============================================================================ */

/* ① greeting — the oversized display headline (mockup .hi :599-604 = --fs-display,
   -.042em, .98). Base .cpd-hi is 23px/800 (client-portal.js:4194); weight already
   matches, so only the ramp moves. */
html[data-ui-theme="portal-bold"] body.cl-app .cpd-hi {
  font-size: clamp(38px, 7.4vw, 66px);
  letter-spacing: -0.042em;
  line-height: 0.98;
}

/* ② the result numerals — split num vs. text exactly as the mockup does
   (.metric :694-700 vs .metric.is-text :700). .cpd-card-val gains ` cp-num` when
   the value is numeric (client-portal.js:324), so .cp-num carries the big metric
   clamp and the bare (word) case carries the smaller text clamp — a word like a
   long label never renders at 64px and never overruns the tile. */
html[data-ui-theme="portal-bold"] body.cl-app .cpd-card-val {
  font-size: clamp(28px, 3.4vw, 44px);
  letter-spacing: -0.038em;
  line-height: 0.95;
}
html[data-ui-theme="portal-bold"] body.cl-app .cpd-card-val.cp-num {
  font-size: clamp(42px, 5vw, 64px);
  letter-spacing: -0.05em;
  line-height: 0.92;
}

/* ③ muted placeholder value ("Soon", client-portal.js:347/365/375) stays quiet —
   without this, rule ② would blow the placeholder up to the text-metric size and
   it would read as a real metric. Keep it a soft caption; base keeps its --g-text-2
   colour (untouched). (0,4,2) so it also wins over the numeric ② for any
   muted+numeric card, whatever the source order. */
html[data-ui-theme="portal-bold"] body.cl-app .cpd-c-muted .cpd-card-val {
  font-size: clamp(24px, 2.8vw, 32px);
  letter-spacing: -0.02em;
}

/* ④ the Stats-page KPI numerals — the same metric scale as ②, on the real element
   `.cp-stat b` (client-portal.js:4903; the brief's ".cp-stat-v" does not exist). */
html[data-ui-theme="portal-bold"] body.cl-app .cp-stat b {
  font-size: clamp(42px, 5vw, 64px);
  letter-spacing: -0.05em;
  line-height: 0.92;
}

/* ⑤ the result-card box grows to hold the big numeral — mockup .tile min-height
   208px (:666). No display/grid change: only the box's floor moves, cards stay a
   2-col grid, nothing is clipped. Base is 118px (client-portal.js:4212). */
html[data-ui-theme="portal-bold"] body.cl-app .cpd-card {
  min-height: 208px;
}


/* ============================================================================
   PORTAL-CALM — kill the slot machine. Every numeral becomes plain ink.
   Calm's mockup paints ALL numerals var(--v-ink) regardless of tone
   (variant-a-calm.html:410-412); the accent is spent on interaction, never on a
   number. #cp-style hard-codes the tone colours, so we repoint them to --g-text.
   Colour only; --g-text is theme-aware, so one rule serves light AND dark.
   The tone icon-CHIPS keep their (L1-desaturated) green/amber — only the NUMBERS
   go neutral, matching the mockup ("one brick accent, desaturated green/amber").
   ============================================================================ */

/* home-dashboard result numerals (the literal "three green numbers" case).
   Overrides #cp-style :4233-4234 (`.cpd-c-ok/.cpd-c-warn .cpd-card-val`). */
html[data-ui-theme="portal-calm"] body.cl-app .cpd-c-ok .cpd-card-val {
  color: var(--g-text);
}
html[data-ui-theme="portal-calm"] body.cl-app .cpd-c-warn .cpd-card-val {
  color: var(--g-text);
}

/* Stats-page KPI numerals — same defect, different screen. Overrides #cp-style
   :4906-4907 (`.cp-stat-win b` green, `.cp-stat-accent b` accent). Neutralising
   these too is what keeps Calm internally consistent (a green KPI number on the
   Stats page would re-open the exact slot-machine the Home fix closes). See the
   lane report — this pair extends the brief's named .cpd-card-val example to the
   full "coloured stat numerals" set the calm mockup mandates. */
html[data-ui-theme="portal-calm"] body.cl-app .cp-stat-win b {
  color: var(--g-text);
}
html[data-ui-theme="portal-calm"] body.cl-app .cp-stat-accent b {
  color: var(--g-text);
}


/* ============================================================================
   PORTAL-BALANCED — intentionally empty.
   Balanced is a pure token skin (PLAN §3): its identity is the smallest delta
   from studio and is fully carried by L1's --g-* values. It owns no component
   rule here. If a future change needs one, it goes below this line with the same
   html[data-ui-theme="portal-balanced"] body.cl-app <selector> prefix.
   ============================================================================ */

/* ---------------------------------------------------------------------------
   CLIENT OS primitives on the Bold skin (2026-09-12, L1 handoff). The Bold ramp
   above is pinned to .cpd-* / .cp-stat selectors, so a client on Bold would see
   oversized dashboard numerals next to NORMAL-sized estimate / invoice figures.
   Same clamps as (2) and (4) on the real Client OS elements (css/client-os.css):
   the KPI numeral, the money block's total, and the detail heading. (0,3,2) beats
   the component sheet's (0,1,0) whatever the source order.
   --------------------------------------------------------------------------- */
html[data-ui-theme="portal-bold"] body.cl-app .cos-kpi-n {
  font-size: clamp(42px, 5vw, 64px);
  letter-spacing: -0.05em;
  line-height: 0.92;
}
html[data-ui-theme="portal-bold"] body.cl-app .cos-money-row.is-total .cos-money-v {
  font-size: clamp(24px, 2.8vw, 32px);
  letter-spacing: -0.03em;
  line-height: 1;
}
html[data-ui-theme="portal-bold"] body.cl-app .cos-head-title {
  font-size: clamp(26px, 3.4vw, 40px);
  letter-spacing: -0.038em;
  line-height: 0.98;
}
