/* GENERATED FILE -- DO NOT EDIT.
   Written by `php artisan syncoralis:design-tokens` from
   resources/design-system/tokens/, which is itself an imported copy of
   the Claude Design project. Edit neither this file nor that copy: change
   the design system, re-import, regenerate.

   Crossed:  colors.css, roles.css, semantic.css, radius-shadow.css, dark.css, fonts.css
   Excluded: typography.css, spacing.css, motion.css
             (see DesignTokenBundle for the reason per file -- each
             one is a different reason)

   input-hash: 69e3da484608138406874f2bf9126608522fdc2686566237aa830204627b2882

   That hash is over the FILES THIS WAS BUILT FROM, and it is the reason
   `--check` means anything. "The committed file matches a regeneration"
   only proves the generator agrees with itself; the hash is what ties
   this output to a specific input set. */

/* ===== colors.css ==================================================== */

/* Colour. The brand teal family and slate neutrals, FIXED by brand decision of
   31-08-2026. The ramp they sit on is Tailwind teal / Tailwind slate, which is
   what the Filament panels are configured with (Color::hex('#0D9488'),
   Color::Slate).

   The ramp is Tailwind v3, and that matters. Tailwind v4 recalculated the teal
   family in OKLCH: teal-950 is #022f2e there and #042f2e here, and the other
   steps moved with it. Going to v4 therefore shifts every step at once, so it is
   one migration and not a value you top up on its own.

   Do not add brand colours outside this file. */
:root {
  /* Teal -- platform brand */
  --teal-50: #f0fdfa;
  --teal-100: #ccfbf1;
  --teal-200: #99f6e4;
  --teal-300: #5eead4;
  --teal-400: #2dd4bf;
  --teal-500: #14b8a6;
  --teal-600: #0d9488;
  --teal-700: #0f766e;
  --teal-800: #115e59;
  --teal-900: #134e4a;
  --teal-950: #042f2e;

  /* Slate -- neutrals */
  --slate-50: #f8fafc;
  --slate-100: #f1f5f9;
  --slate-200: #e2e8f0;
  --slate-300: #cbd5e1;
  --slate-400: #94a3b8;
  --slate-500: #64748b;
  --slate-600: #475569;
  --slate-700: #334155;
  --slate-800: #1e293b;
  --slate-900: #0f172a;
  --slate-950: #020617;
  --white: #ffffff;

  /* Brand roles */
  --brand-primary: var(--teal-600);       /* app panel primary */
  --brand-primary-dark: var(--teal-700);  /* admin panel primary */
  --brand-ink: var(--slate-900);
  --brand-body: var(--slate-700);
  --brand-muted: var(--slate-500);
  --brand-line: var(--slate-200);
  --brand-background: var(--slate-50);

  /* Status colours, as the Filament panels use them */
  --success-50: #f0fdf4;
  --success-500: #22c55e;
  --success-600: #16a34a;
  --success-700: #15803d;
  --warning-50: #fffbeb;
  --warning-500: #f59e0b;
  --warning-600: #d97706;
  --warning-700: #b45309;
  --danger-50: #fef2f2;
  --danger-500: #ef4444;
  --danger-600: #dc2626;
  --danger-700: #b91c1c;
  /* Info has NO family here, on purpose (03-09-2026). A blue --info-50/500/600
     family used to sit on these lines beside roles.css saying --color-info is
     teal-700 (teal-300 in the dark): two sources for one colour. Measured:
     nothing in the panels, the views or the other token files referenced the
     blue values, everything referenced the role. The role is the source; the
     panels' info family is built from the teal family through it. */

  /* Synco, the mascot.
     The FIGURE's colours are the same in both modes -- that is the point, and it
     is why light mode gets ground tokens rather than a second palette. See
     guidelines/synco-placement.md, "Lichte grond". */
  --synco-dome-light: #1e6a82;
  --synco-dome-mid: #12455c;
  --synco-dome-dark: #0c2e41;
  --synco-arm-light: #13485f;
  --synco-arm-dark: #0d3348;
  --synco-arm-behind: #0e3547;
  --synco-coral-band: #2e7d74;
  --synco-ring: #eafffb;
  --synco-glow: var(--teal-300);
  --synco-iris: var(--teal-500);
  --synco-pupil: #071826;
  --synco-speech-surface: #0e1c2b;
  --synco-speech-border: rgba(94, 234, 212, 0.28);
  --synco-speech-subtitle: #8b9bb0;

  /* Light ground: the stage Synco stands on when the surface is light.

     THE PLATE IS A STAGE, NOT A CONTRAST MEASURE, and the note that used to
     stand here said the opposite -- that it "drops the figure's contrast
     against its immediate surround from about 12:1 to a workable range".
     MEASURED 05-09-2026 with Contrast::ratio(): the head mid-tone #12455c
     reads 9.91:1 on teal-50 and 10.34:1 on white. That is 0.43 of a point, so
     the plate changes essentially nothing about contrast and never did. What
     it does is give the dark figure a defined ground on a light page instead
     of letting it float, which is worth having and is a different claim.

     THE FIGURE KEEPS ITS COLOURS IN BOTH THEMES. That is the whole design of
     this block: only the plate, the ground shadow and the props are
     theme-aware, through data-synco-ground and data-synco-prop inside each
     pose. Without a stylesheet those two fall back to the dark values the
     drawing carries, which is the correct failure. */
  --synco-ground-light: var(--teal-50);
  /* 1px hairline. 1.21:1 on the plate: decorative, and named as such so
     nobody later reads it as a boundary that has to be perceivable. */
  --synco-ground-light-ring: var(--teal-200);
  --synco-ground-light-edge: rgba(13, 148, 136, 0.14);
  --synco-ground-light-shadow: 0 10px 24px -12px rgba(12, 46, 65, 0.35);
  --synco-ground-radius: 24px;
  /* The ellipse under the figure. The drawing carries #071824 at 75% for the
     dark theme; on a light plate that reads as a hole rather than a shadow. */
  --synco-ground-ellipse: rgba(15, 23, 42, 0.12);
  --synco-ground-dark: var(--surface-inverted-raised);

  /* Props: the line icons in the curl of a raised arm. teal-600 on the light
     plate is 3.59:1, over the 3:1 the new contrast norm sets for a
     non-textual element. The drawing's own #2DD4BF would be 1.78:1 there,
     which is why the prop is the one part of the figure that is theme-aware
     at all. */
  --synco-prop: var(--teal-600);

  /* Speech cloud on light ground: the design system's own card tokens. */
  --synco-speech-surface-light: var(--white);
  --synco-speech-border-light: var(--slate-200);
  --synco-speech-subtitle-light: var(--slate-500);
}


/* ===== roles.css ===================================================== */

/* Role tokens for state colour. Decided 31-08-2026; supersedes the "teal is a
   work choice" note in the project instructions for these roles only.

   Two rules govern this file.
   1. A token is named after its ROLE, never its value. `--color-primary` is the
      fill of a filled control; it is not "the brand teal". The brand teal stays
      teal-600 in the mark, the mascot ground and the badge tints -- it is simply
      not a surface that carries white text (3.74:1), so it is not this role.
   2. Every text colour ships with the surface it sits on, and that surface is
      derived from the same token with color-mix, so the pair cannot drift apart
      when the palette moves. Hover is likewise derived, never named twice.
   3. A HOVER MOVES AWAY FROM THE BACKGROUND, never towards it: darker on a light
      ground, lighter on a dark one. Hence 88% towards #000 in light and 86%
      towards #fff in dark -- one rule, two appearances. The reason is that the
      hover fill still has to carry its own text. A step towards the background
      shrinks the distance between fill and label, so the state a user is
      actively pointing at is the worst-contrasting state on the page. Filament
      derives light-mode hover the other way and lands the fill on 3.75:1; the
      token bridge passes this rule across explicitly rather than leaving the
      direction to the framework.

   All ratios below are measured, sRGB, WCAG 2.1. Light surfaces are measured
   against --surface-card (#ffffff), dark against --surface-page (#0a1120). */
:root {
  /* Primary: the fill of a filled control. teal-700, because teal-600 does not
     carry white (3.74:1) and moving to a darker step costs nothing the brand
     mark needs. */
  --color-primary: var(--teal-700);              /* white on it: 5.47:1 */
  --color-on-primary: var(--white);
  --color-primary-hover: color-mix(in srgb, var(--color-primary) 88%, #000);  /* #0d6861, white: 6.62:1 */
  --color-primary-active: color-mix(in srgb, var(--color-primary) 78%, #000);
  --color-primary-surface: color-mix(in srgb, var(--color-primary) 8%, var(--surface-card));
  --color-primary-quiet: var(--teal-800);        /* white on it: 7.58:1, for a fill on a tinted card */

  /* Error. Two values across the modes; no single red carries both grounds. */
  --color-error: #b91c1c;                        /* on white: 6.47:1 */
  --color-error-hover: #991b1b;                  /* red-800: one step darker than the role; white on it 8.31:1 */
  --color-error-surface: color-mix(in srgb, var(--color-error) 8%, var(--surface-card));
  --color-error-border: var(--color-error);      /* against white input: 6.47:1 */
  --color-on-error: var(--white);                /* on the filled danger button (danger-700) */

  /* Success. Genuinely new: the palette had no green in a text role. */
  --color-success: #166534;                      /* on white: 7.13:1 */
  --color-success-hover: #14532d;                /* green-900: one step darker than the role; white on it 9.11:1 */
  --color-success-surface: color-mix(in srgb, var(--color-success) 8%, var(--surface-card));

  /* Warning. Amber-800 rather than amber-700: 700 lands at 4.84:1 on its own
     tinted surface, which is a pass with no room in it. */
  --color-warning: #92400e;                      /* on white: 7.09:1 */
  --color-warning-hover: #78350f;                /* amber-900: one step darker than the role; white on it 9.07:1 */
  --color-warning-surface: color-mix(in srgb, var(--color-warning) 8%, var(--surface-card));

  /* Status "new": a product that has arrived from a connection and has never
     been edited in cultiva. A STATUS ROLE AND NOT A BRAND COLOUR -- the
     syncoralis palette is not settled and this invents no part of it; violet
     is here because "new" needed to be distinguishable from the three
     traffic-light states at a glance, and nothing in the teal/red/amber/green
     set is. Violet-600 and violet-400 are Tailwind v3, the same source the
     teal ramp and the -hover roles come from.

     MEASURED, sRGB, WCAG 2.1, and the reason there are two values: #7c3aed
     reads 5.45:1 on the light page and 5.70:1 on white, but only 3.05:1 on
     the dark card (#111a2b) and 3.31:1 on the dark page. As a 10px dot that
     is a pass against 1.4.11 with no room in it; as text it fails 1.4.3
     outright. The handoff design uses one value for both themes -- measured
     in the browser, all seven uses are the background of a small shape and
     none is a text colour -- so the design is not wrong, it is narrower than
     a token has to be. */
  --color-status-new: #7c3aed;                   /* on page 5.45:1, on card 5.70:1; white on it 5.70:1 */
  --color-status-new-surface: color-mix(in srgb, var(--color-status-new) 8%, var(--surface-card));

  /* Info / notice: allowed to come from the primary family, and does. */
  --color-info: var(--teal-700);                 /* on white: 5.47:1 */
  --color-info-hover: var(--teal-800);           /* one step darker, like --color-link-hover */
  --color-info-surface: color-mix(in srgb, var(--color-info) 8%, var(--surface-card));

  /* Link: points at an existing variant instead of inventing a blue. */
  --color-link: var(--teal-700);                 /* on white 5.47:1, on page 5.23:1 */
  --color-link-hover: var(--teal-800);
  /* THE -hover ROLES (03-09-2026): a filled status button needs a hover a
     step darker than its fill, and the status families end at the role --
     no token was darker, so the hover equalled the rest state. Measured as
     a missing token, not a wrong slot; the values are Tailwind v3 one step
     down from each role, the same source the families come from. */

  /* Focus. Two roles, because a ring beside a control and a ring on a filled
     control are measured against different things. */
  --color-focus: var(--teal-700);                /* beside a control: 5.47:1 on card, 5.23:1 on page */
  --color-focus-on-fill: var(--surface-card);    /* 2px gap ON the fill: 5.47:1 against teal-700 */

  /* Disabled. Judged as a DIFFERENCE from the active state, not as a ratio
     against the page: fill separates from the active fill by 1.23:1 and the
     value text drops from 17.85:1 to 2.08:1, a factor of 8.6. The border matches
     the fill, so the control also loses its edge. */
  --color-disabled-surface: var(--slate-200);    /* vs active white input: 1.23:1 */
  --color-disabled-border: var(--slate-200);
  --color-disabled-text: var(--slate-400);       /* on the disabled fill: 2.08:1 */
}

[data-theme="dark"], .dark {
  --color-primary: var(--teal-500);
  --color-on-primary: #04211f;                   /* ink on teal-500: 6.79:1 */
  --color-primary-hover: color-mix(in srgb, var(--color-primary) 86%, #fff);  /* #35c2b2, ink: 7.65:1 */
  --color-primary-active: color-mix(in srgb, var(--color-primary) 74%, #fff);
  --color-primary-surface: color-mix(in srgb, var(--color-primary) 14%, var(--surface-page));
  --color-primary-quiet: var(--teal-400);

  --color-error: #f87171;                        /* on page: 6.82:1, on card 6.29:1, on input 6.55:1 */
  --color-error-surface: color-mix(in srgb, var(--color-error) 14%, var(--surface-page));
  --color-error-border: var(--color-error);      /* against the dark input: 6.55:1 */
  --color-on-error: #250505;

  --color-success: #4ade80;                      /* on page: 10.82:1 */
  --color-success-surface: color-mix(in srgb, var(--color-success) 14%, var(--surface-page));

  --color-warning: #fcd34d;                      /* on page: 13.07:1 */
  --color-warning-surface: color-mix(in srgb, var(--color-warning) 14%, var(--surface-page));

  /* Violet-400 rather than violet-600, which lands at 3.05:1 on the card. The
     step matches the family: error is red-400 at 6.82:1 here, and this is
     6.93:1 on the page / 6.40:1 on the card -- so unlike the design's single
     value it clears 4.5:1 and may be used as text as well as a dot. */
  --color-status-new: #a78bfa;                   /* on page 6.93:1, on card 6.40:1 */
  --color-status-new-surface: color-mix(in srgb, var(--color-status-new) 14%, var(--surface-page));

  --color-info: var(--teal-300);                 /* on page: 12.74:1 */
  --color-info-surface: color-mix(in srgb, var(--color-info) 14%, var(--surface-page));

  --color-link: var(--teal-300);                 /* on page 12.74:1, on card 11.77:1 */
  --color-link-hover: var(--teal-200);

  --color-focus: var(--teal-400);                /* beside a control: 10.13:1 on page, 9.35:1 on card */
  --color-focus-on-fill: var(--surface-page);    /* gap ON the fill: 7.57:1 against teal-500 */

  --color-disabled-surface: #1e2a3d;             /* vs active dark input: 1.25:1 */
  --color-disabled-border: #1e2a3d;
  --color-disabled-text: var(--slate-500);       /* on the disabled fill: 3.04:1 */
}


/* ===== semantic.css ================================================== */

/* Semantic aliases. Components reference these, never the raw ramps. */
:root {
  /* Text */
  --text-heading: var(--slate-900);
  --text-body: var(--slate-700);
  --text-muted: var(--slate-500);
  --text-subtle: var(--slate-400);
  --text-on-primary: var(--white);
  --text-link: var(--teal-600);
  --text-link-hover: var(--teal-700);
  /*
    For a link that must carry weight on its own -- 14px, underlined, sitting in
    a sentence rather than in a row of controls. `--text-link` is teal-600, which
    is about 3.55:1 on white and therefore short for body-size text; teal-700 is
    4.86:1 and passes. The palette is fixed, so the answer is a second role, not
    a new colour.
  */
  --text-link-strong: var(--teal-700);

  /* Surfaces */
  --surface-page: var(--slate-50);
  --surface-card: var(--white);
  --surface-sidebar: var(--white);
  --surface-topbar: var(--white);
  --surface-raised: var(--white);
  --surface-input: var(--white);
  --surface-hover: var(--slate-50);
  --surface-active: var(--slate-100);
  --surface-disabled: var(--slate-100);
  --surface-selected: var(--teal-50);

  /* Borders */
  --border-line: var(--slate-200);
  /* A border that CARRIES MEANING, at 3:1 against its ground (WCAG 1.4.11,
     #452). --border-line is 1.23:1 on white and is meant to be that quiet, so a
     separation that says something structural, the outline of an empty or
     dotted area, a selection edge, borrows nothing from a text role any more.
     slate-500 reads 4.76:1 on white, 4.55:1 on --surface-page and 4.34:1 on
     --surface-active, the darkest ground it actually meets.
     The question that decides between the two: does meaning disappear if this
     border is invisible? */
  --border-emphasis: var(--slate-500);
  /* Rest border of a form control: 3:1 against its ground (WCAG 1.4.11, #601).
     slate-500 reads 4.76:1 on white and 4.55:1 on the page. Hover moves AWAY
     from the ground (roles.css rule 3): slate-600, 7.58:1 on white. */
  --border-input: var(--slate-500);
  --border-input-hover: var(--slate-600);
  --border-card: var(--ring-hairline);
  --border-focus: var(--teal-600);

  /* Controls */
  /* The primary button follows the primary ROLE, never a scale step (#736,
     Pim's decision of 25-09). It was teal-600, which carries white at 3.74:1 --
     under 4.5:1 for 14px button text -- while its hover sat exactly on the
     role's rest colour. Ratios computed, sRGB, WCAG 2.1: */
  --button-primary-bg: var(--color-primary);             /* teal-700, white on it: 5.47:1 */
  --button-primary-bg-hover: var(--color-primary-hover); /* #0d6861, white on it: 6.62:1 */
  --button-primary-text: var(--color-on-primary);
  --button-secondary-bg: var(--white);
  --button-secondary-text: var(--slate-700);
  --button-secondary-border: var(--slate-500);  /* 4.76:1 on white, 4.55:1 on the page (#601) */
  --button-ghost-text: var(--slate-500);
  --button-ghost-text-hover: var(--slate-700);
  --button-danger-bg: var(--danger-600);
  --button-danger-bg-hover: var(--danger-700);

  /* Navigation */
  --nav-item-text: var(--slate-700);
  --nav-item-text-hover: var(--teal-600);
  --nav-item-text-active: var(--teal-600);
  --nav-item-bg-hover: var(--slate-100);
  --nav-item-bg-active: var(--teal-50);
  --nav-group-label: var(--slate-500);

  /* Badges: text / background per status.
     The tint is DERIVED from the text colour it carries, the same way the status
     surfaces in tokens/roles.css are. color-mix against `transparent` keeps the
     translucency the hand-written rgba() literals had, so a badge still works on
     any surface -- but it can no longer drift away from its role. The previous
     values were Tailwind defaults and a hand-copied #0D9488, which sat beside the
     roles instead of following them. */
  --badge-neutral-text: var(--slate-700);
  --badge-neutral-bg: color-mix(in srgb, var(--text-muted) 10%, transparent);
  --badge-primary-text: var(--color-primary);
  --badge-primary-bg: color-mix(in srgb, var(--color-primary) 10%, transparent);
  --badge-success-text: var(--color-success);
  --badge-success-bg: color-mix(in srgb, var(--color-success) 10%, transparent);
  --badge-warning-text: var(--color-warning);
  --badge-warning-bg: color-mix(in srgb, var(--color-warning) 10%, transparent);
  --badge-danger-text: var(--color-error);
  --badge-danger-bg: color-mix(in srgb, var(--color-error) 10%, transparent);

  /* Inverted ground: a permanently dark block INSIDE a light page -- the ground
     Synco stands on, a brand strip, a code sample. These do not move with the
     theme and are not meant to: the dark STAND is tokens/dark.css, which
     redefines the ordinary aliases under [data-theme="dark"], .dark. If you are
     building the dark theme, read --text-body and --surface-page; they follow.
     Read one of the five below and you get a value that never will. */
  --surface-inverted: var(--slate-900);
  --surface-inverted-raised: var(--slate-800);
  --text-on-inverted-heading: var(--white);
  --text-on-inverted: var(--slate-400);
  --text-link-on-inverted: var(--teal-400);
}


/* ===== radius-shadow.css ============================================= */

/* Corners, borders, shadows. The panel look is flat: one hairline ring and a
   very small shadow on cards, no heavy elevation anywhere. */
:root {
  --radius-sm: 0.25rem;   /* 4  checkbox */
  --radius-md: 0.375rem;  /* 6  inputs, buttons */
  --radius-lg: 0.5rem;    /* 8  dropdowns, badges on large sizes */
  --radius-xl: 0.75rem;   /* 12 cards, sections, modals */
  --radius-2xl: 1rem;     /* 16 speech cloud (mascot) */
  --radius-full: 9999px;  /* badges, pills, avatars */

  --border-width: 1px;
  --ring-hairline: rgba(2, 6, 23, 0.05);   /* slate-950 / 5%  -- card ring */
  --ring-focus-width: 2px;

  --shadow-xs: 0 1px 2px 0 rgba(2, 6, 23, 0.05);
  --shadow-sm: 0 1px 3px 0 rgba(2, 6, 23, 0.08), 0 1px 2px -1px rgba(2, 6, 23, 0.06);
  --shadow-md: 0 4px 6px -1px rgba(2, 6, 23, 0.08), 0 2px 4px -2px rgba(2, 6, 23, 0.06);
  --shadow-lg: 0 10px 15px -3px rgba(2, 6, 23, 0.08), 0 4px 6px -4px rgba(2, 6, 23, 0.05);
  --shadow-dropdown: var(--shadow-lg);
  --shadow-modal: 0 25px 50px -12px rgba(2, 6, 23, 0.25);
}


/* ===== dark.css ====================================================== */

/* Dark theme -- the ground the panels are actually designed on (screenshots of
   app.syncoralis, 31-08-2026). Scoped twice: [data-theme="dark"] for pages in
   this system, and .dark because that is the class Filament's own theme switcher
   puts on the root element. Only the semantic aliases move; the ramps do not. */
[data-theme="dark"], .dark {
  --text-heading: var(--white);
  --text-body: var(--slate-300);
  --text-muted: var(--slate-400);
  --text-subtle: var(--slate-500);
  --text-link: var(--teal-400);
  --text-link-hover: var(--teal-300);
  --text-link-strong: var(--teal-300);

  --surface-page: #0a1120;
  --surface-card: #111a2b;
  --surface-sidebar: #0a1120;
  --surface-topbar: var(--slate-900);
  --surface-raised: #162033;
  --surface-input: #0d1626;
  --surface-hover: rgba(148, 163, 184, 0.08);
  --surface-active: rgba(148, 163, 184, 0.14);
  --surface-disabled: rgba(148, 163, 184, 0.12);
  --surface-selected: rgba(20, 184, 166, 0.12);

  --border-line: rgba(148, 163, 184, 0.16);
  /* A border that carries meaning at 3:1 (#452). slate-400 reads 6.36:1 on
     --surface-raised, the darkest ground it meets, 6.79:1 on the card and
     7.35:1 on the page. */
  --border-emphasis: var(--slate-400);
  /* Rest border of a form control at 3:1 (#601). slate-500 reads 3.66:1 on the
     card, 3.80:1 on --surface-input and 3.30:1 on Filament's white/5 field fill.
     Hover lighter, away from the ground: slate-400, 6.79:1 on the card. */
  --border-input: var(--slate-500);
  --border-input-hover: var(--slate-400);
  --border-card: rgba(148, 163, 184, 0.14);
  --border-focus: var(--teal-400);

  /* The role again (#736), restated here because a nested [data-theme] scope
     inherits the computed value from above and would keep the light one. */
  --button-primary-bg: var(--color-primary);             /* teal-500, ink #04211f on it: 6.79:1 */
  --button-primary-bg-hover: var(--color-primary-hover); /* #35c2b2, ink on it: 7.65:1 */
  --button-primary-text: var(--color-on-primary);
  --button-secondary-bg: rgba(148, 163, 184, 0.1);
  --button-secondary-text: var(--slate-200);
  --button-secondary-border: var(--slate-500);  /* 3.11:1 on its own fill over the card, 3.43:1 over the page (#601) */
  --button-ghost-text: var(--slate-400);
  --button-ghost-text-hover: var(--slate-200);

  --nav-item-text: var(--slate-300);
  --nav-item-text-hover: var(--teal-300);
  --nav-item-text-active: var(--teal-400);
  --nav-item-bg-hover: rgba(148, 163, 184, 0.08);
  --nav-item-bg-active: rgba(148, 163, 184, 0.14);
  --nav-group-label: var(--slate-400);

  /* Badge tints follow the roles here too, at 16% instead of 10% because a
     translucent tint needs more weight to read on a dark ground. */
  --badge-neutral-text: var(--slate-300);
  --badge-neutral-bg: color-mix(in srgb, var(--text-muted) 16%, transparent);
  --badge-primary-text: var(--teal-300);
  --badge-primary-bg: color-mix(in srgb, var(--color-primary) 16%, transparent);
  --badge-success-text: var(--color-success);
  --badge-success-bg: color-mix(in srgb, var(--color-success) 16%, transparent);
  --badge-warning-text: var(--color-warning);
  --badge-warning-bg: color-mix(in srgb, var(--color-warning) 16%, transparent);
  --badge-danger-text: var(--color-error);
  --badge-danger-bg: color-mix(in srgb, var(--color-error) 16%, transparent);

  --ring-hairline: rgba(148, 163, 184, 0.14);
  --shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.4);
  --shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.45);
  --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.55), 0 4px 6px -4px rgba(0, 0, 0, 0.4);
  --shadow-modal: 0 25px 50px -12px rgba(0, 0, 0, 0.7);

  /* Synco's ground. The FIGURE is unchanged here on purpose -- its colours are
     the same in both themes, which is the point of the mascot having a ground
     rather than a second palette. Only these three move.

     The plate and its ring go to `transparent` rather than being unset: the
     stage class paints them either way, and an unset custom property would
     inherit the light value instead of disappearing. On a dark page the page
     itself is the ground, so there is nothing to stand on top of. */
  --synco-ground-light: transparent;
  --synco-ground-light-ring: transparent;
  /* Back to what the drawing carries, so the ellipse reads as a shadow on a
     dark page rather than as the lighter smudge the light value would give. */
  --synco-ground-ellipse: rgba(7, 24, 36, 0.75);
  /* teal-400, the value the drawings are drawn with. Its light counterpart is
     teal-600, which is the darker one -- the prop moves because the ground
     under it moves, not because the figure does. */
  --synco-prop: var(--teal-400);
}


/* ===== fonts.css ===================================================== */

/* Manrope, served locally. Supplied by the brand on 31-08-2026 as TrueType and
   delivered as woff2 on 03-09-2026 (variable 200-800 plus four statics); the
   statics are the fallback for engines that ignore the variable font. No
   external font requests are made. Licence: assets/fonts/OFL.txt.
   LOCAL CHANGE AHEAD OF THE PROJECT: the project's copy still names TrueType files
   that were never delivered, and an ExtraBold static that does not exist. This
   copy names what is on disk; see README.md beside this file. */
@font-face {
  font-family: "Manrope";
  src: url("../../fonts/syncoralis/Manrope-VariableFont_wght.woff2") format("woff2");
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Manrope Static";
  src: url("../../fonts/syncoralis/Manrope-Regular.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Manrope Static";
  src: url("../../fonts/syncoralis/Manrope-Medium.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Manrope Static";
  src: url("../../fonts/syncoralis/Manrope-SemiBold.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Manrope Static";
  src: url("../../fonts/syncoralis/Manrope-Bold.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}
