/* ============================================================================
   Decision Frameworks — design tokens

   The normative half of the design language. Every shared value lives here
   exactly once; components reference, never restate. The reasoning behind the
   values — when to use which, how much a surface should assert itself — lives
   in docs/design-language.md, which deliberately contains no numbers.

   NAMING: --df-<group>-<name>[-<variant>]
     group    surface | pill | dot | control | persona | rail | typename | ...
     variant  size or state suffix: -sm/-md/-lg, -hover/-active

   Tokens hang off `body`, matching the convention already in app.css
   (--body-font, and the body[data-theme='dark'] override block). Anything that
   must differ per theme goes in the dark block at the foot of this file.

   Prefer composing from FluentUI's own tokens (--neutral-*, --accent-*) over
   literal colours, so the app keeps following the Fluent theme.

   EARNING A PLACE: a value belongs here once it has **two or more** consumers.
   A token used once carries the same drift risk as a literal and adds
   indirection on top, so per-view one-offs (rail widths, the bar's height, the
   row's selection tint) deliberately stay local to their stylesheet.

   STATUS: consumed by the four IssueRaising views and the assessment link
   button. Other features still hardcode; migrate opportunistically when you
   touch one rather than sweeping.

   CHECKING: `tools/Check-DesignTokens.ps1` fails on any `var(--df-*)` that is
   not declared here. A typo'd custom property does not error at runtime — it
   silently falls back to the initial value — so run it after editing.
   ============================================================================ */

body {
    /* ---- Surfaces -------------------------------------------------------
       The card/bar/tile surface. Slightly lighter than the default card fill.
       Canonical: .issue-card / .issue-bar / .issue-tile */
    --df-surface-card: var(--neutral-fill-input-rest);
    --df-surface-card-border: var(--neutral-stroke-rest);
    --df-surface-card-radius: 8px;

    /* ---- Pills (tag badges) --------------------------------------------
       Canonical: .issue-card-tag (IssueCard.razor.css), duplicated as
       .issue-bar-tag and .detail-tag. */
    --df-pill-height: 18px;
    --df-pill-radius: 999px;
    --df-pill-padding-x: 8px;
    --df-pill-font-size: 11px;
    --df-pill-font-weight: 600;

    /* ---- Switchable chips: the "off" wash --------------------------------
       A chip that can be switched off keeps its own colour as a hairline border
       rather than greying out, and washes that colour in on hover. The base
       colour differs per consumer — the issue type, the tag, or a neutral for
       colourless pseudo-tags — so what is shared is the *strength*, not a
       resolved colour. Hence a percentage.
       Distinct from --df-control-ghost-hover, which is a neutral overlay on
       icon buttons: a chromatic wash needs more strength to read at all.
       Canonical: .issue-type-chip.off (IssueTypeChips), .tag-pill.off (TagPill). */
    --df-chip-off-wash: 16%;

    /* ---- Toggle "on" wash -----------------------------------------------
       A toggle that is on carries an accent wash behind its label. The strength has to
       differ per theme, which is why it is a token rather than a literal: the percentage
       that reads as a clear tint over the light card desaturates to plain grey over the
       dark one, because a thin accent laid on a dark surface loses its hue. Sibling of
       --df-chip-off-wash, which makes the same point for switchable chips.
       Canonical: .tb-toggle.on (Post Issues, Select) in IssueRaising. */
    --df-toggle-on-wash: 14%;

    /* ---- Dots (a pill collapsed to colour only) -------------------------
       Canonical: .issue-row-dot, .issue-tile-dot. */
    --df-dot-size: 9px;

    /* ---- Ghost icon controls -------------------------------------------
       Round, transparent at rest, translucent overlay on hover so the cue
       reads on any background — plain, hovered, selected or tinted.
       NB the radius and the fill belong on ::part(control), not the host.
       Canonical: .issue-card-footer-button, .issue-row-action-button,
       .issue-bar-bottom-right fluent-button. */
    --df-control-radius-round: 1000px;
    --df-control-ghost-hover: color-mix(in srgb, var(--neutral-foreground-rest) 12%, transparent);
    --df-control-ghost-active: color-mix(in srgb, var(--neutral-foreground-rest) 18%, transparent);

    /* ---- Creator persona -----------------------------------------------
       A size ramp, not one size: the persona shrinks with the surface.
       Canonical: .issue-card-persona (lg), .issue-row-persona (md),
       .issue-bar-persona / .issue-tile-persona (sm). */
    --df-persona-size-lg: 24px;
    --df-persona-size-md: 22px;
    --df-persona-size-sm: 18px;
    --df-persona-font-lg: 10px;
    --df-persona-font-md: 9.5px;
    --df-persona-font-sm: 8px;
    --df-persona-fill: var(--accent-fill-rest);
    --df-persona-foreground: var(--foreground-on-accent-rest, #fff);

    /* ---- Turned type name ----------------------------------------------
       The spelled-out issue type running down the colour rail. Weight,
       tracking and opacity are shared so it reads as the same label wherever
       it appears; only the size differs per surface, and it differs in only
       two places, so the sizes stay local.
       Rail *widths* likewise stay local — they are a ramp (wider surface,
       wider rail) with one consumer each, described in docs/design-language.md.
       Canonical: .issue-spine-name (card), .issue-bar-typename (bar). */
    --df-typename-weight: 600;
    --df-typename-tracking: 0.1em;
    --df-typename-opacity: 0.88;

    /* ---- Selection ------------------------------------------------------
       Single select is the accent; multi-select is the presence green, and
       adds the corner tick — colour alone is not an accessible signal.
       Canonical: .issue-card-single-selected / -multi-selected, mirrored in
       every view.
       The list row additionally *tints* its background; that stays local as
       the only consumer. NB any surface that inherits a background in order to
       occlude something must resolve opaque — mix against --df-surface-card,
       never against transparent. */
    --df-select-single: var(--accent-fill-focus);
    --df-select-multi: var(--presence-available);

    /* =====================================================================
       TIER 2 — everyday components
       Owned by the Excel-to-Blazor migration effort. Add tokens here as that
       work settles them; keep the --df-<group>-<name> convention. Delete a
       stub rather than leaving it empty if it turns out not to be needed.
       See docs/design-language.md for what belongs at this tier.
       ===================================================================== */

    /* --- Signed values ---
       A figure coloured by its sign: gains positive, losses negative. Sourced
       from the Fluent presence palette so the app keeps one green and one red
       from a single, theme-managed source instead of growing a private pair.
       Named by meaning rather than by "presence", so the value can be overridden
       here without any call site caring where it came from — which is also the
       escape hatch if the dark theme needs it: presence colours do not brighten
       in dark, so small signed text there sits near the contrast floor.
       Canonical: .rfv-pos / .rfv-neg (RiskFactorVoiWorkspace.razor.css) and the
       per-factor VOI tooltip (PerFactorVoiSummary.razor.css). */
    --df-value-positive: var(--presence-available);
    --df-value-negative: var(--presence-busy);

    /* --- Status colours ---
       Affirmative / caution / destructive, for status accents, banners and status text.
       `--success-fill-rest` / `--warning-fill-rest` / `--error-fill-rest` were referenced across the
       app but are NOT real FluentUI tokens (Fluent Blazor ships only --accent-* and --neutral-*
       fills), so every use silently fell back — grey, accent, or a hardcoded hex (issue #463).
       Sourced, like the signed-value pair above, from the Fluent presence palette so there is one
       theme-managed green / amber / red. Warning is the two-consumer anchor (a landing card accent +
       the anonymous-room banner); success and danger join it so the family reads as one and no
       phantom status token survives. Presence colours do not brighten in dark — fine for saturated
       accents, strokes and text; where a pale fill is wanted, mix the token into a neutral surface at
       the call site (there is no shared pale, so it stays local).
       Canonical: .welcome-empty-state--success / .doc-card--pending (Index), the anonymous-room
       closed banner and over-limit count (AnonymousIssueRaising). */
    --df-status-success: var(--presence-available);
    --df-status-warning: var(--presence-away);
    --df-status-danger: var(--presence-busy);

    /* --- Form fields --- */
    /* TODO(tier2): label/field spacing, input height, invalid state */

    /* --- Data grids --- */
    /* TODO(tier2): row height, header treatment, zebra/hover, dense variant */

    /* --- Dialogs --- */
    /* TODO(tier2): width ramp, padding, footer action order */

    /* --- Buttons (non-ghost) --- */
    /* TODO(tier2): primary/secondary/destructive, height ramp, icon spacing */

    /* --- Charts --- */
    /* TODO(tier2): series palette, axis/gridline treatment, empty state */

    /* =====================================================================
       TIER 1 — chrome
       Nav, layout, panels. Should be almost entirely FluentUI defaults; add a
       token here only when something genuinely cannot be expressed with them.
       ===================================================================== */

    /* ── Chrome elevation — TUNE --df-chrome-shadow-strength (CSS hot-reloads) ────────────────
       The top bar and left nav rail cast a drop shadow onto the content's TOP and LEFT edges. The
       hard part was keeping it fixed while the content scrolls: an inset on the content was covered
       by the scrolling card, an absolute overlay on the content scrolled away, and a sticky strip
       latched onto whichever nested scroll a page happened to have. So the content pane is now wrapped
       in a NON-scrolling `.doc-elevation-frame`, and the shadow is a single INSET box-shadow on that
       frame's overlay (`.doc-elevation-frame::before`). Because the frame never scrolls, the overlay
       is genuinely fixed no matter what scrolls inside it; because it's ONE inset shadow, the top and
       left edges are identical and meet in a rounded corner.
       The offset points into the top-left and |spread| > blur, so it doesn't leak onto the right or
       bottom. On mobile there's no rail, so the layout media queries drop it to top-only. Change
       --df-chrome-shadow-strength (opacity 0–1) for a stronger/softer shadow. The mobile bottom bar
       keeps its own symmetric --df-chrome-shadow. */
    --df-chrome-shadow-strength:  0.33;
    --df-chrome-shadow-inset:     inset 12px 12px 14px -15px rgba(0, 0, 0, var(--df-chrome-shadow-strength));
    --df-chrome-shadow-inset-top: inset 0   12px 14px -15px rgba(0, 0, 0, var(--df-chrome-shadow-strength));
    --df-chrome-shadow:           0 0 8px 0 rgba(0, 0, 0, 0.18);
    /* Radius of the content's top-left corner AND the shadow overlay's corner — they must match, or
       the frame's square corner peeks out inside the shadow's rounded one. */
    --df-chrome-corner: 8px;

    /* Radius of a chrome *layer* — the white document paper (.doc-placeholder-inner in both
       layouts) and a floating page toolbar card. Follows FluentUI's own layer radius so the
       app tracks the theme, and lives here because that token is UNITLESS (8, not 8px): a
       bare var() silently renders no radius at all, so the `* 1px` belongs in exactly one
       place rather than being re-derived — and re-broken — at each call site.
       Deliberately NOT --df-surface-card-radius, which is the same number today but is a
       tier-3 value owned by the issue cards; chrome and domain objects are free to diverge.
       Canonical: .issue-toolbar-card (IssueRaising), .doc-placeholder-inner (Document/MainLayout). */
    --df-chrome-layer-radius: calc(var(--layer-corner-radius) * 1px);
}

/* Theme overrides. FluentDesignTheme sets document.body.dataset.theme, and
   app.css already keys off it. Only tokens that cannot be expressed as a Fluent
   token need repeating here — most of the above follow the theme for free. */
body[data-theme='dark'] {
    /* An accent wash thin enough to read as a tint on the light card desaturates to plain
       grey over the dark one, so an "on" toggle needs more of the accent here to still read
       as accent rather than as a grey fill. */
    --df-toggle-on-wash: 30%;
}
