/*
  GENERATED by scripts/build-css.mjs from src/tokens/*.json. Do not edit.

  The DTCG sets are the source. Edit those, or let a Figma sync open a PR
  against them, then run `pnpm build`. Editing this file works until the
  next build silently reverts it.

  CloudGrid tokens: the CloudGrid Web 2026 design language.

  This is the @cloudgrid-io/ui copy, ported 2026-08-10 from the v0 library
  (atomicfuse/ui, src/styles/tokens.css), which was itself synced from
  cloudgrid-landing. That makes this the third copy in the chain, and three
  copies is one too many: the intent is that this package becomes authoritative
  and the other two consume it. Until that migration happens, treat the SITE's
  src/styles/tokens.css as the source of truth and sync changes forward to here.

  The site's copy carries a superset (a legacy alias shim, --bg/--ink/etc., for
  its unrebuilt surfaces) that is deliberately NOT part of this package.

  Values here are the real brand system. The setup guide's Step 2 sketch
  (cyan/magenta, dark-first, Nunito/DM Mono) does not describe this brand and
  was not used.

  Originally ported from the Claude Design project "Cloudgrid"
  (303a54ca-2f23-4906-8040-879e8d9a7b6f), token files colors/typography/fonts/
  spacing/radius/elevation/motion. Values marked SOURCE were sampled from the
  supplied 1440px brand frames or given by the brand owner.

  The system is light, flat and gradient-free. Containment is done with 1px
  hairlines, not elevation. The one dramatic move is the purple panel, which is
  a token flip rather than a separate stylesheet: put data-cg-surface="panel" on
  any container filled with --cg-surface-panel and every semantic token below
  switches to its on-purple value.

  A theme change is a value swap in this file. Components consume custom
  properties exclusively and must never hardcode a hex.
*/

:root,
[data-theme='default'] {
  /* ---- brand ----
     brand (SOURCE) */
  --cg-ink: #222222;
  --cg-primary: #5a47f0;
  --cg-secondary: #b6de68;
  --cg-tertiary: #60e9f0;

  /* ---- danger ----
     danger (PLACEHOLDER, not a brand value)

     Operator decision 2026-08-16, issue #62, stated as a placeholder in the
     operator's own words: "its just a red i found. one day the brand designer
     might change it, but until then this is it."

     It lives here, beside the brand sources, because that is the one place a
     designer should have to edit. Nothing else in the system carries a red.

     Measured against every surface before it was chosen, because a flat value
     cannot work on all three:

     #E53935 on white  #ffffff : 4.23:1
     #E53935 on panel  #5a47f0 : 1.38:1   <-- invisible, hence the override
     #E53935 on ink    #222222 : 3.76:1

     1.38:1 on purple is the #41 failure repeating: that issue found the primary
     button rendering the panel's own colour at 1:1. The per-surface values in
     the panel and ink scopes below are derived from this red rather than being
     new brand decisions.

     KNOWN, and deliberately not "fixed" by changing the operator's value: 4.23:1
     on white clears the 3:1 bar for UI components and borders, and is just under
     the 4.5:1 AA bar for body text. `text-destructive` has 5 uses. A future
     brand pass can darken it; that is a decision, not a tidy-up. */
  --cg-danger: #E53935;

  /* ---- state ----
     state: what an entity IS, not what it means editorially.

     Adopted from the Console rather than invented, 2026-08-24 (#96). The Console
     had already chosen and contrast-tested these — --color-live and
     --color-attention — while the brand carried no state colour at all beyond the
     danger placeholder. Taking its values means the Console's appearance does not
     change when it starts consuming this package, and the two stop disagreeing
     about what 'live' looks like.

     Each carries per-surface values in surface-panel and surface-ink, for the same
     reason danger does: measured against all three grounds, no single value works.
     The live green is 1.72:1 on the purple panel, and the brand's own lime is
     1.54:1 on white. A flat value would be invisible somewhere.

     No --cg-offline-fill, deliberately. Measured, the pair does not work: the
     muted neutral on a neutral tint is 2.90:1, under the 3:1 bar for a dot or a
     border. Rather than invent a value to satisfy the ratio, an unplugged chip
     uses the existing surface-card ground with border-control, and --cg-offline
     is the dot on that ground, where it measures 3.28:1. Absence of state should
     not need a colour of its own.

     pending joined them on 2026-08-24 (#114) as an ALIAS of expired rather than a
     new value. Same amber today, separate name, so the two can diverge later with
     a one-line edit here and no change in any consumer. Aliases compile to var(),
     so the flip survives.

     unhealthy joined them on 2026-08-25 (#122) as a REAL value, not an alias, and
     it is the one tone here that was searched for rather than adopted. Founder
     decision: expired is terminal, unhealthy is live-and-fixable, and sharing a
     token would mean retuning one silently retunes the other. It is a warmer,
     brighter gold on the same ramp as the amber rather than a new hue family,
     because green/amber/red is the traffic light an operator already reads and
     'serving but degraded' is its middle rung. Its own note carries the numbers
     and the three families that were measured and rejected. */
  /*
     Serving. From the Console's --color-live. 3.40:1 on white — clears the 3:1 bar for an indicator, which is all this is ever used as. Never body text on white. */
  --cg-online: #00a05c;
  /*
     Unplugged. Deliberately the existing muted neutral rather than a new colour — an entity that is off should recede, not signal. 3.28:1 on white. */
  --cg-offline: var(--cg-neutral-500);
  /*
     Past its 30-day life and no longer served. From the Console's --color-attention. 4.39:1 on white. Amber rather than red: expiry is the documented default for a drop, not a fault. */
  --cg-expired: #b0662a;
  /*
     In progress. Deliberately an ALIAS of expired rather than the same hex written twice: the two are one amber today and they are not the same idea, so a designer must be able to separate them without touching a consumer.

     Expired is terminal, pending is transitional, and warm is the honest reading for both. Grey would be wrong twice over for a building entity, because it is not absence and because a building entity may still be serving its previous version.

     Founder decision 2026-08-24, issue #114: "building is like something in progress, something in between amber and yellow and orange." */
  --cg-pending: var(--cg-expired);
  /*
     Serving, and degraded. The entity is up and answering; its health checks are not. 4.82:1 on white and 4.46:1 on its own fill — an indicator, like every tone here, never body text.

     A REAL value rather than an alias, which is the whole decision. Founder, 2026-08-25, issue #122: expired is terminal, unhealthy is live-and-fixable, and one token for both would mean a designer retuning one silently retunes the other. That is the same reasoning that gave pending its own NAME in #114 — this one also needs its own VALUE, because it must not read as either of the states it sits between.

     WHY A GOLD, measured rather than asserted. Green/amber/red is the traffic light an operator already reads, and this palette's amber is spent on two states that are both benign: pending is transitional, expired is terminal. Unhealthy is the warning rung, so it takes the warmer, brighter, more saturated seat on the same ramp rather than a different hue family.

     The alternatives were searched, not guessed, over every hue at 5-degree steps against all four existing tones on all three surfaces:

       magenta h339   13.7 from danger on the panel, where danger is a pale pink.
                      The one confusion that matters most, and a new palette worst.
       azure   h235   the best normal-vision numbers of anything measured (21.5),
                      and 1.2 from panel offline for a deuteranope — a degraded
                      entity would be indistinguishable from a stopped one.
       chartreuse     10-14 from --cg-secondary and --cg-volt. It IS the brand lime,
                      and #114 already ruled a lime cannot signal state.

     dE2000 on white: online 28.4, offline 26.6, expired/pending 22.3, danger 43.1. The tightest pair is expired, as expected for the neighbouring rung, and 22.3 is wider than the tightest pair this palette already ships on white (19.4, expired/danger).

     KNOWN, and recorded rather than tuned away: on ink the pair is 18.3, which is a new worst for that surface (was 25.3). It stays above the palette's global floor of 16.5, and buying more would mean walking into --cg-secondary (16.5 away) or --cg-volt (17.8). A light amber and a light gold have the least room on a dark ground; that is the cost of putting them on one ramp deliberately. */
  --cg-unhealthy: #7F7301;
  /*
     From the Console's --color-live-fill. --cg-online measures 3.06:1 on it. */
  --cg-online-fill: #e6f7ef;
  /*
     From the Console's --color-attention-fill. --cg-expired measures 3.99:1 on it. */
  --cg-expired-fill: #fdf3e0;
  /*
     The chip ground for pending, aliased to expired's for the same reason the foreground is. Splitting pending from expired later means editing these two entries and nothing else. */
  --cg-pending-fill: var(--cg-expired-fill);
  /*
     The chip ground for unhealthy. --cg-unhealthy measures 4.46:1 on it.

     A pale tint of its own foreground, in the same family as online-fill and expired-fill, so the five chips read as one set rather than as four tints and an exception. It is deliberately NOT expired-fill: a shared ground would put the two warm states on the same card and undo half of what the separate foreground buys. */
  --cg-unhealthy-fill: #fdf6df;
  /*
     From the Console's --color-error-fill. --cg-danger measures 3.72:1 on it. danger had no fill before; a chip needs one. */
  --cg-danger-fill: #fceded;

  /* ---- brand-derived ----
     brand derived (interaction only) */
  --cg-primary-press: #4b39db;
  --cg-primary-tint: #eeecfe;
  --cg-secondary-press: #a6cf57;
  --cg-tertiary-press: #4dd8e0;

  /* ---- neutrals ---- */
  --cg-neutral-0: #ffffff;
  /* SOURCE: alternate page wash */
  --cg-lavender-50: #f2f1f7;
  /* SOURCE: hairline / card border */
  --cg-neutral-100: #f1f1f1;
  /* SOURCE: control border, inactive pill fill */
  --cg-neutral-200: #e3e3e3;
  /* SOURCE: placeholder */
  --cg-neutral-400: #acacac;
  /* SOURCE: footer text */
  --cg-neutral-500: #8e8e8e;
  /* SOURCE: legal / secondary text */
  --cg-neutral-700: #595959;
  /* SOURCE: ink */
  --cg-neutral-900: #222222;

  /* ---- semantic-surfaces ---- */
  --cg-surface-page: var(--cg-neutral-0);
  --cg-surface-page-alt: var(--cg-lavender-50);
  --cg-surface-card: var(--cg-neutral-0);
  --cg-surface-subtle: var(--cg-lavender-50);
  --cg-surface-control: var(--cg-neutral-200);
  --cg-surface-panel: var(--cg-primary);
  --cg-surface-code: var(--cg-ink);

  /* ---- semantic-text ---- */
  --cg-text-primary: var(--cg-neutral-900);
  --cg-text-secondary: var(--cg-neutral-700);
  --cg-text-muted: var(--cg-neutral-500);
  --cg-text-placeholder: var(--cg-neutral-400);
  --cg-text-accent: var(--cg-primary);
  --cg-text-inverse: var(--cg-neutral-0);
  --cg-text-on-primary: var(--cg-neutral-0);
  --cg-text-on-accent: var(--cg-ink);
  --cg-text-on-code: #e7e7e7;

  /* ---- semantic-lines ---- */
  --cg-border-hairline: var(--cg-neutral-100);
  --cg-border-control: var(--cg-neutral-200);
  --cg-border-strong: var(--cg-ink);
  --cg-border-accent: var(--cg-primary);
  --cg-focus-ring: rgba(90, 71, 240, 0.28);

  /* ---- link ---- */
  --cg-link: var(--cg-text-primary);
  --cg-link-hover: var(--cg-primary);

  /* ---- type-families ----
     H1 is Futura Condensed Extra Bold where it is installed. It is a licensed
     face, NOT a webfont, so Saira Semi Condensed 800 is the self-hosted
     fallback that keeps every H1 heavy and condensed everywhere else. Drop the
     licensed woff2 in and it takes over with no other change. */
  --cg-font-display: 'Futura Condensed ExtraBold', 'Futura Condensed', 'Saira Semi Condensed Variable', 'Saira Semi Condensed', 'Arial Narrow', sans-serif;
  --cg-font-body: 'Manrope Variable', 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --cg-font-mono: 'JetBrains Mono Variable', 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* ---- weights ----
     weights (Manrope ships 400/500/700) */
  --cg-weight-regular: 400;
  --cg-weight-medium: 500;
  --cg-weight-bold: 700;
  --cg-weight-display: 800;

  /* ---- h1-display-ramp ----
     H1 display ramp: uppercase, condensed, Primary or white

     Stepped down one notch 2026-08-06 (operator: main headings read too
     dominant). The SOURCE values were xl 64 / lg 48 / md 42 / sm 32. */
  --cg-display-xl: 56px;
  --cg-display-lg: 44px;
  /* SOURCE: onboarding H1 (was 42px) */
  --cg-display-md: 38px;
  --cg-display-sm: 30px;
  --cg-display-line: 1.06;
  --cg-display-tracking: 0.012em;

  /* ---- manrope-ramp ---- */
  --cg-heading-lg: 24px;
  /* SOURCE: card title */
  --cg-heading-md: 20px;
  /* SOURCE: step title */
  --cg-heading-sm: 17px;
  --cg-heading-line: 1.3;
  /* SOURCE: H1 subline */
  --cg-body-lg: 19px;
  /* SOURCE: default UI text */
  --cg-body-md: 16px;
  /* SOURCE: card body, legal */
  --cg-body-sm: 15px;
  /* SOURCE: footer, helper */
  --cg-caption: 13px;
  --cg-body-line: 1.5;
  --cg-body-tracking: 0em;
  --cg-mono-size: 14px;
  --cg-mono-line: 1.7;
  --cg-label-size: 15px;
  --cg-label-weight: var(--cg-weight-medium);

  /* ---- spacing ----
     spacing: 4px base */
  --cg-space-1: 4px;
  --cg-space-2: 8px;
  --cg-space-3: 12px;
  --cg-space-4: 16px;
  --cg-space-5: 20px;
  --cg-space-6: 24px;
  --cg-space-8: 32px;
  --cg-space-10: 40px;
  --cg-space-12: 48px;
  --cg-space-16: 64px;
  --cg-space-20: 80px;
  --cg-space-30: 120px;

  /* ---- layout ----
     layout (SOURCE measurements from the 1440px frames) */
  --cg-column-form: 414px;
  /* SOURCE 844px; widened 2026-08-06 with the container */
  --cg-column-wide: 920px;
  --cg-page-pad: 32px;
  --cg-header-height: 90px;
  --cg-footer-height: 64px;
  --cg-stack-tight: 8px;
  --cg-stack: 16px;
  --cg-stack-loose: 24px;
  --cg-section-gap: 56px;
  /*
     Marketing pages are wider than the onboarding frames the system was
     measured from, so the site adds one container width of its own.
     1120 -> 1280 on 2026-08-06 (operator: too much white space at the sides). */
  --cg-container: 1280px;
  --cg-measure: 68ch;

  /* ---- corners ---- */
  --cg-radius-xs: 8px;
  --cg-radius-sm: 10px;
  /* SOURCE: code block, OTP cell */
  --cg-radius-md: 12px;
  /* SOURCE: provider button, input, tool card */
  --cg-radius-lg: 14px;
  /* SOURCE: option card */
  --cg-radius-xl: 16px;
  /* SOURCE: full-bleed purple panel */
  --cg-radius-2xl: 24px;
  --cg-radius-pill: 999px;
  --cg-border-width: 1px;
  --cg-border-width-strong: 1.5px;

  /* ---- elevation ----
     elevation: hairlines first, shadow only on the wash or on hover */
  --cg-shadow-none: none;
  --cg-shadow-card: 0 1px 2px rgba(34, 34, 34, 0.04);
  --cg-shadow-raised: 0 4px 14px rgba(34, 34, 34, 0.06);
  --cg-shadow-hover: 0 8px 24px rgba(34, 34, 34, 0.08);
  --cg-shadow-panel: 0 10px 40px rgba(90, 71, 240, 0.18);
  --cg-ring-focus: 0 0 0 3px var(--cg-focus-ring);

  /* ---- motion ----
     motion: small and quick, nothing slides in */
  --cg-duration-fast: 120ms;
  --cg-duration: 180ms;
  --cg-duration-slow: 280ms;
  --cg-ease-out: cubic-bezier(0, 0, 0.2, 1);
  --cg-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
  --cg-transition-control: background-color var(--cg-duration) var(--cg-ease-out), border-color var(--cg-duration) var(--cg-ease-out), color var(--cg-duration) var(--cg-ease-out), box-shadow var(--cg-duration) var(--cg-ease-out);
  --cg-lift-hover: translateY(-1px);
  --cg-press-scale: 0.985;

  /* ---- indicator ----
     indicator + chrome: taken from the Console so the system holds every value in
     one place, 2026-08-24 (#96).

     PENDING A DESIGNER. These are adopted as-is, not designed. They are here so the
     Console can stop carrying private copies and so there is a single thing to edit;
     the values themselves are the Console's current ones and are expected to change.
     Measurements are recorded beside each so the decision is informed rather than
     inherited. */
  /*
     The live/current INDICATOR — the dot in its halo, and the brand mark. Never
     decorative, never a fill.

     MEASURED 1.21:1 on white, which is below every bar there is. It works on the
     panel (4.82:1) and on ink (13.13:1); on the page ground it reads only because
     it is paired with the ring and, in a pill, with volt-ink. Recorded rather than
     silently corrected: darkening it would change the Console's appearance, which
     is a design decision and not a contrast fix.

     Note it is a SECOND lime beside --cg-secondary (#b6de68), 36 dE away. Which one
     the brand owns is the open question here.

     It is also a second LIVE. state.online (#00a05c) is the same idea in the state
     scale, and EntityStatus (#116) already paints the live dot with it. They are not
     interchangeable at any bar — online is 3.40:1 on white, volt is 1.21:1 — so a
     surface must not swap one for the other on the assumption that both mean
     'serving'. Which name the brand keeps for live belongs to the same open question,
     and until it is answered volt is the Console's brand mark and online is the
     entity's state. */
  --cg-volt: #b6ff2e;
  /*
     The halo behind a volt dot. Its job is to make the dot findable on a light ground, which is what carries the 1.21:1 above. */
  --cg-volt-ring: rgba(182, 255, 46, 0.32);
  /*
     Text and glyphs ON volt. 9.95:1 against it — the one part of the volt family that
     is comfortably legible.

     This is NOT the state -ink that EntityStatus (#116) says the library lacks. That
     note wants a foreground for the WORD on a state chip, and the arrangement it
     shipped instead — dot carries the colour, word is text-ink — already measures
     14.33:1 on online-fill, against 10.86:1 for this olive. volt-ink is tuned to volt
     and belongs to volt. Adding a state -ink is still a brand decision and still
     open. */
  --cg-volt-ink: #243d00;
  /*
     The wash behind a modal or overlay. Uses the BRAND ink (#222222) rather than the
     Console's (#16181d) — a scrim sits above content and belongs to the system, not
     to one surface's ink scale.

     Does NOT flip per surface, deliberately: it composites over whatever is beneath
     it, so a panel-scoped override would darken a scrim that is already dark. */
  --cg-scrim: rgba(34, 34, 34, 0.4);
  /*
     The wash under a hovered row or control. The system had no hover token; components were each inventing one. */
  --cg-hover: rgba(34, 34, 34, 0.045);
}

[data-cg-surface='panel'] {
  /* ---- semantic-text ---- */
  --cg-text-primary: #ffffff;
  --cg-text-secondary: rgba(255, 255, 255, 0.82);
  --cg-text-muted: rgba(255, 255, 255, 0.66);
  --cg-text-accent: #ffffff;

  /* ---- semantic-lines ---- */
  --cg-border-control: rgba(255, 255, 255, 0.62);
  --cg-border-hairline: rgba(255, 255, 255, 0.24);
  --cg-border-strong: #ffffff;
  --cg-focus-ring: rgba(255, 255, 255, 0.5);

  /* ---- link ---- */
  --cg-link: #ffffff;
  --cg-link-hover: var(--cg-secondary);

  /* ---- semantic-surfaces ---- */
  --cg-surface-card: transparent;

  /* ---- danger ---- */
  /*
     The source red measures 1.38:1 against this purple, which is invisible.
     Same class as #41. This tint is derived from it and measures 4.52:1, so it
     clears AA for body text as well as the 3:1 UI bar. */
  --cg-danger: #FFDAD6;

  /* ---- state ----
     state: the per-surface values for online/offline/expired. Same necessity as danger — measured, not assumed. pending is an alias of expired (#114), declared here so it flips rather than freezing to the base scope. unhealthy (#122) is a real value rather than an alias, and needs the same per-surface treatment for the same reason every other tone here does: its base gold is unreadable on this ground. */
  /*
     4.88:1 on the purple. The source green is 1.72:1 here — invisible, same class as the danger override. */
  --cg-online: #C8F5DC;
  /*
     4.11:1. A desaturated lavender so 'off' still recedes against the panel instead of reading as another state. */
  --cg-offline: #D9D4FB;
  /*
     4.68:1. The amber as a tint; the source value is 1.38:1 on this ground. */
  --cg-expired: #FFE2B8;
  /*
     Aliased to expired, which is 4.68:1 on the purple. Declared here as well as at :root because an alias is substituted where it is DECLARED — a :root-only pending would freeze to the white-surface amber and stop flipping, with no error. */
  --cg-pending: var(--cg-expired);
  /*
     4.41:1 on the purple, 3.27:1 on its own fill. The source gold is 1.09:1 on this ground — invisible, same class as the danger override.

     This is the surface that DECIDED the value. A dot on a panel chip has to clear 3:1 against rgba(255,255,255,0.16) over #5a47f0, whose relative luminance is 0.192; that forces the dot's own luminance above 0.677, i.e. Lab L >= 86, which is why every state value here is a near-white tint. Four already occupy that sliver at hues 29, 81, 159 and 297, and a fifth has to fit between them. The gold sits at hue 97, 20.0 from expired and 29.5 from online.

     It is louder than its four siblings, deliberately: a warning that recedes is not doing its job, and chroma is the only axis left once lightness is pinned by the contrast floor. */
  --cg-unhealthy: #F7E20C;
  /*
     Translucent white rather than a tint; the panel foreground measures 3.62:1 on it. */
  --cg-online-fill: rgba(255, 255, 255, 0.16);
  /*
     Translucent white rather than a tint; the panel foreground measures 3.47:1 on it. */
  --cg-expired-fill: rgba(255, 255, 255, 0.16);
  /*
     Aliased to expired-fill. Declared per scope for the same reason the foreground is. */
  --cg-pending-fill: var(--cg-expired-fill);
  /*
     Translucent white rather than a tint, like every other chip ground here; the panel foreground measures 4.33:1 on it. Written out rather than aliased to online-fill for the same reason the others are: four tokens that happen to share a value are not one token. */
  --cg-unhealthy-fill: rgba(255, 255, 255, 0.16);
  /*
     Translucent white rather than a tint; the panel foreground measures 3.35:1 on it. */
  --cg-danger-fill: rgba(255, 255, 255, 0.16);

  /* ---- indicator ----
     indicator + chrome: only hover flips. A dark wash is invisible on a dark ground. */
  /*
     Translucent white — the base wash is a dark ink and would not register on the panel ground. */
  --cg-hover: rgba(255, 255, 255, 0.10);
}

[data-cg-surface='ink'] {
  /* ---- semantic-text ---- */
  --cg-text-primary: #ffffff;
  --cg-text-secondary: rgba(255, 255, 255, 0.78);
  --cg-text-muted: rgba(255, 255, 255, 0.56);
  --cg-text-accent: var(--cg-secondary);

  /* ---- semantic-surfaces ---- */
  --cg-surface-card: rgba(255, 255, 255, 0.04);
  --cg-surface-page-alt: rgba(255, 255, 255, 0.06);

  /* ---- semantic-lines ---- */
  --cg-border-control: rgba(255, 255, 255, 0.4);
  --cg-border-hairline: rgba(255, 255, 255, 0.16);
  --cg-border-strong: #ffffff;
  --cg-border-accent: var(--cg-secondary);
  --cg-focus-ring: rgba(182, 222, 104, 0.45);

  /* ---- link ---- */
  --cg-link: #ffffff;
  --cg-link-hover: var(--cg-secondary);

  /* ---- danger ---- */
  /*
     Ink has more headroom than the panel, so this stays recognisably red rather
     than washing out to pink: 6.97:1 against #222, comfortably past AA for body
     text. The source red would have managed only 3.76:1 here. */
  --cg-danger: #FF8A80;

  /* ---- state ----
     state: the per-surface values for online/offline/expired. Same necessity as danger — measured, not assumed. pending is an alias of expired (#114), declared here so it flips rather than freezing to the base scope. unhealthy (#122) is a real value rather than an alias, and needs the same per-surface treatment for the same reason every other tone here does: its base gold is unreadable on this ground. */
  /*
     9.00:1 on #222. Ink has headroom, so this stays a recognisable green rather than washing to mint. */
  --cg-online: #5FD99A;
  /* 5.65:1. Still the quiet one, lifted just enough to read. */
  --cg-offline: #9A9A9A;
  /* 8.63:1. Keeps the amber legible without turning yellow. */
  --cg-expired: #F0B45E;
  /*
     Aliased to expired, which is 8.63:1 on #222. Declared here as well as at :root because an alias is substituted where it is DECLARED — a :root-only pending would freeze to the white-surface amber and stop flipping, with no error. */
  --cg-pending: var(--cg-expired);
  /*
     11.35:1 on #222, 8.88:1 on its own fill. Ink has headroom, so the gold stays a gold instead of washing to cream.

     This is the tightest the tone gets anywhere: 18.3 from expired, which is a new worst pair for this surface (was 25.3, offline/danger) while staying above the palette's global floor of 16.5. Recorded rather than tuned away — a light amber and a light gold have the least room on a dark ground, and the next 2 points of separation would walk into --cg-secondary (16.5 away) or --cg-volt (17.8). The pair that matters most is unaffected: 31.3 from online. */
  --cg-unhealthy: #F1DC03;
  /* Translucent white; the ink foreground measures 7.04:1 on it. */
  --cg-online-fill: rgba(255, 255, 255, 0.08);
  /* Translucent white; the ink foreground measures 6.76:1 on it. */
  --cg-expired-fill: rgba(255, 255, 255, 0.08);
  /*
     Aliased to expired-fill. Declared per scope for the same reason the foreground is. */
  --cg-pending-fill: var(--cg-expired-fill);
  /* Translucent white; the ink foreground measures 11.42:1 on it. */
  --cg-unhealthy-fill: rgba(255, 255, 255, 0.08);
  /* Translucent white; the ink foreground measures 5.45:1 on it. */
  --cg-danger-fill: rgba(255, 255, 255, 0.08);

  /* ---- indicator ----
     indicator + chrome: only hover flips. A dark wash is invisible on a dark ground. */
  /*
     Translucent white — the base wash is a dark ink and would not register on the ink ground. */
  --cg-hover: rgba(255, 255, 255, 0.06);
}
