/*! FinTruvix customer design system.
    ===========================================================================================================
    SOURCE OF TRUTH for the palette + base UI. Customer Blade uses var(--token) — never a hardcoded hex — so a
    palette change is a one-file edit. partials/theme.blade.php links this with a content-hash ?v=, so any edit
    busts the cache with no hard refresh. Filament (staff) theming is SEPARATE and must not be coupled to this.

    DESIGN LANGUAGE — derived from DESIGN.md (Apple analysis), with three other skills governing the rest:

      • DESIGN.md .................. visual language: palette, type scale, shape, elevation philosophy.
      • ui-ux-pro-max .............. page pattern (Marketplace / Directory), UX + accessibility rules, and the
                                     Laravel/Blade/Livewire stack rules.
      • Web Interface Guidelines ... the compliance gate (focus, motion, forms, typography, anti-patterns).
      • composition-patterns ....... component API design, translated from React to Blade components.

    WHERE THEY DISAGREED, AND WHY THIS RESOLVES IT THE WAY IT DOES:

      1. ui-ux-pro-max's colour search returned gold + purple on a dark canvas and listed "light mode default"
         as an anti-pattern. DESIGN.md mandates ONE accent (Action Blue) on a light-dominant canvas and forbids
         a second. DESIGN.md wins on palette — but note the two agree where it counts: ui-ux-pro-max's PRODUCT
         match for a two-sided marketplace says "Trust: Blue/Green" and "verified badge". The gold came from a
         generic style row, not from the product. Both modes still ship, because this app has a live toggle and
         removing it would be a regression; light is simply the default now.
      2. DESIGN.md lists dark-mode counterparts as a Known Gap. They are DERIVED here, against ui-ux-pro-max's
         dark-contrast rules (primary text >= 4.5:1, secondary >= 3:1, borders visible in BOTH themes).
      3. DESIGN.md's ink-48 (#7a7a7a) is 4.29:1 on white and 3.94:1 on parchment — below the 4.5:1 both
         ui-ux-pro-max and WCAG require. Fine print now uses #6e6e73 (Apple's own systemGray secondary label,
         4.66:1 on the worst light surface). #7a7a7a survives ONLY on disabled controls, which WCAG 1.4.3
         explicitly exempts. Being Apple-accurate is not worth shipping text people cannot read.

    THE ADAPTATION. Apple's system is photography-first: chrome recedes so the PRODUCT can speak, and the one
    shadow in the entire system exists to give a product render weight. FinTruvix has no product photography —
    it sells EVIDENCE: a Trust Score, a track record, a fee, a realised P&L. So the thesis is translated, not
    copied: THE NUMBER IS THE ARTIFACT. Figures get the display treatment, the tabular alignment and the single
    shadow; everything around them stays flat, hairline-bordered and quiet. That is the one deliberate risk in
    this system, and it comes from the brief rather than from decoration.
    =========================================================================================================== */

/* ================================ LIGHT — the default canvas ================================ */
:root {
    color-scheme: light;

    /* Surfaces. Parchment (#f5f5f7) is the signature Apple off-white: just different enough from
       white to create rhythm without a border. */
    --canvas: #ffffff;
    --canvas-alt: #f5f5f7;
    --surface: #ffffff;
    --surface-2: #fafafc;
    --surface-3: #f5f5f7;

    /* Dark bands. These are SECTION SURFACES, not a theme — they stay dark in both modes, because the
       alternation itself is the divider (DESIGN.md: "the color change IS the divider"). */
    --band-dark: #272729;
    --band-dark-2: #2a2a2c;
    --band-dark-3: #252527;
    --void: #000000;

    /* Text. One near-black for everything on light, exactly as Apple does — #1d1d1f rather than pure
       black keeps the page photographic rather than printed. */
    --text: #1d1d1f;
    --text-2: #333333;
    --text-muted: #6a6a6e;
    --text-faint: #6a6a6e;
    --text-disabled: #7a7a7a;   /* WCAG 1.4.3 exempts disabled controls — the ONLY place this is allowed */
    --on-dark: #ffffff;
    --on-dark-2: #cccccc;

    /* Hairlines. Apple has no card shadows; separation is a 1px line or a surface change.
       --hairline is DECORATIVE (a card edge) so it may be as light as Apple draws it. --field-border is
       not: WCAG 1.4.11 requires 3:1 for the boundary that identifies a form control, and Apple's own
       #c7c7cc is 1.68:1 on white. #86868b (3.62:1, still an Apple system grey) carries it instead. */
    --hairline: #e0e0e0;
    --divider-soft: #f0f0f0;
    --field-border: #86868b;

    /* THE SINGLE ACCENT — green. Every "click me" signal in the product is this and nothing else.
       Light gets the deep lime (#4d7c0f: 4.99:1 as text on white, 4.59:1 on parchment, and it carries
       white at 4.99:1 as a button fill). Dark gets the lemon (see the dark block) — the same brand at
       the brightness each ground needs, which is why --on-accent is a token rather than a constant.

       NOTE ON THE TWO GREENS. The brand lime sits at hue 86; the profit green (--up) sits at hue 148.
       They are deliberately a different family — yellow-green vs true green — because in a trading UI
       a green NUMBER means profit and a green CONTROL means "press this", and those must not read as
       the same statement. Colour is never the only signal either way: a P&L figure always carries its
       sign, and a control always looks like a control. */
    --accent: #4d7c0f;
    --accent-text: #49760e;
    --accent-focus: #3f6212;
    --on-accent: #ffffff;

    /* P&L. Apple's system has no up/down colours — a trading product cannot do without them, so these
       come from Apple's system green/red rather than an invented pair. Green is darkened from Apple's
       #248a3d, which is 4.04:1 on parchment: a P&L figure appears in small table cells as well as at
       display size, so it has to clear 4.5:1, not merely AA-large. Colour is NEVER the only signal —
       every figure carries a +/- sign (ui-ux-pro-max: "color is not the only indicator"). */
    --up: #0b7a3e;
    --down: #d70015;
    --warn: #ae4e00;
    /* Not a second accent. The P/I/T score trio reads as ONE family, so the Integrity meter — the only
       thing that ever used this — takes the brand hue like its two siblings. Kept as a name because
       several views refer to it by meaning rather than by colour. */
    --info: var(--accent);

    /* Status tints — flat washes, no borders doing decorative work. */
    --ok-text: #1a6b34; --ok-bg: #eaf6ee; --ok-border: #bfe3cb;
    --warn-text: #8a3d00; --warn-bg: #fdf0e6; --warn-border: #f3d5bb;
    --err-text: #b3000f; --err-bg: #fdecee; --err-border: #f5c6cb;

    --meter-track: #e8e8ed;
    --scrim: rgba(0, 0, 0, .48);

    /* ============================ LIQUID GLASS — the material ============================
       Glassmorphism is a PAINT: a tint plus a blur, which over flat ground reads as a slightly
       lighter rectangle. That version was built and rejected. Liquid Glass is a MATERIAL, so it is
       four properties rather than one fill, and all four are tokens so a layout consumes them in
       three declarations and the degradation below can switch the whole system off at the root.

         --glass*        the body tint, per nesting depth
         --glass-blur    what the material does to the ground behind it
         --glass-edge    THICKNESS: a lit top edge, a 1px ring, a shaded bottom edge
         --cast*         the material's own weight

       WHY THERE IS NO REFRACTION HERE, having shipped it in the study: `backdrop-filter: url(#f)`
       needs one SVG displacement map per element SIZE to bend at the rim rather than wobble
       everywhere, it is Chromium-only, and it re-runs a filtered backdrop sample on every scroll
       frame. On a dashboard of twenty cards that is a frame-budget decision, not a finish. The rim
       and the thickness are what carry the material at product scale; refraction is available for a
       single chosen hero surface if it is ever worth the cost.

       EVERY VALUE BELOW IS MEASURED, not chosen — see the contrast contract in the dark block. */
    --field: 6%;                                   /* strength of the ambient wash on --canvas */
    --glass:       color-mix(in srgb, #ffffff 72%, transparent);
    --glass-2:     color-mix(in srgb, #ffffff 84%, transparent);
    --glass-3:     color-mix(in srgb, #ffffff 90%, transparent);
    /* A FIXED overlay floats over content nothing constrains, so it takes the densest tint in the
       system: at 94% its link text measured 4.37:1 over a dark band, at 97% it measures 4.68:1
       against PURE BLACK. Transparency has no upside on a control that must always be readable. */
    --glass-dense: color-mix(in srgb, #ffffff 97%, transparent);

    --glass-blur:    saturate(170%) blur(18px);
    --glass-blur-lg: saturate(180%) blur(26px);

    /* The edge does two jobs at once: it bounds the pane AND catches the light at its top, which is
       what makes it read as a pane rather than a wash. Three insets, no gradient border, no extra
       DOM — so it can be applied to markup that already uses ::before/::after (the ledger spine,
       the trust ring, the row counter all do). */
    --rim-hi:   rgba(255, 255, 255, .85);
    --rim-ring: rgba(20, 23, 15, .10);
    --rim-lo:   rgba(20, 23, 15, .06);
    --glass-edge: inset 0 1px 0 var(--rim-hi), inset 0 0 0 1px var(--rim-ring), inset 0 -1px 0 var(--rim-lo);
    --glass-sheen: radial-gradient(132% 104% at 14% -20%, rgba(255, 255, 255, .55), transparent 58%);
    /* SPECULAR — the reflection that follows the cursor across a pane. Real glass catches the light
       source it is under; a static sheen alone reads as a printed highlight. Default position is far
       off the box so the layer is invisible until the pointer is actually over a pane.

       THE ALPHA IS A CEILING, NOT A TASTE. A white bloom ADDS white: on a light pane that only helps
       dark ink, but on a dark pane it lightens the ground under PALE ink. Measured on the worst dark
       pane (#1d2016), --text-muted fails at alpha 0.09 (4.41:1) and the ceiling is 0.06 — so dark
       ships 0.05 and its reflection is genuinely subtle. That is the mirror of the transparency
       asymmetry: dark tolerates more tint and LESS specular. */
    --spec-x: -9999px;   /* off the box, so the layer is invisible until a pointer arrives */
    --spec-y: -9999px;
    --spec-size: 340px;
    /* THE BLOOM IS A DIFFERENT COLOUR IN EACH THEME, and measurement forced that. On dark it is
       WHITE and brightens (+10.7 levels, clearly read). On light a white bloom has nowhere to go —
       the pane is already #f9faf7, and #fcfcfc -> #ffffff is at most +3 levels, below the ~2-3 level
       just-noticeable difference for a large smooth area, so it was invisible. Light therefore gets a
       faint LIME CAUSTIC that darkens slightly instead: -10.6 levels, brand-coherent, and reading as
       light bent through glass rather than as a grey smudge.
       Both are ceilings, not tastes: white on the worst dark pane fails --text-muted at .09 (ceiling
       .06, ships .05); lime on the worst light pane fails at .12 (ceiling .10, ships .06). */
    --spec-color: rgba(77, 124, 15, .06);

    /* NOTE, and it cost an hour: there is deliberately NO `--glass-spec` template token holding the
       whole gradient. A custom property's var() references are substituted WHERE IT IS DECLARED, not
       where it is used — so a `--glass-spec` declared on :root resolves its var(--spec-x) against
       :root ONCE (to -9999px) and inherits the already-substituted token stream down. The cursor
       position and the dark-chamber alpha override would both be invisible. Each pane rule therefore
       writes the gradient itself, and only the SCALARS travel as tokens. */


    --cast:    0 1px 2px rgba(20, 23, 15, .05), 0 10px 28px -10px rgba(20, 23, 15, .16);
    --cast-lg: 0 2px 6px rgba(20, 23, 15, .06), 0 20px 48px -14px rgba(20, 23, 15, .22);

    /* THE REDIRECTION. Every surface in the product paints from these three, so this is what carries
       the material into ~40 component classes across four layouts without touching one of them —
       and what lets the escape hatches at the foot of this file undo it globally. */
    --surface:   var(--glass);
    --surface-2: var(--glass-2);
    --surface-3: var(--glass-3);
    --hairline:  var(--rim-ring);
    /* The ground the panes sit on. It cannot be pure white: a white pane at 72% over a white ground
       is invisible, so the canvas steps back to a lime-biased off-white and the panes read lighter
       than it. */
    --canvas:     #F6F7F3;
    --canvas-alt: #EDEEE7;

    /* Shape (DESIGN.md rounded scale). No values between these — mixing radii grammars is called out
       explicitly in the Don'ts. */
    --r-none: 0px;
    --r-xs: 5px;
    --r-sm: 8px;
    --r-md: 11px;
    --r-lg: 18px;
    --r-pill: 9999px;

    /* Spacing — 8px base, with Apple's 17px body step. */
    --s-xxs: 4px; --s-xs: 8px; --s-sm: 12px; --s-md: 17px;
    --s-lg: 24px; --s-xl: 32px; --s-xxl: 48px; --s-section: 80px;

    --maxw: 1120px;
    --maxw-wide: 1440px;
    --maxw-read: 720px;

    /* Elevation. There is EXACTLY ONE shadow in this system and it belongs to the artifact — in Apple's
       original, a product render; here, the figure that carries the platform's claim. Never on chrome,
       cards, buttons or text. */
    --shadow-artifact: 0 6px 38px 4px rgba(0, 0, 0, .16);
    /* SOLID, not a 45%-alpha wash. WCAG 1.4.11 asks for 3:1 on the indicator that shows which control
       has focus, and mixing the accent down to 45% composited to 2.11:1 on white and 2.05:1 on
       parchment — the ring was legible enough to look designed and not legible enough to do its job.
       At full strength it is 6.50:1 on the worst light surface and 11.07:1 on the worst dark one. */
    --ring: 0 0 0 3px var(--accent-focus);

    --dur-fast: 150ms;
    --dur: 220ms;
    --ease: cubic-bezier(.4, 0, .2, 1);
}

/* ================================ DARK — derived counterpart ================================
   DESIGN.md documents the daytime system only; this is the derived night one. Every value was checked
   against the worst surface it can land on, not the most flattering. */
:root[data-theme="dark"] {
    color-scheme: dark;

    --canvas: #000000;
    --canvas-alt: #1d1d1f;
    --surface: #1d1d1f;
    --surface-2: #252527;
    --surface-3: #2a2a2c;

    --text: #f5f5f7;
    --text-2: #d2d2d7;
    /* #98989d, not Apple's #8e8e93 — the latter is 4.39:1 on the deepest raised surface (#2a2a2c). */
    --text-muted: #98989d;
    --text-faint: #98989d;
    --text-disabled: #636366;

    --hairline: #38383a;
    --divider-soft: #2a2a2c;
    --field-border: #828287;   /* 4.40:1 on the field fill — same 1.4.11 reasoning as light */

    /* The lemon set. A deep-lime fill would go muddy against near-black, so on dark the accent INVERTS:
       a bright fill carrying dark ink, which is the pairing this project shipped before and the reason
       --on-accent is a token. #C7EA46 is 10.43:1 on the deepest raised surface and carries #14210A at
       12.21:1, so the button is the most legible element on the page rather than the least. */
    --accent: #C7EA46;
    --accent-text: #C7EA46;
    /* Brighter than --accent, not darker. A hover has to CHANGE something: setting this equal to the
       base fill (the obvious-looking choice on an already-bright accent) silently removes hover
       feedback from every button in the product. #DCF57E is a visible step up and still carries the
       ink at 13.91:1. It also has to stay legible as the focus ring, which is derived from it. */
    --accent-focus: #DCF57E;
    --on-accent: #14210A;

    --up: #30d158;
    --down: #ff6961;   /* Apple's #ff453a is 4.20:1 on #2a2a2c; this is its lighter system variant */
    --warn: #ff9f0a;
    --info: var(--accent);

    --ok-text: #6ee7a8; --ok-bg: rgba(48, 209, 88, .14); --ok-border: rgba(48, 209, 88, .34);
    --warn-text: #ffcf70; --warn-bg: rgba(255, 159, 10, .14); --warn-border: rgba(255, 159, 10, .34);
    --err-text: #ff8a80; --err-bg: rgba(255, 69, 58, .14); --err-border: rgba(255, 69, 58, .34);

    --meter-track: #38383a;
    --scrim: rgba(0, 0, 0, .66);


    /* ---------------------------- LIQUID GLASS — night ----------------------------
       THE CONTRAST CONTRACT, measured worst-case (scratchpad/verify_site.py). A translucent pane's
       real background is whatever shows through, so every figure is the WORST composite the ambient
       field can produce, never the typical one:

         LIGHT  field 8% -> #e8ece2   pane #f9faf7 .. #fcfcfc
                body 16.03  secondary 12.03  fine print 4.83  link 4.76  profit 5.17  loss 5.13
                warn 4.95  field border 3.45          (floor for this field was 41% — 72% ships)
         DARK   field 10% -> #1f2311  pane #151713 .. #1d2016
                body 15.16  secondary 10.96  fine print 5.75  link 12.02  profit 8.17  loss 5.85
                warn 8.03   field border 4.32          (floor was 35% — 58% ships)

       So there is margin on both, deliberately: the floor is where a nested pane, a busier ground or
       a future darker accent would start failing. GLASS IS ASYMMETRIC between the themes — light
       tolerates mild frost, dark tolerates real glass — because on a light canvas the physics runs
       out of contrast first. That is a property of the material, not a compromise.

       The dark-band scope further down inverts the whole set: a LIGHT pane on the ledger's dark
       chamber composites to #c3c3c3 and takes link text to 2.82:1, a real failure in the SHIPPED
       DEFAULT theme. Inverted it measures 5.58:1. */
    --field: 10%;
    --glass:       color-mix(in srgb, #1C1E19 58%, transparent);
    --glass-2:     color-mix(in srgb, #23261F 70%, transparent);
    --glass-3:     color-mix(in srgb, #292C24 78%, transparent);
    --glass-dense: color-mix(in srgb, #1C1E19 96%, transparent);

    --glass-blur:    saturate(160%) blur(18px);
    --glass-blur-lg: saturate(170%) blur(26px);

    /* Inverted polarity: on dark the lit edge is a pale hairline and the shaded edge is near-black.
       Same two jobs, opposite sign — the --on-accent lesson applied to an edge. */
    --rim-hi:   rgba(255, 255, 255, .14);
    --rim-ring: rgba(255, 255, 255, .12);
    --rim-lo:   rgba(0, 0, 0, .45);
    --glass-edge: inset 0 1px 0 var(--rim-hi), inset 0 0 0 1px var(--rim-ring), inset 0 -1px 0 var(--rim-lo);
    --glass-sheen: radial-gradient(132% 104% at 14% -20%, rgba(255, 255, 255, .07), transparent 58%);
    --spec-color: rgba(255, 255, 255, .05);   /* ceiling .06 — see the light block */

    --cast:    0 1px 2px rgba(0, 0, 0, .40), 0 10px 30px -10px rgba(0, 0, 0, .55);
    --cast-lg: 0 2px 8px rgba(0, 0, 0, .45), 0 22px 54px -14px rgba(0, 0, 0, .62);

    --surface:   var(--glass);
    --surface-2: var(--glass-2);
    --surface-3: var(--glass-3);
    --hairline:  var(--rim-ring);
    --canvas:     #0C0D0B;
    --canvas-alt: #131510;

    --shadow-artifact: 0 8px 42px 5px rgba(0, 0, 0, .62);
}

/* ================================ LEGACY TOKEN BRIDGE ================================
   The previous system ("Lemon Green on Graphite") named its tokens differently, and 58 view files
   still reference those names. These aliases are the MIGRATION MECHANISM, not debt: they re-point
   every existing surface at the new language in one move, and — because they are the only definition
   of those names — they ENFORCE the new rules globally rather than file by file.

     • --grad-* collapse to a flat colour. DESIGN.md bans gradients outright, so every gradient in the
       codebase disappears here instead of needing 12 separate edits.
     • --shadow, --shadow-sm, --shadow-lg, --shadow-primary collapse to none. This system has ONE
       shadow and it belongs to the artifact; card shadows are the single loudest difference between
       the old look and this one.
     • --primary maps to --accent-text, not --accent. Of its 196 uses, 135 are text/border/icon and
       most of the rest are color-mix() tints that sit UNDER that same text — so the text-safe value
       is the correct one. The handful of solid fills that pair with --on-primary live in the layouts,
       which are rewritten to native tokens.

   As each surface is rewritten to native tokens its aliases stop being read. Delete a line here only
   once nothing references it. */
:root, :root[data-theme="dark"] {
    --primary: var(--accent-text);
    --primary-hover: var(--accent-focus);
    --on-primary: var(--on-accent);
    --bg: var(--canvas);
    --border: var(--hairline);
    --border-strong: var(--field-border);
    --gray-200: var(--hairline);
    --danger-600: var(--down);
    /* `--glass` and `--glass-border` were aliases here, and they are DELETED rather than repointed:
       nothing in the tree read either (checked), and this rule is later in source with
       :root[data-theme="dark"] in its selector list — so at (0,2,0) it silently outranked the real
       --glass defined in the dark token block above and reverted the whole night theme to an 82%
       tint of the canvas. The name now belongs to the material, not to the bridge. */

    --grad-primary: var(--accent);
    --grad-accent: var(--accent);
    --grad-hero: var(--canvas-alt);

    --shadow: none;
    --shadow-sm: none;
    --shadow-lg: none;
    --shadow-primary: none;

    --radius-sm: var(--r-xs);
    --radius: var(--r-sm);
    --radius-lg: var(--r-md);
    --radius-xl: var(--r-lg);
    --radius-pill: var(--r-pill);
}

/* ================================ BASE ================================ */

*, *::before, *::after { box-sizing: border-box; }

html {
    scroll-behavior: smooth;
    /* WIG: heading anchors need clearance under the sticky bar. */
    scroll-padding-top: 76px;
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    /* DESIGN.md's own first-choice substitute stack: on Apple platforms this resolves to the REAL SF Pro,
       and everywhere else to the platform UI face (Inter if present). Deliberately no webfont — a CDN
       request would add a third-party dependency, a preconnect and a CLS risk to a build-less stylesheet,
       and buy nothing on the platforms that matter most here. */
    font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, "Segoe UI", Roboto, Inter,
        "Helvetica Neue", Arial, sans-serif;
    /* Apple runs body at 17px, not 16 — the extra pixel is the brand's reading pace. */
    font-size: 17px;
    font-weight: 400;
    line-height: 1.47;
    letter-spacing: -.374px;
    /* THE AMBIENT FIELD. Frosted glass over flat colour is invisible — with nothing behind it to
       tint, a translucent pane reads as a slightly grubby opaque one, which is precisely how the
       glassmorphism attempt failed. So the ground carries a soft wash for the material to work
       against. Deliberately quiet (8% light / 10% dark): the sweep showed a STRONGER field forces a
       DENSER pane to stay readable, so loudness here is paid for in transparency there.
       `fixed` anchors it to the viewport — one paint, not one per scroll step — and the pools use
       ONLY the brand lime (hue 86); a page-wide wash in the profit hue would make the whole product
       read as "up". */
    background-color: var(--canvas);
    background-image:
        radial-gradient(62% 46% at 4% 0%,   color-mix(in srgb, var(--accent) var(--field), transparent) 0%, transparent 68%),
        radial-gradient(52% 40% at 98% 6%,  color-mix(in srgb, var(--accent) calc(var(--field) * .60), transparent) 0%, transparent 66%),
        radial-gradient(74% 54% at 84% 98%, color-mix(in srgb, var(--accent) calc(var(--field) * .48), transparent) 0%, transparent 70%);
    background-attachment: fixed;
    background-repeat: no-repeat;
    color: var(--text);
    min-height: 100vh;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

/* WIG: prevents the 300ms double-tap zoom delay on touch. */
a, button, [role="button"], input, select, textarea, summary, label { touch-action: manipulation; }

a { color: var(--accent-text); text-decoration: none; }
a:hover { text-decoration: underline; }
/* WIG: :focus-visible, never :focus — no ring on a mouse click. */
a:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--r-xs); }

::selection { background: color-mix(in srgb, var(--accent) 22%, transparent); }

img, svg, video { max-width: 100%; }
img { height: auto; }

/* Display type. Apple's signature is weight 600 with NEGATIVE tracking — never 700, never 500
   (its ladder is 300/400/600/700 with 500 deliberately absent). */
h1, h2, h3, h4, h5, h6 {
    font-weight: 600;
    /* WIG: prevents widows on headings. */
    text-wrap: balance;
    margin: 0 0 var(--s-sm);
}
h1 { font-size: clamp(34px, 5vw, 56px); line-height: 1.07; letter-spacing: -.02em; }
h2 { font-size: clamp(28px, 3.4vw, 40px); line-height: 1.10; letter-spacing: -.015em; }
h3 { font-size: 24px; line-height: 1.2; letter-spacing: -.01em; }
h4 { font-size: 21px; line-height: 1.19; letter-spacing: -.008em; }
p { margin: 0 0 var(--s-md); }
strong, b { font-weight: 600; }

/* Every figure in the product is tabular — a column of scores or prices must align on the decimal.
   WIG asks for this on number columns; here it is the house style, because the number is the artifact. */
.num, .fig, td.num, th.num { font-variant-numeric: tabular-nums; }

code, kbd {
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
    font-size: .88em;
    background: var(--surface-3);
    padding: 2px 6px;
    border-radius: var(--r-xs);
}

hr { border: 0; border-top: 1px solid var(--hairline); margin: var(--s-xl) 0; }

summary { list-style: none; cursor: pointer; }
summary::-webkit-details-marker { display: none; }

/* Screen-reader-only, and the skip link WIG requires for keyboard users. */
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
    position: absolute; left: var(--s-sm); top: -100px; z-index: 200;
    padding: 10px 18px; border-radius: var(--r-sm);
    background: var(--accent); color: var(--on-accent); font-size: 14px; font-weight: 600;
    transition: top var(--dur-fast) var(--ease);
}
.skip-link:focus { top: var(--s-sm); text-decoration: none; }

/* ================================ TYPE UTILITIES ================================ */

.eyebrow, .kicker, .eyebrow-inline {
    display: block;
    font-size: 12px; font-weight: 600; line-height: 1;
    letter-spacing: .06em; text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: var(--s-sm);
}
.lead { font-size: clamp(19px, 2vw, 28px); font-weight: 400; line-height: 1.28; letter-spacing: 0; color: var(--text-2); }
.lead-airy { font-size: clamp(18px, 1.8vw, 24px); font-weight: 300; line-height: 1.5; letter-spacing: 0; color: var(--text-2); }
.tagline { font-size: 21px; font-weight: 600; line-height: 1.19; letter-spacing: -.008em; }
.muted { color: var(--text-muted); font-size: 15px; line-height: 1.47; }
.fine { font-size: 12px; line-height: 1.4; color: var(--text-muted); }
.legal { font-size: 12px; line-height: 1.5; color: var(--text-muted); }
.measure { max-width: var(--maxw-read); }

/* ================================ BANDS — the section rhythm ================================
   Apple's page is a stack of full-bleed tiles where the SURFACE CHANGE is the divider: no borders, no
   shadows, no decorative rules between sections. `.band` is that unit. Never round it — tiles are
   rectangular and touch edge to edge. */
.band {
    padding: var(--s-section) var(--s-lg);
    /* Transparent, not --canvas: an opaque section would cover the ambient field it exists to show.
       The alternation that used to be this element's job is now carried by the panes themselves —
       every entry is a card with its own lit edge, which is a stronger divider than a tone change. */
    background: transparent;
    color: var(--text);
}
.band--alt { background: color-mix(in srgb, var(--canvas-alt) 62%, transparent); }
.band--dark { background: var(--band-dark); color: var(--on-dark); }
.band--dark-2 { background: var(--band-dark-2); color: var(--on-dark); }
.band--dark-3 { background: var(--band-dark-3); color: var(--on-dark); }
.band--void { background: var(--void); color: var(--on-dark); }
.band--tight { padding-top: var(--s-xxl); padding-bottom: var(--s-xxl); }

/* Inside a permanently-dark tile the whole token set inverts — text ladder, accent, hairline, field
   border and the P&L pair — because the tile is dark in BOTH themes and would otherwise inherit the
   light theme's values on the shipped default. `.led--dark` (the marketing ledger's dark entries) is
   in this list for exactly that reason: without it the row key rendered at 2.94:1. Any NEW
   permanently-dark surface class must be added here too. */
.band--dark, .band--dark-2, .band--dark-3, .band--void, .led--dark { --text: var(--on-dark); --text-2: var(--on-dark-2); --text-muted: #a1a1a6; --text-faint: #a1a1a6; --accent: #C7EA46; --accent-text: #C7EA46; --accent-focus: #DCF57E; --on-accent: #14210A; --hairline: #3a3a3c; --surface: #2f2f31; --surface-2: #333335; --surface-3: #333335; --meter-track: #3a3a3c; --field-border: #858589; --up: #30d158; --down: #ff6961;
    --glass: color-mix(in srgb, #1C1E19 58%, transparent); --glass-2: color-mix(in srgb, #23261F 70%, transparent);
    --glass-3: color-mix(in srgb, #292C24 78%, transparent); --glass-dense: color-mix(in srgb, #1C1E19 96%, transparent);
    --rim-hi: rgba(255, 255, 255, .14); --rim-ring: rgba(255, 255, 255, .12); --rim-lo: rgba(0, 0, 0, .45);
    --glass-sheen: radial-gradient(132% 104% at 14% -20%, rgba(255, 255, 255, .07), transparent 58%);
    --spec-color: rgba(255, 255, 255, .05);
    --surface: var(--glass); --surface-2: var(--glass-2); --surface-3: var(--glass-3);
    --ok-text: #6ee7a8; --ok-bg: rgba(48, 209, 88, .16); --ok-border: rgba(48, 209, 88, .34);
    --warn-text: #ffcf70; --warn-bg: rgba(255, 159, 10, .16); --warn-border: rgba(255, 159, 10, .34);
    --err-text: #ff8a80; --err-bg: rgba(255, 69, 58, .16); --err-border: rgba(255, 69, 58, .34); }

/* `.band-inner` is accepted as a synonym of `.band__inner` — the marketing pages already use it. */
.band__inner, .band-inner { max-width: var(--maxw); margin: 0 auto; }
.band__inner--wide { max-width: var(--maxw-wide); }
.band__inner--read { max-width: var(--maxw-read); }
.band__inner--center, .band--center { text-align: center; }

@media (max-width: 640px) {
    .band { padding: var(--s-xxl) var(--s-md); }
}

/* ================================ BUTTONS ================================
   Two grammars and no others: a PILL for actions (the pill radius IS the action signal), and a compact
   RECT for utility chrome. Press state is transform: scale(.95) everywhere — the system-wide
   micro-interaction. No shadows, no gradients. */

button, .btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    padding: 11px 22px;
    border: 1px solid transparent;
    border-radius: var(--r-pill);
    background: var(--accent);
    color: var(--on-accent);
    font-family: inherit; font-size: 17px; font-weight: 400; line-height: 1.2;
    letter-spacing: -.374px;
    text-align: center; text-decoration: none; cursor: pointer;
    /* WIG: never `transition: all` — list the properties. */
    transition: transform var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease),
        border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
button:hover, .btn:hover { background: var(--accent-focus); color: var(--on-accent); text-decoration: none; }
button:active, .btn:active { transform: scale(.95); }
button:focus-visible, .btn:focus-visible { outline: none; box-shadow: var(--ring); }
button:disabled, .btn:disabled, button[aria-disabled="true"] {
    background: var(--surface-3); color: var(--text-disabled);
    cursor: not-allowed; transform: none;
}

/* Ghost pill — the second CTA when two sit together ("Learn more" beside "Buy"). */
button.secondary, .btn.secondary {
    background: transparent; color: var(--accent-text); border-color: currentColor;
}
button.secondary:hover, .btn.secondary:hover { background: color-mix(in srgb, var(--accent) 8%, transparent); color: var(--accent-text); }

/* Quiet text action. */
button.ghost, .btn.ghost {
    background: transparent; color: var(--text-2); border-color: transparent; font-weight: 400;
}
button.ghost:hover, .btn.ghost:hover { background: var(--surface-3); color: var(--text); }

/* A submit that has to read as a LINK, not an action. Some state changes cannot honestly be an anchor — a
   GET that mutates is prefetchable, so "clear my cookie choice" has to be a POST — but it belongs among the
   links around it rather than wearing the accent pill. A FULL reset, because the bare `button` selector
   above is global and aggressive; inheriting font and colour is what makes it disappear into its context. */
button.linklike {
    display: inline; width: auto; padding: 0; gap: 0;
    background: none; border: 0; border-radius: 0; box-shadow: none; transform: none;
    color: inherit; font: inherit; letter-spacing: inherit; text-align: left; text-decoration: none;
    cursor: pointer;
}
button.linklike:hover { background: none; text-decoration: underline; }
button.linklike:active { transform: none; }
button.linklike:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--r-xs); }

/* Utility rect — nav actions, table row actions. 8px radius, never a pill: the pill means "action". */
button.mini, .btn.mini, button.util, .btn.util {
    padding: 8px 15px; font-size: 14px; line-height: 1.29; letter-spacing: -.224px;
    border-radius: var(--r-sm);
    background: var(--surface-2); color: var(--text); border-color: var(--hairline);
}
button.mini:hover, .btn.mini:hover, button.util:hover, .btn.util:hover {
    background: var(--surface-3); color: var(--text); border-color: var(--field-border);
}
button.small, .btn.small { padding: 9px 18px; font-size: 15px; }
button.large, .btn.large { padding: 14px 28px; font-size: 18px; font-weight: 300; }

button.link, .btn.link {
    background: none; border: 0; padding: 0; color: var(--accent-text); font-size: inherit;
}
button.link:hover, .btn.link:hover { background: none; color: var(--accent-text); text-decoration: underline; }

button.danger, .btn.danger { background: var(--down); color: #ffffff; }
button.danger:hover, .btn.danger:hover { background: var(--down); filter: brightness(.92); }

/* Icon-only control. 44x44 exactly — the platform minimum, and what ui-ux-pro-max requires for touch.
   Every one of these needs an aria-label; a bare icon button has no accessible name. */
.icon-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; padding: 0;
    border-radius: var(--r-pill);
    background: transparent; color: var(--text-2); border: 1px solid transparent;
}
.icon-btn:hover { background: var(--surface-3); color: var(--text); }
.icon-btn:active { transform: scale(.95); }
.icon-btn:focus-visible { outline: none; box-shadow: var(--ring); }
.icon-btn svg { width: 20px; height: 20px; display: block; }

/* Theme toggle. The icon shows the state you are ABOUT TO ENTER, which is the convention people read
   fastest: on light you see a moon ("go dark"), on dark a sun. Both glyphs ship and CSS picks one, so
   the swap costs no JS and cannot desync from the attribute that drives the palette. */
.icon-btn .i-sun { display: none; }
:root[data-theme="dark"] .icon-btn .i-moon { display: none; }
:root[data-theme="dark"] .icon-btn .i-sun { display: block; }

/* ================================ FORMS ================================
   ONE FIELD RADIUS: every data-entry control is var(--r-md), full stop. Anything a person types into,
   picks from, or drops a file onto shares the same corner — a single-line input, a textarea, a native
   select, the searchable combobox, the file drop zone and the read-only boxes that imitate a field.
   No pills, no card radius, no off-ladder literals. A form is read as one column, so a control that
   disagrees with the one above it reads as broken rather than as emphasis, and every deviation this
   system shipped was eventually reported as a defect: a pill search box beside an 11px select, an 8px
   textarea under an 11px input, an 18px file drop among 11px fields.

   The radius is therefore NOT a per-control decision. If a new control needs to stand out, it does so
   with the accent, the label or its position — never by changing its corners.

   ENUMERATE EVERY TYPE. This selector list is an allow-list, and a type missing from it gets no radius,
   no border and no padding — it renders as a raw browser control among styled ones, which is worse than
   a mismatched radius and is invisible until someone opens that one page. `datetime-local` (the signal
   publish form's "Expires at") was missing and rendered bare among four styled number inputs.
   Adding a new input type to a Blade view means adding it here.

   `file` is deliberately NOT in this list and is styled separately down in FILE DROP. An attribute
   selector is (0,1,1) and a class is (0,1,0), so `input[type="file"]` here would OUT-SPECIFY
   `.filedrop-native` — the visually-hidden real input behind every <x-file-drop> — and hand it back
   width:100%, padding and a border. Source order would not save it; specificity wins.

   Labels are always visible — a placeholder is not a label, and ui-ux-pro-max flags placeholder-only
   as an anti-pattern. */

input[type="text"], input[type="email"], input[type="password"], input[type="number"], input[type="date"],
input[type="search"], input[type="tel"], input[type="url"], input[type="datetime-local"],
input[type="time"], input[type="month"], input[type="week"], select, textarea {
    width: 100%;
    padding: 12px 16px;
    border: 1px solid var(--field-border);
    border-radius: var(--r-md);
    background: var(--surface);
    color: var(--text);
    font-family: inherit; font-size: 17px; line-height: 1.4; letter-spacing: -.374px;
    transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
/* Multi-line is still a field: same corner as the single-line input it sits under. Only the height
   and the resize affordance differ. */
textarea { min-height: 96px; resize: vertical; }
input::placeholder, textarea::placeholder { color: var(--text-muted); opacity: 1; }
input:focus-visible, select:focus-visible, textarea:focus-visible {
    outline: none; border-color: var(--accent-focus); box-shadow: var(--ring);
}
input[aria-invalid="true"], select[aria-invalid="true"], textarea[aria-invalid="true"] { border-color: var(--down); }
input:disabled, select:disabled, textarea:disabled {
    background: var(--surface-3); color: var(--text-disabled); cursor: not-allowed;
}

/* Native select needs explicit colours or Windows dark mode paints it black-on-black (WIG). */
select {
    -webkit-appearance: none; -moz-appearance: none; appearance: none;
    padding-right: 40px;
    background-color: var(--surface);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%236e6e73' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 14px center; background-size: 11px 8px;
}
:root[data-theme="dark"] select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%2398989d' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
select option { background: var(--surface); color: var(--text); }

.field { margin: 0 0 var(--s-lg); max-width: 460px; }
.field > label, .label {
    display: block;
    font-size: 14px; font-weight: 600; line-height: 1.29; letter-spacing: -.224px;
    color: var(--text); margin: 0 0 7px;
}
.field--wide { max-width: none; }
.req { color: var(--down); margin-left: 2px; }
.hint { display: block; font-size: 13px; line-height: 1.45; color: var(--text-muted); margin-top: 6px; }
.err { display: block; font-size: 13px; line-height: 1.45; color: var(--err-text); margin-top: 6px; font-weight: 500; }
.check { display: flex; gap: 10px; align-items: flex-start; font-size: 15px; color: var(--text-2); cursor: pointer; }
.check input[type="checkbox"], .check input[type="radio"] { width: 18px; height: 18px; margin: 2px 0 0; accent-color: var(--accent); flex-shrink: 0; }
.form-actions { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin-top: var(--s-lg); }
.opts { display: inline-flex; gap: 10px; align-items: center; flex-wrap: wrap; }

/* A FIELD AND ITS INLINE ACTION, on one line — the "readonly link + Copy" row, a search box with a
   button, a value with an Apply. This exists because the pattern was hand-rolled four times with
   `style="display:flex;gap:8px"` and drifted into three different button variants (.ghost, .secondary
   .small, .mini), so the same row shipped with a pill at one end and an 11px field at the other in
   three places.

   THE RULE: a button that shares a ROW with a field takes the FIELD radius, not the pill. The pill is
   the action signal and it is right for a standalone CTA sitting on its own; hard against a field at an
   8px gap it just reads as two shapes that failed to line up. This narrows the button grammar in one
   specific context rather than weakening it — .form-actions below a form is untouched, and every
   standalone button in the product is still a pill.

   Placed after the button rules on purpose: `.input-row > button` and `button.mini` are both (0,1,1),
   so ORDER is what makes this win. Moving it above BUTTONS silently stops it working. */
.input-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.input-row > input, .input-row > select { flex: 1; min-width: 220px; width: auto; }
.input-row > button, .input-row > .btn,
.ft-share__link > button, .ft-share__link > .btn { border-radius: var(--r-md); flex-shrink: 0; }

/* Password reveal. */
.pw-field { position: relative; }
.pw-field > input { padding-right: 48px; }
.pw-toggle {
    position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
    width: 36px; height: 36px; padding: 0; border: 0; border-radius: var(--r-sm);
    background: none; color: var(--text-muted);
    display: inline-flex; align-items: center; justify-content: center;
}
.pw-toggle:hover { background: var(--surface-3); color: var(--text); transform: translateY(-50%); }
.pw-toggle:active { transform: translateY(-50%) scale(.95); }
.pw-toggle:focus-visible { outline: none; box-shadow: var(--ring); }
.pw-toggle svg { width: 18px; height: 18px; }
.pw-toggle .eye-off { display: none; }
.pw-field.show .pw-toggle .eye { display: none; }
.pw-field.show .pw-toggle .eye-off { display: inline; }

/* ================================ MESSAGES ================================
   Flat washes with a hairline. No shadow, no gradient. Each carries a role so assistive tech announces
   it (WIG: async updates need aria-live; the markup supplies role="status" / role="alert"). */
.status, .banner, .errors {
    padding: 14px 17px;
    border: 1px solid var(--hairline);
    border-radius: var(--r-md);
    background: var(--surface-2);
    color: var(--text-2);
    font-size: 15px; line-height: 1.47;
    margin: 0 0 var(--s-md);
}
.status, .banner.ok { background: var(--ok-bg); border-color: var(--ok-border); color: var(--ok-text); }
.banner { background: var(--warn-bg); border-color: var(--warn-border); color: var(--warn-text); }
.banner.info { background: var(--surface-2); border-color: var(--hairline); color: var(--text-2); }
.errors { background: var(--err-bg); border-color: var(--err-border); color: var(--err-text); }
.errors ul { margin: 0; padding-left: 20px; }

/* ================================ THE RISK CAVEAT ================================
   partials/risk-note is included from BOTH marketing and public layouts, so its baseline lives here
   rather than in either one. It reads as what it is — a footnote set off from the page above it, at
   fine-print size, on a measure short enough to scan.

   The ledger variant BELOW used to live in layouts/marketing.blade.php, and keeping it there was a
   bug rather than a style choice. Livewire's wire:navigate MERGES the <head> and leaves the previous
   page's inline <style> in place, so following the header's Contact link from the marketing home page
   left the marketing rules applying to a layouts.public page: measured in a real browser, the caveat
   went from padding-left 0 + a top rule to padding-left 129px + a ::before left spine, so the small
   print sat 129px out of alignment with every other line on /contact while a direct page load looked
   correct. A variant of a SHARED partial therefore has to be a MODIFIER ON THE PARTIAL, defined once
   here, opted into at the call site — never an override in a layout, which can only be as reliable as
   whichever stylesheet happened to survive the last client-side navigation. */
.risk-note {
    margin: var(--s-xxl) 0 0;
    padding-top: var(--s-md);
    border-top: 1px solid var(--hairline);
}
.risk-note p {
    margin: 0; max-width: 78ch;
    font-size: 12px; line-height: 1.5; color: var(--text-muted);
}

/* Ledger variant — opted into by passing ftRiskLedger => true to the partial. The marketing pages
   hang every entry off one continuous spine, so there the small print JOINS the spine instead of
   visibly stopping it, and the top rule is dropped because the spine already does that work.
   Both selectors are a single class, so this block MUST stay after the baseline to win the tie.

   The rail/gutter geometry is deliberately identical to `main > section.led` in layouts/marketing —
   the caveat has to line up with the ledger rows above it. Change one and change the other; there is
   no shared token for it, because the spine belongs to that layout and this is its one guest. */
.risk-note--ledger {
    --rail: clamp(44px, 6vw, 84px);
    --gut: max(var(--s-md), calc((100% - 1180px) / 2));
    position: relative; margin: 0; border-top: 0;
    padding: var(--s-lg) var(--gut) var(--s-lg)
             calc(var(--gut) + var(--rail) + clamp(12px, 2vw, 28px));
}
.risk-note--ledger::before {
    content: ""; position: absolute; top: 0; bottom: 0;
    left: calc(var(--gut) + var(--rail) - 1px); width: 1px; background: var(--hairline);
}
@media (max-width: 640px) {
    .risk-note--ledger { --rail: 0px; padding-left: calc(var(--gut) + 14px); }
    .risk-note--ledger::before { left: var(--gut); }
}

/* ================================ BADGES ================================ */
.badge {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 4px 11px;
    border-radius: var(--r-pill);
    border: 1px solid var(--hairline);
    background: var(--surface-2);
    color: var(--text-2);
    font-size: 12px; font-weight: 600; line-height: 1.4; letter-spacing: -.06px;
    white-space: nowrap;
}
.badge.ok { background: var(--ok-bg); border-color: var(--ok-border); color: var(--ok-text); }
.badge.warn { background: var(--warn-bg); border-color: var(--warn-border); color: var(--warn-text); }
.badge.down { background: var(--err-bg); border-color: var(--err-border); color: var(--err-text); }
.badge.accent { background: color-mix(in srgb, var(--accent) 10%, transparent); border-color: color-mix(in srgb, var(--accent) 30%, transparent); color: var(--accent-text); }

/* ================================ SURFACES ================================
   A card is a hairline and a radius. Never a shadow — elevation in this system comes from a surface
   change, and the one shadow that exists is reserved for the artifact. */
.card, .panel {
    background: var(--surface);
    border: 1px solid var(--hairline);
    border-radius: var(--r-lg);
    padding: var(--s-lg);
}
.panel { margin: 0 0 var(--s-lg); }
.panel > h2:first-child, .card > h2:first-child, .panel > h3:first-child, .card > h3:first-child { margin-top: 0; }

/* The one shadow. Reserved for the figure that carries the claim — a Trust Score, a passport
   credential, a headline P&L. If it is used anywhere else, that is a bug. */
.artifact { box-shadow: var(--shadow-artifact); }

/* ================================ THE FIGURE ================================
   The centrepiece of the adaptation: where Apple gives a product render the display treatment, this
   gives it to a number. */
.figure {
    display: block;
    font-size: clamp(40px, 6vw, 56px);
    font-weight: 600; line-height: 1.07; letter-spacing: -.02em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}
.figure--md { font-size: clamp(28px, 3.4vw, 40px); line-height: 1.1; }
.figure--sm { font-size: 24px; line-height: 1.2; }
.figure__unit { font-size: .42em; font-weight: 400; color: var(--text-muted); letter-spacing: 0; margin-left: 3px; }
.figure__label {
    display: block; margin-top: 8px;
    font-size: 12px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
    color: var(--text-muted);
}
.figure--up { color: var(--up); }
.figure--down { color: var(--down); }
/* Colour is never the only signal — the sign is part of the value (ui-ux-pro-max). */
.figure--na { color: var(--text-muted); }

/* Meter — a quiet track with a solid fill. No gradient. */
.meter { height: 4px; border-radius: var(--r-pill); background: var(--meter-track); overflow: hidden; margin-top: 12px; }
.meter > span { display: block; height: 100%; border-radius: var(--r-pill); background: var(--accent); }
.meter > span.up { background: var(--up); }
.meter > span.neutral { background: var(--text-muted); }

/* ================================ TABLES ================================
   Wide tables scroll INSIDE their own container at every width — a table never scrolls the page. */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; overscroll-behavior-x: contain; }
table.list {
    width: 100%; border-collapse: collapse;
    font-size: 15px;
    background: var(--surface);
    border: 1px solid var(--hairline);
    border-radius: var(--r-lg);
    overflow: hidden;
}
table.list th, table.list td { text-align: left; padding: 14px 17px; border-bottom: 1px solid var(--divider-soft); }
table.list thead th {
    font-size: 12px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase;
    color: var(--text-muted); background: var(--surface-2);
}
table.list tbody tr:last-child td { border-bottom: 0; }
table.list tbody tr { transition: background-color var(--dur-fast) var(--ease); }
table.list tbody tr:hover { background: var(--surface-2); }
table.list td.num, table.list th.num { text-align: right; font-variant-numeric: tabular-nums; }

/* ================================ EMPTY STATE ================================
   One implementation, used everywhere. An empty screen is an invitation to act, not an apology. */
.empty {
    border: 1px dashed var(--hairline);
    border-radius: var(--r-lg);
    background: var(--surface-2);
    padding: var(--s-xxl) var(--s-lg);
    text-align: center;
}
.empty__icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; margin-bottom: var(--s-md);
    border-radius: var(--r-pill); background: var(--surface-3); color: var(--text-muted);
}
.empty__icon svg { width: 22px; height: 22px; }
.empty__title { font-size: 17px; font-weight: 600; color: var(--text); margin: 0 0 6px; }
.empty__body { font-size: 15px; color: var(--text-muted); margin: 0 auto var(--s-md); max-width: 44ch; }

/* ================================ BRAND ================================ */
.brand-lockup { display: inline-flex; align-items: center; gap: 10px; text-decoration: none; color: var(--text); }
.brand-lockup:hover { text-decoration: none; }
.brand-mark {
    display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
    width: 28px; height: 28px; border-radius: var(--r-sm);
    background: var(--accent); color: var(--on-accent);
    font-weight: 600; font-size: 15px;
}
.brand-glyph { color: var(--on-accent); }
.brand .brand-word { color: var(--text); font-size: 19px; font-weight: 600; letter-spacing: -.02em; }
.brand .brand-word span { color: var(--text); }
/* Both staff-uploaded variants are emitted; CSS picks one so a theme switch needs no reload.
   "light"/"dark" name the BACKGROUND the asset is drawn on, matching BrandingService. */
.brand-logo { height: 28px; width: auto; max-width: 190px; object-fit: contain; display: block; }
.brand-logo--dark { display: none; }
:root[data-theme="dark"] .brand-logo--light { display: none; }
:root[data-theme="dark"] .brand-logo--dark { display: block; }
/* Inside a dark band the surface is dark whatever the theme, so the dark-background asset wins. */
.band--dark .brand-logo--light, .band--dark-2 .brand-logo--light,
.band--dark-3 .brand-logo--light, .band--void .brand-logo--light { display: none; }
.band--dark .brand-logo--dark, .band--dark-2 .brand-logo--dark,
.band--dark-3 .brand-logo--dark, .band--void .brand-logo--dark { display: block; }

/* ================================ INLINE HELP ================================ */
.help { position: relative; display: inline-flex; vertical-align: middle; margin-left: 5px; line-height: 0; }
.help-btn {
    all: unset; box-sizing: border-box; cursor: help;
    width: 16px; height: 16px; flex: none;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: var(--r-pill); color: var(--text-muted); border: 1px solid var(--field-border);
    transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.help-btn:hover, .help-btn:focus-visible { color: var(--accent-text); border-color: var(--accent-text); outline: none; }
.help-pop {
    position: absolute; bottom: calc(100% + 9px); left: 50%; transform: translateX(-50%);
    width: max-content; max-width: 260px;
    background: var(--text); color: var(--canvas);
    border-radius: var(--r-sm); padding: 10px 13px;
    font-size: 13px; font-weight: 400; line-height: 1.45; letter-spacing: 0; text-align: left; text-transform: none;
    opacity: 0; visibility: hidden;
    transition: opacity var(--dur-fast) var(--ease), visibility var(--dur-fast);
    z-index: 70;
}
.help:hover .help-pop, .help:focus-within .help-pop { opacity: 1; visibility: visible; }
@media (max-width: 600px) { .help-pop { max-width: 200px; left: auto; right: -4px; transform: none; } }
.field:has(> .help) > label,
h1:has(+ .help), h2:has(+ .help), h3:has(+ .help) { display: inline-flex; align-items: center; gap: .3em; vertical-align: middle; }
.field:has(> .help) > .help + * { margin-top: 6px; }

/* ================================ DISCLOSURE CARD ================================ */
.disclosure {
    background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--r-lg);
    padding: var(--s-md) var(--s-lg); margin-bottom: 10px; font-size: 15px;
}
.disclosure .dt { font-weight: 600; }

/* ================================ COUNTRY / CURRENCY COMBOBOX ================================ */
[x-cloak] { display: none !important; }
.country-select { position: relative; }
.cs-menu {
    position: absolute; z-index: 60; left: 0; right: 0; top: calc(100% + 6px);
    max-height: 264px; overflow-y: auto; overscroll-behavior: contain;
    background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--r-md); padding: 6px;
}
.cs-opt {
    padding: 10px 12px; border-radius: var(--r-sm); font-size: 15px; cursor: pointer; color: var(--text-2);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cs-opt:hover, .cs-opt.active, .cs-opt.sel { background: var(--surface-3); color: var(--text); }
.cs-empty { padding: 12px; font-size: 14px; color: var(--text-muted); }

/* ================================ FILE DROP ================================
   A file drop is a FIELD, so it takes the field radius — not the card radius it used to carry. At
   --r-lg it wore the same corner as .card/.panel/.filterbar, which made a document upload read as a
   container that happened to be in the form rather than as the control its label belongs to, and put
   a 7px step between it and the inputs stacked either side of it in the KYC and KYB steps.
   The dashed border is what says "drop here"; the corner does not need to say it as well. */
.filedrop { position: relative; }
.filedrop-native { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* The bare fallback: <x-file-drop> with no wire:model renders a plain native input, which matches no
   selector in FORMS (see the note there for why `file` cannot join that list). Styled here instead,
   and :not() keeps it off the hidden input above. Padding is lighter than a text field's because the
   browser draws its own "Choose file" button inside the box. */
input[type="file"]:not(.filedrop-native) {
    width: 100%; padding: 9px 12px;
    border: 1px solid var(--field-border); border-radius: var(--r-md);
    background: var(--surface); color: var(--text);
    font-family: inherit; font-size: 15px; line-height: 1.4;
}
input[type="file"]:not(.filedrop-native):focus-visible { outline: none; border-color: var(--accent-focus); box-shadow: var(--ring); }
.filedrop-zone {
    display: flex; align-items: center; justify-content: center; text-align: center; gap: 14px;
    min-height: 120px; padding: var(--s-lg);
    border: 1.5px dashed var(--field-border); border-radius: var(--r-md);
    background: var(--surface-2); color: var(--text-2); cursor: pointer;
    transition: border-color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
}
.filedrop-zone:hover { border-color: var(--accent); }
.filedrop:focus-within .filedrop-zone { border-color: var(--accent-focus); box-shadow: var(--ring); }
.filedrop.dragover .filedrop-zone { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 6%, transparent); }
.filedrop.hasfile .filedrop-zone { justify-content: flex-start; text-align: left; min-height: 0; padding: var(--s-md); }
.fd-empty { display: flex; flex-direction: column; align-items: center; gap: 9px; pointer-events: none; }
.fd-ico { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; border-radius: var(--r-pill); background: var(--surface-3); color: var(--text-muted); flex-shrink: 0; }
.fd-ico.ok { background: var(--ok-bg); color: var(--ok-text); }
.fd-ico svg { width: 22px; height: 22px; }
.fd-title { font-size: 15px; color: var(--text); }
.fd-title strong, .fd-browse { color: var(--accent-text); font-weight: 600; }
.fd-hint { font-size: 13px; color: var(--text-muted); }
.fd-file { display: flex; align-items: center; gap: 14px; width: 100%; }
.fd-meta { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.fd-name { font-size: 15px; font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fd-size { font-size: 13px; color: var(--text-muted); }
.fd-remove { flex-shrink: 0; }
.fd-uploading { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-muted); margin-top: 9px; }
.fd-spin { width: 13px; height: 13px; border: 2px solid var(--hairline); border-top-color: var(--accent); border-radius: var(--r-pill); animation: ft-spin .7s linear infinite; }

/* ================================ SEARCHABLE SERVER COMBOBOX ================================ */
.ft-combo { position: relative; }
.ft-combo-picked { margin: 6px 0 0; font-size: 13px; color: var(--text-2); }
.ft-combo-picked strong { color: var(--text); font-weight: 600; }
.ft-combo-menu {
    position: absolute; z-index: 40; left: 0; right: 0; margin-top: 6px;
    max-height: 300px; overflow-y: auto; overscroll-behavior: contain;
    background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--r-md); padding: 6px;
}
.ft-combo-group {
    margin: 8px 8px 4px; font-size: 12px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
    color: var(--text-muted);
}
.ft-combo-group:not(:first-child) { border-top: 1px solid var(--divider-soft); padding-top: 10px; }
/* An option is a <button>, so the base button rule has to be undone or every row renders as a blue pill. */
.ft-combo-opt {
    display: block; width: 100%; text-align: left; padding: 9px 11px; border: 0; border-radius: var(--r-sm);
    background: transparent; color: var(--text); font-size: 15px; font-weight: 400; line-height: 1.35;
    letter-spacing: -.224px; cursor: pointer; transform: none;
}
.ft-combo-opt:hover { background: var(--surface-3); color: var(--text); transform: none; }
.ft-combo-opt.is-active { background: var(--surface-3); color: var(--text); box-shadow: inset 2px 0 0 var(--accent); }
.ft-combo-opt:focus { outline: none; }
.ft-combo-opt:focus-visible { outline: none; box-shadow: var(--ring); }
.ft-combo-opt.is-picked { background: var(--surface-3); font-weight: 600; }
.ft-combo-opt.is-picked::after { content: " ✓"; color: var(--accent-text); }
.ft-combo-empty, .ft-combo-more { margin: 9px; font-size: 13px; color: var(--text-muted); line-height: 1.45; }
.ft-combo-more { border-top: 1px solid var(--divider-soft); padding-top: 9px; }

/* ================================ PAGINATION ================================ */
.ft-pager { display: flex; align-items: center; justify-content: space-between; gap: var(--s-md); flex-wrap: wrap; margin-top: var(--s-xl); }
.ft-pager__count { margin: 0; font-size: 14px; color: var(--text-muted); }
.ft-pager__count strong { color: var(--text-2); font-weight: 600; font-variant-numeric: tabular-nums; }
.ft-pager__list { display: flex; align-items: center; gap: 6px; list-style: none; margin: 0; padding: 0; flex-wrap: wrap; }
.ft-pager__btn {
    display: inline-flex; align-items: center; justify-content: center; min-width: 44px; height: 44px;
    padding: 0 14px; border-radius: var(--r-sm); border: 1px solid var(--hairline);
    background: var(--surface); color: var(--text-2);
    font-size: 15px; font-weight: 400; line-height: 1; cursor: pointer; font-variant-numeric: tabular-nums;
}
.ft-pager__btn:hover { background: var(--surface-2); color: var(--text); border-color: var(--field-border); }
.ft-pager__btn:focus-visible { outline: none; box-shadow: var(--ring); }
.ft-pager__btn.is-current { border-color: var(--accent); color: var(--accent-text); background: color-mix(in srgb, var(--accent) 8%, transparent); font-weight: 600; }
.ft-pager__btn.is-disabled { opacity: .4; cursor: not-allowed; }
.ft-pager__btn:disabled { opacity: .55; cursor: progress; }
.ft-pager__gap { padding: 0 2px; color: var(--text-muted); }
@media (max-width: 560px) {
    .ft-pager { justify-content: center; }
    .ft-pager__num, .ft-pager__gap { display: none; }
    .ft-pager__list { width: 100%; justify-content: space-between; }
}

/* ================================ SHARE TRAY ================================ */
.ft-share { background: var(--surface-2); border: 1px solid var(--hairline); border-radius: var(--r-lg); padding: var(--s-md) var(--s-lg); margin: -4px 0 var(--s-sm); }
.ft-share__hd { display: flex; gap: 11px; align-items: flex-start; }
.ft-share__hd .ic { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; color: var(--accent-text); flex-shrink: 0; margin-top: 2px; }
.ft-share__hd strong { display: block; font-size: 15px; letter-spacing: -.01em; }
.ft-share__hd p { margin: 3px 0 0; font-size: 14px; line-height: 1.47; color: var(--text-muted); }
.ft-share__link { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: var(--s-sm); }
.ft-share__link input { flex: 1; min-width: 210px; padding: 9px 12px; font-size: 14px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.ft-share__native { display: none; }
:root.can-share .ft-share__native { display: inline-flex; }
.ft-share__msg { margin: 11px 0 0; padding: 11px 13px; background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--r-sm); font-size: 14px; line-height: 1.55; color: var(--text-2); }
.ft-share__msg span { display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--text-muted); font-weight: 600; margin-bottom: 4px; }
.ft-share__targets { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--s-sm); }
.ft-share__btn {
    display: inline-flex; align-items: center; gap: 7px; padding: 9px 15px; font-size: 14px; font-weight: 400;
    border-radius: var(--r-pill); background: var(--surface); color: var(--text);
    border: 1px solid var(--hairline); text-decoration: none; line-height: 1.2;
    transition: border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.ft-share__btn:hover { border-color: var(--accent); color: var(--accent-text); text-decoration: none; }
.ft-share__btn:active { transform: scale(.95); }
.ft-share__btn:focus-visible { outline: none; box-shadow: var(--ring); }
.ft-share__btn .g { display: inline-flex; align-items: center; justify-content: center; width: 15px; height: 15px; flex-shrink: 0; }
.ft-share__note { margin: 11px 0 0; font-size: 13px; line-height: 1.5; color: var(--text-muted); }
.ft-share-note { margin: -4px 0 var(--s-sm); font-size: 13px; line-height: 1.5; color: var(--text-muted); }

/* ================================ NUMBERED STEPS ================================ */
.ft-steps { list-style: none; margin: var(--s-sm) 0 0; padding: 0; counter-reset: ft-step; display: grid; gap: var(--s-sm); }
.ft-steps > li { counter-increment: ft-step; position: relative; padding-left: 38px; color: var(--text-2); line-height: 1.55; font-size: 15px; }
.ft-steps > li::before {
    content: counter(ft-step); position: absolute; left: 0; top: 0; width: 26px; height: 26px;
    display: inline-flex; align-items: center; justify-content: center; border-radius: var(--r-pill);
    background: var(--accent); color: var(--on-accent); font-size: 13px; font-weight: 600; line-height: 1;
}
.ft-steps > li strong { color: var(--text); }
.ft-bot-handle { display: inline-block; background: var(--surface-3); border: 1px solid var(--hairline); border-radius: var(--r-sm); padding: 3px 9px; font-weight: 600; color: var(--text); }
.ft-why { margin: var(--s-sm) 0 0; padding: 12px 14px; background: var(--surface-2); border: 1px solid var(--hairline); border-left: 2px solid var(--accent); border-radius: var(--r-sm); font-size: 14px; line-height: 1.55; color: var(--text-muted); }
.ft-why strong { color: var(--text-2); }

/* ================================ MOTION ================================
   150–300ms, transform/opacity only, never `transition: all`, and every one of these is neutralised
   under prefers-reduced-motion. Entrances are html.js-gated so a no-JS client sees visible content. */
@keyframes ft-rise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
@keyframes ft-spin { to { transform: rotate(360deg); } }
@keyframes ft-pulse { 0% { transform: scale(.8); opacity: .5; } 70% { transform: scale(1.7); opacity: 0; } 100% { opacity: 0; } }

html.js .reveal { opacity: 0; transform: translateY(12px); transition: opacity 300ms var(--ease), transform 300ms var(--ease); }
html.js .reveal.in { opacity: 1; transform: none; }
html.js .ft-in { opacity: 0; animation: ft-rise 300ms var(--ease) both; animation-delay: var(--d, 0s); }
.ft-spin-slow, .ft-float, .ft-float2, .ft-dash, .ft-shimmer, .ft-arc { /* retired decorative motion — kept as no-ops so old markup degrades cleanly */ }

/* ================================ SCROLL MOTION TOOLKIT ================================
   Four primitives the marketing pages compose. All four share the same contract:

     • the element is FULLY VISIBLE and complete without JavaScript — motion is added, never depended on
     • only transform / opacity / stroke-dashoffset animate (compositor-friendly, no layout thrash)
     • `prefers-reduced-motion: reduce` lands every one of them in its FINISHED state instantly

   The trigger is `.in`, applied by the shared observer in partials/theme.blade.php. Nothing here polls
   or measures layout during render.
   ------------------------------------------------------------------------------------------------- */

/* 1. SEQUENCE — children arrive in order once the group is in view.
      The stagger is pure CSS (nth-child -> --i), so a view never has to hand-number its own children
      and inserting a row in the middle cannot silently break the rhythm. */
html.js .ft-seq > * { opacity: 0; transform: translateY(14px); }
html.js .ft-seq.in > * {
    opacity: 1; transform: none;
    transition: opacity 420ms var(--ease), transform 420ms var(--ease);
    transition-delay: calc(var(--i, 0) * 70ms);
}
.ft-seq > *:nth-child(1) { --i: 0 } .ft-seq > *:nth-child(2) { --i: 1 }
.ft-seq > *:nth-child(3) { --i: 2 } .ft-seq > *:nth-child(4) { --i: 3 }
.ft-seq > *:nth-child(5) { --i: 4 } .ft-seq > *:nth-child(6) { --i: 5 }
.ft-seq > *:nth-child(7) { --i: 6 } .ft-seq > *:nth-child(8) { --i: 7 }
.ft-seq > *:nth-child(9) { --i: 8 } .ft-seq > *:nth-child(n+10) { --i: 9 }

/* 2. DRAW — an SVG stroke writes itself on.
      The path carries pathLength="1", which renormalises its geometry so a dasharray of 1 covers it
      exactly. That means NO JavaScript measurement of getTotalLength(), and it stays correct when the
      viewBox is scaled responsively — the usual implementation of this effect breaks on both counts. */
html.js .ft-draw { stroke-dasharray: 1; stroke-dashoffset: 1; }
html.js .in .ft-draw, html.js .ft-draw.in {
    stroke-dashoffset: 0;
    transition: stroke-dashoffset var(--dur, 1400ms) cubic-bezier(.32, .72, .3, 1);
    transition-delay: var(--d, 0s);
}

/* 3. TRACE — something travels ALONG that stroke (a trade moving from a strategist to a follower).
      offset-path follows the same geometry the line drew, so the dot cannot drift off the wire. */
html.js .ft-trace { opacity: 0; }
html.js .in .ft-trace {
    opacity: 1;
    animation: ft-travel var(--dur-travel, 1200ms) cubic-bezier(.4, 0, .3, 1) var(--d, 0s) both;
}
@keyframes ft-travel { from { offset-distance: 0%; } to { offset-distance: 100%; } }

/* 4. SEND — a short dash travelling the length of a stroke, for showing an order MOVING along a wire
      to a broker. (Named ft-send, not ft-pulse: `@keyframes ft-pulse` above already belongs to the
      live-dot ring, and a class and a keyframe sharing a name is legal but reads as a bug.) Built from stroke-dasharray rather than offset-path because
      dasharray is universally supported and behaves identically on every SVG geometry; the dash length
      is the visible pulse and the gap must exceed the path length so only one pulse is ever on the wire.
      `pathLength="1"` normalises the geometry, so the numbers below are fractions of the path, not
      user units — the same trick .ft-draw uses. */
html.js .ft-send { stroke-dasharray: 0.12 1; stroke-dashoffset: 1.12; opacity: 0; }
html.js .in .ft-send {
    opacity: 1;
    animation: ft-send-run var(--dur-send, 2600ms) linear var(--d, 0s) infinite;
}
/* The travel happens in the FIRST ~38% of the cycle and the rest is a hold, off. That gap is what makes
   a second hop possible: give hop two a delay of ~36% of the same duration and its pulse leaves just as
   hop one arrives, then both rest until the cycle restarts. Sharing one duration is what keeps the two
   hops in phase for ever — two different durations drift apart within a few seconds.

   The hold is also the honest choice: a continuous stream of pulses would read as live traffic, and
   there is none behind this drawing. One wave, a pause, one wave. */
@keyframes ft-send-run {
    0%   { stroke-dashoffset: 1.12; opacity: 0; }
    4%   { opacity: 1; }
    34%  { opacity: 1; }
    38%  { stroke-dashoffset: 0; opacity: 0; }
    100% { stroke-dashoffset: 0; opacity: 0; }
}

/* 5. SCRUB — a value tied to scroll position rather than to a timer.
      `--p` (0..1) is written by the observer while the element is on screen; CSS reads it. Used for the
      passport that accumulates as the page moves, where the visitor's own scrolling IS the timeline. */
html.js .ft-scrub { --p: 0; }

@media (prefers-reduced-motion: reduce) {
    html.js .ft-seq > *, html.js .ft-seq.in > * { opacity: 1 !important; transform: none !important; transition: none !important; }
    html.js .ft-draw, html.js .in .ft-draw, html.js .ft-draw.in { stroke-dashoffset: 0 !important; transition: none !important; }
    html.js .ft-trace, html.js .in .ft-trace { opacity: 1 !important; animation: none !important; offset-distance: 100% !important; }
    /* A pulse is a LOOP, so there is no finished state to land in — it simply does not run, and the
       wires it travelled are already drawn and legible on their own. */
    html.js .ft-pulse, html.js .in .ft-send { animation: none !important; opacity: 0 !important; }
}

.live-dot { position: relative; display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--up); flex-shrink: 0; }
.live-dot::after { content: ""; position: absolute; inset: 0; border-radius: 50%; background: var(--up); animation: ft-pulse 2.6s ease-out infinite; }

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    html.js .reveal { opacity: 1 !important; transform: none !important; transition: none; }
    html.js .ft-in { opacity: 1 !important; animation: none !important; }
    .live-dot::after { animation: none !important; }
    *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}


/* ==========================================================================================
   LIQUID GLASS — the applied material
   The tokens live in the two blocks at the top of this file; this section is the small amount of
   CSS that CONSUMES them, plus the escape hatches that switch the whole system off at the root.

   The material deliberately uses NO pseudo-element and adds NO markup: the edge is three insets
   and the sheen is a background-image. That is what lets it be applied to components that already
   spend their ::before/::after elsewhere — the ledger spine, the row counter, the trust ring's
   inner disc and the stretched card link all do.
   ========================================================================================== */

.glass {
    background-color: var(--glass);
    background-image:
        radial-gradient(var(--spec-size) circle at var(--spec-x) var(--spec-y),
            var(--spec-color) 0%, transparent 62%),
        var(--glass-sheen);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
    box-shadow: var(--glass-edge), var(--cast);
    border: 0;
    border-radius: var(--r-lg);
}
/* Raised: the surfaces meant to read as sitting ON the page rather than in it. */
.glass--raised {
    -webkit-backdrop-filter: var(--glass-blur-lg);
    backdrop-filter: var(--glass-blur-lg);
    box-shadow: var(--glass-edge), var(--cast-lg);
}
/* Flush: a pane inside a pane. A second cast shadow inside a shadowed parent reads as dirt, and
   two identical tints give no edge — hence the denser --glass-2 rather than a heavier border. */
.glass--flush {
    background-color: var(--glass-2);
    box-shadow: var(--glass-edge);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

/* The hover lift — a pane that is a link gains weight rather than changing colour — lives on each
   layout's own card class (see `.card:hover` in layouts.public), not on a `.glass-lift` helper here.
   The helper was written first, never referenced by any view, and its ring had no radius to follow. */

/* FIXED OVERLAYS take the densest tint AND the blur. Their own component CSS only sets a surface
   colour, so the blur has to be applied here; and they float over content nothing constrains, which
   is why the tint is 97%/96% rather than 72%/58% — measured against pure black and pure white. */
.ftx-consent, .ftx-panel, .ftx-mini, .ftx-bell-panel, .ftx-toast,
.drop-menu-box, .cs-menu, .ft-combo-menu, .ft-share-tray {
    --surface: var(--glass-dense);
    --surface-2: var(--glass-dense);
    --surface-3: var(--glass-dense);
    -webkit-backdrop-filter: var(--glass-blur-lg);
    backdrop-filter: var(--glass-blur-lg);
    box-shadow: var(--glass-edge), var(--cast-lg);
    /* A RADIUS FLOOR, because the ring follows it. A floating overlay always wants corners, and this
       rule cannot verify that each component declared some — a component that forgets would otherwise
       get a hard square box. Anything with its own larger radius keeps it (own rule, more specific);
       the full-bleed exception is overridden immediately below. */
    border-radius: var(--r-md);
}
/* `.ftx-consent__panel` is NOT in that list: it is a transparent inner wrapper with no radius, and
   --glass-edge contains an `inset 0 0 0 1px` ring which FOLLOWS the element's radius — so on a
   radius-0 wrapper it draws a hard square box around content that had no border at all. The same
   mistake put a square box around the whole sign-in form (guest layout `.card`) and around the
   high-water-mark chart. THE RULE: give the material only to something that is already a pane, i.e.
   has its own background AND its own radius. */

/* A FULL-BLEED BAR has no corners, so a ring's left and right sides run down the viewport edges as
   two stray hairlines. It takes the lit TOP edge only — the same treatment the sticky topbar gets. */
.ftx-consent--bar { border-radius: 0; box-shadow: inset 0 1px 0 var(--rim-hi), var(--cast-lg); }

/* ------------------------------------------------------------------------------------------
   ESCAPE HATCHES. Three of them, and each returns the product to the OPAQUE look it shipped
   before — never to a washed-out half-glass. They are token-only, which is why they reach every
   component in four layouts without naming one: a layout consumes `backdrop-filter:
   var(--glass-blur)`, so setting that token to `none` here switches the blur off everywhere.

   `--glass-edge`/`--cast` resolve to a transparent shadow rather than `none`, because
   `box-shadow: none, none` is invalid and would drop the whole declaration instead of clearing it.
   ------------------------------------------------------------------------------------------ */

/* 1. No backdrop-filter at all: a translucent pane with no blur is simply see-through. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    :root {
        --glass: #ffffff; --glass-2: #fafafc; --glass-3: #f5f5f7; --glass-dense: #ffffff;
        --hairline: #e0e0e0; --canvas: #ffffff; --canvas-alt: #f5f5f7;
        --glass-blur: none; --glass-blur-lg: none; --glass-sheen: none; --spec-color: transparent;
        --glass-edge: 0 0 0 0 transparent; --cast: 0 0 0 0 transparent; --cast-lg: 0 0 0 0 transparent;
    }
    :root[data-theme="dark"] {
        --glass: #1d1d1f; --glass-2: #252527; --glass-3: #2a2a2c; --glass-dense: #1d1d1f;
        --hairline: #38383a; --canvas: #000000; --canvas-alt: #1d1d1f;
        --glass-blur: none; --glass-blur-lg: none; --glass-sheen: none; --spec-color: transparent;
        --glass-edge: 0 0 0 0 transparent; --cast: 0 0 0 0 transparent; --cast-lg: 0 0 0 0 transparent;
    }
    body { background-image: none; }
    .band { background: var(--canvas); }
    .band--alt { background: var(--canvas-alt); }
}

/* 2. The OS has been asked to reduce transparency — a real accessibility preference, and
      transparency is this material's entire premise. Honoured by removing it, not softening it. */
@media (prefers-reduced-transparency: reduce) {
    :root {
        --glass: #ffffff; --glass-2: #fafafc; --glass-3: #f5f5f7; --glass-dense: #ffffff;
        --hairline: #e0e0e0; --canvas: #ffffff; --canvas-alt: #f5f5f7;
        --glass-blur: none; --glass-blur-lg: none; --glass-sheen: none; --spec-color: transparent;
    }
    :root[data-theme="dark"] {
        --glass: #1d1d1f; --glass-2: #252527; --glass-3: #2a2a2c; --glass-dense: #1d1d1f;
        --hairline: #38383a; --canvas: #000000; --canvas-alt: #1d1d1f;
        --glass-blur: none; --glass-blur-lg: none; --glass-sheen: none; --spec-color: transparent;
    }
    body { background-image: none; }
    .band { background: var(--canvas); }
    .band--alt { background: var(--canvas-alt); }
}

/* 3. More contrast requested: opaque panes, a real border, and the sheen goes — an 85%-white inset
      is decoration, and decoration is the first thing to drop when someone asks for legibility. */
@media (prefers-contrast: more) {
    :root {
        --glass: #ffffff; --glass-2: #ffffff; --glass-3: #f5f5f7; --glass-dense: #ffffff;
        --hairline: #6e6e73; --rim-hi: transparent; --rim-lo: transparent; --rim-ring: #6e6e73;
        --canvas: #ffffff; --glass-sheen: none; --spec-color: transparent;
    }
    :root[data-theme="dark"] {
        --glass: #1d1d1f; --glass-2: #1d1d1f; --glass-3: #2a2a2c; --glass-dense: #1d1d1f;
        --hairline: #98989d; --rim-hi: transparent; --rim-lo: transparent; --rim-ring: #98989d;
        --canvas: #000000; --glass-sheen: none; --spec-color: transparent;
    }
    body { background-image: none; }
}
