@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap');

/* ---- static/cf-theme.css ---- */
/* Cartel Family — theme tokens: SYNDICATE NOIR (decided 2026-10-12).
 *
 * THE palette. Every colour, type face, space, radius, shadow, glass recipe
 * and motion value in the product resolves from this file: the web pages,
 * the Telegram Mini App, the admin console, the landing, the share-card PNGs
 * (pnl_share_cards.py parses it) and every canvas (cf-charts.js reads the
 * computed values off <body>). Nothing else defines a colour.
 *
 * The values ARE the Noir design system. The prototype they were taken from
 * (/design/a/*, its tokens.css and COMPONENTS.md) was deleted on 2026-10-15
 * once every surface wore Noir; this file and cf-noir.css are the system now,
 * with the AA corrections the product's contrast test computes
 * (tests/test_accent_contrast.py) — see "AA" below.
 *
 * Three layers:
 *   1. NOIR TOKENS — the design system's own names (--ink-0..5 grounds,
 *      --text-1..4, --gold-50..900 + --molten, the ONE electric accent --ion,
 *      --up/--dn, rank metals, glass, elevation, type, space, radii, motion,
 *      chart series). New work uses these.
 *   2. PRODUCT TOKENS — the short names every existing stylesheet already
 *      reads (--bg --s1 --s2 --line --ink --ink2 --ink3 --acc --accT --onAcc
 *      --up --dn --pro --nav-* --rank-* --series-* --dur-* ...), each pointed
 *      at its Noir value, so every page is Noir without touching its markup.
 *   3. ALIASES — the ~60 older names (--bg2, --text, --accent-cta, --m3-*).
 *
 * NAME TRAP: in Noir `--ink-1` (with a hyphen and a digit) is a GROUND
 * colour; the product's `--ink` / `--ink2` / `--ink3` are TEXT colours. They
 * are different tokens and both exist here on purpose.
 *
 * Themes (owner decision 2026-09-25, kept by the Noir decision): dark is the
 * default; [data-theme="light"] is an explicit choice; absent means dark
 * whatever the OS prefers. The light palette is scoped to body.cf-themable so
 * a legacy template with hardcoded dark surfaces is not handed light chrome
 * over dark content. Light is ice white, the same blue (deeper), navy type.
 *
 * BRAND COLOUR: BLUE (owner's decision, 2026-10-16: "change the gold colour
 * scheme to match the blue"). The ramp was sampled from the new brand art
 * (the Boss Bull icon on royal blue, and the CARTEL banner): electric
 * #1687FF, royal #0659B7, deep navy #0F264F / #061735. The --gold-* names
 * stay as ALIASES of --blue-* so every stylesheet keeps working; --molten is
 * the blue molten (ice -> electric -> royal -> deep). Rank metals keep their
 * metal tones (they are ranks, not brand). The ONE live accent --ion moved
 * from cyan to aqua-teal so it never reads as the primary blue.
 *
 * AA (tests/test_accent_contrast.py computes these from this file):
 *   dark  --acc #3d97ff under --on-molten #04122a      6.28:1
 *   dark  --accent-text #7cb8ff on --ink-4 #122036     7.90:1 (worst ground)
 *   dark  --text-3 #8b9ab0 on --ink-4                  5.71:1
 *   light --acc #1f6fe0 under #ffffff                  4.76:1
 *   light --accent-text #1652b8 on --ink-4 #eaf1fb     6.30:1
 *   light --text-3 #56647c on --ink-4                  5.26:1
 *   light --up #0e6947 / --dn #c22e40 keep their earlier AA corrections.
 */


/* ── 1+2. DARK (the default): Noir tokens and the product names ────────── */
:root, [data-theme="dark"] {
  color-scheme: dark;

  /* product names, first so every parser (pnl_share_cards.py, the contrast
     test) reads the dark value; each resolves to a Noir token below */
  --bg: var(--ink-1); --s1: var(--ink-3); --s2: var(--ink-4);
  --ink: var(--text-1); --ink2: var(--text-2); --ink3: var(--text-3); --body: #d5deea;
  --acc: #3d97ff; --accT: var(--accent-text); --onAcc: var(--on-molten);
  --up: #4fe0a2; --dn: #ff5f6d;
  --upBg: rgba(79,224,162,.14); --dnBg: rgba(255,95,109,.14);
  --pro: #f2b84b; --proBg: #120d06; --proLine: #4a3a1c;
  --onPro: #1c1209;   /* label on an amber FILL */

  /* ground and surfaces */
  --ink-0: #03070f;                 /* deepest: bezel inner, dial */
  --ink-1: #050b17;                 /* page: deep navy ink */
  --ink-2: #081120;                 /* sunken: inputs, segmented track */
  --ink-3: #0c1729;                 /* card */
  --ink-4: #122036;                 /* raised control */
  --ink-5: #1c2d48;                 /* hairline on raised, sheet grabber */
  --ground-rgb: 5 11 23;
  --ground-hi: #0b1a33;
  --raise: 17 29 49;
  --card-hi: #122036; --card-lo: #09121f;
  --sheet-hi: #101c30; --sheet-lo: #081120;
  --well-hi: #0d1626; --well-lo: #060c17;
  --badge-hi: #11213b; --badge-lo: #08101e;
  --surface-hover: #0b1424;
  --well: rgb(0 0 0 / .26);         /* figure wells inside cards */
  --tint: 214 232 255;              /* light-on-dark channel: rgb(var(--tint) / .04) */
  --shade: 0 0 0;
  --scrim-rgb: 2 5 12;
  --ion-ground: 4 28 28;

  /* text: ice white, never pure white */
  --text-1: #eef3fb;
  --text-2: #a7b4c8;
  --text-3: #8b9ab0;
  --text-4: #4a566a;
  --accent-text: #7cb8ff;           /* blue as TEXT (= --blue-300) */
  --accent-text-strong: #b0d4ff;    /* blue figures (= --blue-200) */
  --on-molten: #04122a;
  --on-ion: #032622;

  /* molten blue: brand electric #1687FF / royal #0659B7 / navy #0F264F ramped */
  --blue-50: #eef6ff; --blue-100: #d6e9ff; --blue-200: #b0d4ff; --blue-300: #7cb8ff;
  --blue-400: #3d97ff; --blue-500: #1687ff; --blue-600: #0f6ad8; --blue-700: #0b4fa8;
  --blue-800: #0b3570; --blue-900: #071a38;
  --gold-50: var(--blue-50); --gold-100: var(--blue-100); --gold-200: var(--blue-200); --gold-300: var(--blue-300);
  --gold-400: var(--blue-400); --gold-500: var(--blue-500); --gold-600: var(--blue-600); --gold-700: var(--blue-700);
  --gold-800: var(--blue-800); --gold-900: var(--blue-900);
  --glow: 61 151 255;
  --molten: linear-gradient(118deg, #d4e9ff 0%, #8cc4ff 22%, #4aa0ff 46%, #2f86ff 64%, #1a5fd0 100%);
  --molten-text: linear-gradient(100deg, #eef6ff 0%, #b0d4ff 30%, #6aaeff 62%, #3d97ff 100%);
  --molten-edge: linear-gradient(180deg, rgba(214,233,255,.42), rgba(22,135,255,.08) 40%, rgba(22,135,255,0) 70%);
  --molten-hi: rgba(214,233,255,.55);    /* the molten fill's own rim */
  --molten-lo: rgba(6,40,110,.35);       /* its inset royal base */
  --sheen-rgb: 236 245 255;              /* the light sweep, the ripple, a top highlight */

  /* the ONE electric accent: ion = live / active only (aqua-teal, so it never
     reads as the primary blue) */
  --ion: #40ead2; --ion-rgb: 64 234 210;

  /* direction, as channels */
  --up-rgb: 79 224 162; --dn-rgb: 255 95 109;

  /* ember: the celebration palette (sparks, embers), as HSL parts */
  --ember-h: 208; --ember-h-span: 22; --ember-s: 100%; --ember-l: 70%;

  /* rank metals, Associate -> Boss: base / highlight / shadow */
  --metal-associate: #8d939c; --metal-associate-hi: #d7dce3; --metal-associate-lo: #3a3e45;
  --metal-soldier: #c07a45;   --metal-soldier-hi: #f3c194;   --metal-soldier-lo: #5a3016;
  --metal-capo: #c6ccd6;      --metal-capo-hi: #ffffff;      --metal-capo-lo: #5d6470;
  --metal-underboss: #e0b464; --metal-underboss-hi: #fff0c4; --metal-underboss-lo: #7a5420;
  --metal-boss: #f4d79a;      --metal-boss-hi: #fffaf0;      --metal-boss-lo: #2a1c0e;

  /* chart series: brand blue, ion, jade, amethyst, ember, gold, brass, rose */
  --series-1: #7cb8ff; --series-2: #40ead2; --series-3: #4fe0a2; --series-4: #c08cff;
  --series-5: #ff9b5c; --series-6: #ecc286; --series-7: #f2e58a; --series-8: #ff6fa8;

  /* chains (one dot colour per chain; NA.chainChip in the reference) */
  --chain-solana: #b98cff; --chain-base: #5b8cff; --chain-bsc: #f3c74f;
  --chain-arbitrum: #62b5ff; --chain-polygon: #a77bff; --chain-robinhood: #c6f25b;
  --chain-ethereum: #9aa9ff; --chain-monad: #a98bff; --chain-hyperevm: #5fe3c4;

  /* navigation hues (navigation.HUES): drawn from the Noir series */
  --nav-feed: #5fd0ff; --nav-discover: #c08cff; --nav-market: #4fe0a2; --nav-bot: #40ead2;
  --nav-traders: #ff9b5c; --nav-calls: #f2e58a; --nav-leaderboard: #7cb8ff; --nav-groups: #8fb4ff;
  --nav-promote: #ff6fa8; --nav-launch: #4fe0a2; --nav-share: #9aa7ba; --nav-admin: #7cb8ff;
  --nav-portfolio: #4fe0a2; --nav-profile: #7cb8ff; --nav-trade: #3d97ff; --nav-history: #8fb4ff;
  --nav-referrals: #f2e58a; --nav-settings: #9aa7ba; --nav-about: #9aa7ba;

  /* family ranks (gamification.RANKS): each rank's metal */
  --rank-associate: #8d939c; --rank-soldier: #d08a55; --rank-capo: #c6ccd6;
  --rank-underboss: #e0b464; --rank-boss: #f4d79a;
}

/* ── 1. NOIR: theme-independent tokens ──────────────────────────────────── */
:root {
  /* type: Space Grotesk for words, JetBrains Mono for every figure */
  --font-display: 'Space Grotesk', ui-sans-serif, system-ui, sans-serif;
  --font-body: 'Space Grotesk', ui-sans-serif, system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;
  --font-ui: var(--font-body);
  --font-num: var(--font-mono);
  --fs-hero: clamp(40px, 7.4vw, 104px); --lh-hero: .94; --fw-hero: 700; --tr-hero: -.05em;
  --fs-h1: clamp(30px, 4.4vw, 56px);    --lh-h1: 1.02;  --fw-h1: 700;   --tr-h1: -.035em;
  --fs-page-title: 26px;                --lh-page-title: 1.1; --fw-page-title: 700; --tr-page-title: -.03em;
  --fs-h2: clamp(22px, 2.6vw, 34px);    --lh-h2: 1.1;   --fw-h2: 700;   --tr-h2: -.03em;
  --fs-h3: 18px; --lh-h3: 1.2; --fw-h3: 600; --tr-h3: -.01em;
  --fs-body: 15px; --lh-body: 1.55; --fw-body: 400;
  --fs-small: 13px; --lh-small: 1.45;
  --fs-micro: 11px; --lh-micro: 1.2; --fw-micro: 600;
  --fs-figure-xl: clamp(26px, 3.2vw, 42px);
  --fs-figure: 20px;
  --tr-caps: .16em; --track-caps: var(--tr-caps);

  /* space: a 4px grid */
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 20px;
  --sp-6: 24px; --sp-8: 32px; --sp-10: 40px; --sp-12: 48px; --sp-16: 64px; --sp-24: 96px;
  --gutter: clamp(16px, 4vw, 48px);
  --maxw: 1320px;
  --rail-w: 232px; --rail-w-collapsed: 72px;
  --bar-h: 64px;
  --tap: 44px;                       /* minimum touch target */
  --pad-compact: 12px; --pad-comfortable: 16px;

  /* radii: badge 6 · control 10 · card 14 · sheet 20 · hero 28 · pill */
  --r-badge: 6px; --r-control: 10px; --r-card: 14px; --r-sheet: 20px; --r-full: 999px;
  --r-xs: 6px; --r-sm: 10px; --r-md: 14px; --r-lg: 20px; --r-xl: 28px; --r-pill: 999px;

  /* glass */
  --blur: 16px; --glass-saturate: 1.2;

  /* motion (COMPONENTS.md "Motion & toasts"). The --t-* names are Noir's; the
     --dur-* names are the product's, at the same values. */
  --ease-out: cubic-bezier(.2,.8,.2,1);
  --ease-in: cubic-bezier(.55,0,1,.45);
  --ease-in-out: cubic-bezier(.65,0,.35,1);
  --ease-spring: cubic-bezier(.34,1.56,.64,1);
  --ease-draw: cubic-bezier(.3,.7,.2,1);
  --t-fast: 160ms; --t-med: 280ms; --t-slow: 520ms; --t-enter: 600ms;
  --t-count: 900ms; --t-draw: 700ms; --t-sweep: 760ms; --t-ripple: 620ms; --t-press: 90ms;
  --toast-life: 5200ms;
  --dur-fast: .16s; --dur: .28s; --dur-draw: .7s;

  /* z-index, on the product's scale (its modals sit at 1500, its tips at 9800) */
  --z-base: 0; --z-sticky: 30; --z-bar: 40; --z-popover: 900; --z-sheet: 1500;
  --z-toast: 9700; --z-overlay: 9750;

  /* breakpoints (documentation: media queries use the literals) */
  --bp-phone: 390px; --bp-phone-max: 767px; --bp-tablet: 768px; --bp-laptop: 1024px; --bp-desktop: 1280px; --bp-wide: 1440px;

  --chart-fill-top: .22; --chart-glow: 4px;

  /* Card padding follows density; compact is the default. */
  --pad: var(--pad-compact);

  /* ── density: the compact pass (owner, 2026-10-11: "more minimal and
     compact"). One dial per kind of space, so every page tightens together.
     Touch targets stay 44px: --h-btn only drops on a fine pointer at laptop
     width. */
  --wrap-pad: 16px 24px;
  --wrap-pad-phone: 10px 12px 20px;
  --gap-cols: 16px;
  --gap-section: 12px;
  --gap-stack: 10px;
  --pad-card: var(--pad) 16px;
  --pad-card-head: 12px 16px 6px;
  --row-min: 48px;
  --h-btn: 44px;
}
@media (hover:hover) and (pointer:fine) and (min-width:1025px){
  :root{ --h-btn: 36px; }
}

/* ── derived tokens + aliases ───────────────────────────────────────────── */
/* Declared on body.cf-themable as well as :root. A custom property that
   references another is resolved where it is DECLARED, so a recipe declared
   only on :root resolves against the root's (dark) values and stays dark
   under the light palette, which lives on body.cf-themable. Re-declared on
   the body, every recipe follows the theme. */
:root, body.cf-themable {
  /* Noir recipes */
  --ion-dim: rgb(var(--ion-rgb) / .14);
  --ion-glow: 0 0 12px rgb(var(--ion-rgb) / .55), 0 0 2px rgb(var(--ion-rgb) / .9);
  --up-dim: rgb(var(--up-rgb) / .14);
  --dn-dim: rgb(var(--dn-rgb) / .14);
  --danger: var(--dn);
  --rank-ink: var(--text-1);
  --glass: rgb(var(--raise) / .62);
  --glass-edge: rgb(var(--tint) / .09);
  --glass-edge-hi: rgb(var(--tint) / .18);
  --glass-fill: linear-gradient(180deg, rgb(var(--raise) / .7), rgb(var(--raise) / .6) 38%, var(--glass));
  --glow-gold: 0 0 0 1px rgb(var(--glow) / .35), 0 8px 30px rgb(var(--glow) / .28);
  --focus-ring: 0 0 0 2px var(--ink-1), 0 0 0 4px var(--gold-300);
  --focus: var(--focus-ring);
  --chart-up: var(--up); --chart-down: var(--dn);
  --chart-grid: rgb(var(--tint) / .06);
  --chart-crosshair: rgb(var(--glow) / .55);
  /* the ground: navy ink, a blue light from above, a hint of ion top-right,
     royal blue bottom-left, and a 7% film grain drawn by an SVG turbulence filter */
  --ground:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 .85  0 0 0 0 .92  0 0 0 0 1  0 0 0 .055 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>"),
    radial-gradient(1200px 600px at 50% -10%, rgb(var(--glow) / .16), transparent 60%),
    radial-gradient(900px 500px at 100% 0%, rgb(var(--ion-rgb) / .05), transparent 60%),
    radial-gradient(800px 800px at 0% 100%, rgb(var(--glow) / .14), transparent 60%);

  /* product names that are recipes */
  --line: rgb(var(--tint) / .1);
  --grid: var(--chart-grid);
  --accBg: rgb(var(--glow) / .16);
  --scrim: rgb(var(--scrim-rgb) / .66);
  --e1: var(--shadow-2);
  --e2: var(--shadow-3);

  /* older names */
  --bg2: var(--s1);
  --bg3: var(--s2);
  --bg4: var(--s2);
  --text: var(--ink);
  --muted: var(--ink2);
  --dim: var(--ink3);
  --border: var(--line);
  --border2: var(--glass-edge-hi);
  --glass-border: var(--glass-edge);

  --accent: var(--acc);
  --accent-rgb: 61,151,255;
  --accent-cta: var(--acc);        /* a FILL: its label is --onAcc */
  --accent-ink: var(--accT);       /* accent as TEXT */
  --accent-fill: var(--molten);    /* the molten FILL, where a gradient is allowed */
  --gold: var(--acc);
  --gold2: var(--accT);
  --gold-rgb: 61,151,255;
  --on-gold: var(--onAcc);

  --green: var(--up);
  --green2: var(--up);
  --green-glow: var(--upBg);
  --red: var(--dn);
  --yellow: var(--pro);
  --blue: var(--series-6);
  --purple: var(--series-4);

  --m3-background: var(--bg);
  --m3-surface-lowest: var(--bg);
  --m3-surface-low: var(--s1);
  --m3-surface: var(--s1);
  --m3-surface-high: var(--s2);
  --m3-surface-highest: var(--s2);
  --m3-surface-bright: var(--s2);
  --m3-on-surface: var(--ink);
  --m3-on-surface-variant: var(--ink2);
  --m3-outline: var(--ink3);
  --m3-outline-variant: var(--line);
  --m3-primary: var(--accT);
  --m3-primary-container: var(--acc);
  --m3-on-primary: var(--onAcc);
  --m3-on-primary-container: var(--onAcc);
  --m3-primary-fixed: var(--gold-300);  /* brand fill, hovered */
  --m3-primary-fixed-dim: var(--acc);
  --m3-secondary: var(--series-2);
  --m3-secondary-container: var(--series-2);
  --m3-tertiary-fixed: var(--series-5);
  --m3-tertiary-fixed-dim: var(--series-5);
  --m3-error: var(--dn);
  --m3-error-container: var(--dnBg);

  --card-radius: var(--r-card);

  --space-xs: var(--sp-1);
  --space-sm: var(--sp-2);
  --gutter-compact: var(--sp-3);
  --space-md: var(--sp-4);
  --space-lg: var(--sp-6);
  --space-xl: var(--sp-8);

  --shadow-card: var(--shadow-2);
  --cf-scrim: var(--scrim);
  --cf-scrim-strong: rgb(var(--scrim-rgb) / .88);
  --cf-modal-shadow: var(--shadow-3);

  --font-sans: var(--font-body);
}

/* elevation + glass fill, per theme (the light values are warm and low) */
:root, [data-theme="dark"] {
  --glass-strong: rgba(10,19,34,.88);
  --shadow-1: 0 1px 0 rgb(var(--tint) / .05) inset, 0 1px 2px rgb(var(--shade) / .5), 0 4px 12px rgb(var(--shade) / .35);
  --shadow-2: 0 1px 0 rgb(var(--tint) / .07) inset, 0 2px 4px rgb(var(--shade) / .45), 0 12px 32px rgb(var(--shade) / .45);
  --shadow-3: 0 1px 0 rgb(var(--tint) / .09) inset, 0 4px 10px rgb(var(--shade) / .5), 0 28px 64px rgb(var(--shade) / .6);
}

html{min-height:100%;background:var(--bg)}

/* ── LIGHT: ice white, the brand blue (deeper), navy type ───────────────── */
:root[data-theme="light"]:has(body.cf-themable),
html:has(body.cf-themable.cf-light){
  --bg: #f3f7fd;
  color-scheme: light;
}
:root[data-theme="light"] body.cf-themable,
body.cf-themable.cf-light{
  --bg: #f3f7fd; --s1: #ffffff; --s2: #eaf1fb;
  --ink: #0a1628; --ink2: #45536a; --ink3: #56647c; --body: #1a2638;
  --acc: #1f6fe0; --accT: #1652b8; --onAcc: #ffffff;
  --up: #0e6947; --upBg: rgba(14,105,71,.10);
  --dn: #c22e40; --dnBg: rgba(194,46,64,.10);
  --pro: #936100; --proBg: #fbf3e2; --proLine: #ebd6a8;
  --onPro: #ffffff;

  --ink-0: #0a1426; --ink-1: #f3f7fd; --ink-2: #e8eff9; --ink-3: #ffffff; --ink-4: #eaf1fb; --ink-5: #cfdbec;
  --ground-rgb: 243 247 253; --ground-hi: #f8fbff; --raise: 255 255 255;
  --card-hi: #ffffff; --card-lo: #f6f9fe; --sheet-hi: #ffffff; --sheet-lo: #f1f6fd;
  --well-hi: #e8eff9; --well-lo: #dde7f4; --badge-hi: #eef5ff; --badge-lo: #dce9fb; --surface-hover: #e8f0fb;
  --well: rgb(30 70 140 / .07);
  --glass: rgb(var(--raise) / .74); --glass-edge: rgb(var(--tint) / .11); --glass-edge-hi: rgb(var(--tint) / .2);
  --tint: 20 40 80; --shade: 30 50 90; --scrim-rgb: 8 18 38; --ion-ground: 226 250 246;
  --text-1: #0a1628; --text-2: #45536a; --text-3: #56647c; --text-4: #9eabbf;
  --accent-text: #1652b8; --accent-text-strong: #0f3f8f;
  --on-molten: #ffffff; --on-ion: #ffffff;
  --molten: linear-gradient(118deg, #4a9dff 0%, #2a7ff0 22%, #1f6fe0 46%, #1a5fc8 64%, #0f3f8f 100%);
  --molten-text: linear-gradient(100deg, #2a7ff0 0%, #1f6fe0 35%, #1652b8 70%, #0f3f8f 100%);
  --molten-hi: rgba(255,255,255,.45);
  --molten-lo: rgba(6,30,80,.35);
  --sheen-rgb: 255 255 255;
  --glow: 31 111 224;
  --ion: #0b7d70; --ion-rgb: 11 125 112;
  --up-rgb: 14 105 71; --dn-rgb: 194 46 64;
  --ember-l: 45%;
  --glass-strong: rgba(255,252,247,.94);
  --molten-edge: linear-gradient(180deg, rgba(255,255,255,.9), rgba(31,111,224,.18) 40%, rgba(31,111,224,0) 70%);
  --shadow-1: 0 1px 0 rgba(255,255,255,.8) inset, 0 1px 2px rgb(var(--shade) / .08), 0 4px 12px rgb(var(--shade) / .07);
  --shadow-2: 0 1px 0 rgba(255,255,255,.9) inset, 0 2px 4px rgb(var(--shade) / .07), 0 12px 32px rgb(var(--shade) / .1);
  --shadow-3: 0 1px 0 rgba(255,255,255,.9) inset, 0 4px 10px rgb(var(--shade) / .08), 0 28px 64px rgb(var(--shade) / .16);
  --focus-ring: 0 0 0 2px var(--ink-1), 0 0 0 4px var(--gold-600);
  --series-1: #1f6fe0; --series-2: #0b7d70; --series-3: #12895c; --series-4: #7d4fd0;
  --series-5: #d2622a; --series-6: #a8743c; --series-7: #9a8320; --series-8: #c23c78;
  --metal-boss-lo: #4a3218;
  --chain-solana: #7d4fd0; --chain-base: #2f5fd6; --chain-bsc: #a8840f;
  --chain-arbitrum: #2a7cc4; --chain-polygon: #6e44c4; --chain-robinhood: #5f7d12; --chain-ethereum: #4b5bc4; --chain-monad: #6a48c8; --chain-hyperevm: #11806a;
  --nav-feed: #0a76b8; --nav-discover: #7d4fd0; --nav-market: #12895c; --nav-bot: #0b7d70;
  --nav-traders: #c4581f; --nav-calls: #8a7314; --nav-leaderboard: #1652b8; --nav-groups: #4a68c8;
  --nav-promote: #c23c78; --nav-launch: #12895c; --nav-share: #56647c; --nav-admin: #1652b8;
  --nav-portfolio: #12895c; --nav-profile: #1652b8; --nav-trade: #1652b8; --nav-history: #4a68c8;
  --nav-referrals: #8a7314; --nav-settings: #56647c; --nav-about: #56647c;
  --rank-associate: #5d6470; --rank-soldier: #8a4f22; --rank-capo: #4f5866;
  --rank-underboss: #7a5420; --rank-boss: #6b4a14;
  --chart-crosshair: rgb(var(--glow) / .7);
}

/* Comfortable density: set on <body data-density="comfortable">. */
body[data-density="comfortable"]{ --pad: var(--pad-comfortable); }

body{
  background-color:var(--bg);
  background-image:var(--ground);
  background-repeat:repeat,no-repeat,no-repeat,no-repeat;
  background-attachment:fixed;
  color:var(--ink);
  font-family:var(--font-body);
  font-weight:500;
  -webkit-font-smoothing:antialiased;
  /* Without this the ground stops where the content does, and a short page
     shows the browser's own canvas below the fold. */
  min-height:100vh;
}
::selection{background:rgb(var(--glow) / .35);color:var(--ink)}

/* ── type ramp (DESIGN_PROMPT §2) ─────────────────────────────────────────── */
.cf-display{font:var(--fw-h1) var(--fs-h1)/var(--lh-h1) var(--font-display);letter-spacing:var(--tr-h1)}
.cf-page-title{font-family:var(--font-display);font-size:var(--fs-page-title);line-height:var(--lh-page-title);font-weight:var(--fw-page-title);letter-spacing:var(--tr-page-title)}
.cf-card-title{font-size:16px;line-height:1.3;font-weight:700}
.cf-handle{font-size:15px;font-weight:700}
.cf-body{font-size:14px;line-height:1.45;font-weight:500;color:var(--body)}
.cf-label{font-size:12px;font-weight:600}
.cf-mono-label{font-family:var(--font-mono);font-size:var(--fs-micro);font-weight:500}
/* Noir caps: 11px mono, wide tracking (section labels, table heads, chips) */
.cf-caps{font:600 var(--fs-micro)/var(--lh-micro) var(--font-mono);letter-spacing:var(--tr-caps);text-transform:uppercase;color:var(--ink3)}
.cf-molten-text{background:var(--molten-text);-webkit-background-clip:text;background-clip:text;color:transparent}
.cf-hero-price{font-family:var(--font-mono);font-size:var(--fs-figure-xl);font-weight:600;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.cf-row-figure{font-family:var(--font-num);font-size:13px;font-weight:500;font-variant-numeric:tabular-nums}
/* Earlier names, kept so pages that opted in keep their sizes. */
.cf-headline-lg{font-size:26px;line-height:1.2;font-weight:700}
.cf-headline-md{font-size:22px;line-height:1.25;font-weight:700}
.cf-headline-sm{font-size:18px;line-height:1.3;font-weight:700}
.cf-title-md{font-size:16px;line-height:1.3;font-weight:700}
.cf-body-lg{font-size:16px;line-height:1.45}
.cf-body-md{font-size:14px;line-height:1.45}
.cf-body-sm{font-size:12px;line-height:1.4}
.cf-label-md{font-size:12px;letter-spacing:.04em;font-weight:600;text-transform:uppercase}
.cf-label-sm{font-size:11px;letter-spacing:.08em;font-weight:700;text-transform:uppercase}

/* Figures: JetBrains Mono, tabular, so columns of prices align. */
.cf-num,.cf-data{font-family:var(--font-num);font-variant-numeric:tabular-nums}

.cf-pill,.cf-avatar{border-radius:var(--r-full)}

/* Focus ring (Noir --focus-ring: a 2px ground gap, then 2px gold), drawn as
   an outline so it never replaces an element's own shadow. */
:focus-visible{outline:2px solid var(--focus-c,var(--gold-300));outline-offset:2px}
:root[data-theme="light"] body.cf-themable{--focus-c:var(--gold-600)}

/* ── theme toggle ─────────────────────────────────────────────────────────── */
.cf-theme-toggle{
  width:40px;height:40px;flex:0 0 40px;
  display:inline-flex;align-items:center;justify-content:center;
  border-radius:var(--r-pill);border:1px solid var(--glass-edge-hi);
  background:var(--s2);color:var(--ink2);cursor:pointer;padding:0;box-shadow:var(--shadow-1);
  transition:color var(--dur-fast),background var(--dur-fast),border-color var(--dur-fast);
}
.cf-theme-toggle:hover{color:var(--accent-text-strong);border-color:rgb(var(--glow) / .45)}
.cf-theme-toggle svg{transition:transform var(--t-med) var(--ease-spring)}
.cf-theme-toggle:hover svg{transform:rotate(-18deg)}
.cf-theme-toggle svg{width:16px;height:16px;display:block}
.cf-theme-toggle .cf-ico-sun{display:none}
:root[data-theme="light"] .cf-theme-toggle .cf-ico-sun{display:block}
:root[data-theme="light"] .cf-theme-toggle .cf-ico-moon{display:none}

@media (prefers-reduced-motion:reduce){
  .cf-theme-toggle{transition:none}
}

/* ── brand marks (DESIGN_PROMPT §1) ───────────────────────────────────────
   The wordmark is set in TYPE: the display face, white on dark and ink on light
   -- "never set the wordmark in gold". New markup uses .cf-wordmark-text.

   .cf-wordmark is the older EMPTY element drawn through a mask image, still
   used in six places. It keeps working, recoloured to --ink (it was gold, which
   the brand rules now forbid) until each place moves to the text mark. */
.cf-wordmark-text{
  font-family:var(--font-display);font-weight:700;letter-spacing:.14em;
  color:var(--ink);text-transform:uppercase;white-space:nowrap;
}
.cf-wordmark{
  display:block;
  background-color:var(--ink);
  -webkit-mask-image:url('/static/img/cartel-family-wordmark-mask.png');
          mask-image:url('/static/img/cartel-family-wordmark-mask.png');
  -webkit-mask-size:contain;   mask-size:contain;
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  -webkit-mask-position:center;  mask-position:center;
}
.cf-tagline{
  font-family:var(--font-display);font-weight:700;letter-spacing:.26em;
  color:var(--accT);text-transform:uppercase;
}
.cf-icon-tile{
  display:block;border-radius:22%;object-fit:cover;
  background:url('/static/brand/icon-tile-128.png') center/cover no-repeat;
}

/* A member who predates handles (users.username empty) reads "unnamed" on
   every list -- never their wallet (handles.UNNAMED, decided 2026-10-09).
   Lower-case, muted, no '@': it is the absence of a name, not a name. */
.cf-unnamed{
  color:var(--ink3);font-weight:500;font-style:normal;text-transform:none;letter-spacing:0;
}

/* Native controls follow the theme. Without color-scheme the browser drew
   every <select>'s open list (Bridge's From/To, Convert's network, settings)
   in light-mode colours on the dark app -- white text on white, unreadable
   (owner's report, 2026-10-11). The open list is painted by the OS, so the
   options get the theme's own surface and ink as well. */
:root{color-scheme:dark}
:root[data-theme="light"]{color-scheme:light}
select option,select optgroup{background-color:var(--s1);color:var(--ink)}

/* ── shared primitives: icons and tooltips ────────────────────────────────
   CFIcon (static/cf-icons.js, Lucide subset) draws in currentColor at
   Lucide's own 2px stroke, 1em square unless a size is given. */
.cf-i{
  width:1em;height:1em;flex:none;display:inline-block;vertical-align:-.125em;
  fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;
}
/* The glyph beside a menu label (navigation.icon_svg / {{ nav_icon() }}):
   a fixed box that never shrinks or shifts, currentColor so it follows the
   row lit, dim, dark or light. The label stays; this only sits beside it. */
.cf-nav-i{flex:none;display:inline-block;vertical-align:-3px;width:16px;height:16px}
.cf-nav-i[width="18"]{width:18px;height:18px}
.cf-nav-i[width="14"]{width:14px;height:14px}
.cf-nav-i[width="12"]{width:12px;height:12px}
/* CFFloat tooltips ([data-cf-tip]). One shared node, positioned by
   Floating UI; never parked invisible -- it is display:none until shown. */
.cf-tip{
  display:none;z-index:9800;pointer-events:none;max-width:240px;
  padding:7px 10px;border-radius:var(--r-sm);
  background:var(--glass-strong);color:var(--ink);border:1px solid rgb(var(--glow) / .3);
  font:500 12px/1.35 var(--font-body);box-shadow:var(--shadow-3);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
}
.cf-tip.on{display:block}
/* One dropdown menu (CFFloat.menu positions it): the profile and DM "more"
   menus, a message's own menu, the admin role picker. Each used to carry its
   own copy of these rules, at three slightly different paddings. */
.cf-menu{
  display:none;position:absolute;z-index:900;min-width:150px;padding:4px;
  background:var(--glass-strong);border:1px solid var(--glass-edge-hi);border-radius:var(--r-md);box-shadow:var(--shadow-3);
  -webkit-backdrop-filter:blur(var(--blur)) saturate(var(--glass-saturate));backdrop-filter:blur(var(--blur)) saturate(var(--glass-saturate));
}
.cf-menu.open{display:block;animation:cf-pop-in var(--dur-pop) var(--ease-spring)}
@keyframes cf-pop-in{from{transform:translateY(-4px) scale(.97)}to{transform:none}}
.cf-menu>a,.cf-menu>button{
  display:flex;align-items:center;gap:8px;width:100%;min-height:36px;box-sizing:border-box;
  text-align:left;background:none;border:0;cursor:pointer;text-decoration:none;
  padding:0 10px;border-radius:var(--r-sm);font:500 13.5px var(--font-body);color:var(--ink);transition:background var(--dur-fast);
}
.cf-menu>a:hover,.cf-menu>button:hover,.cf-menu>a:focus-visible,.cf-menu>button:focus-visible{background:rgb(var(--tint) / .06)}
.cf-menu>.danger{color:var(--dn)}
@media (pointer:coarse){.cf-menu>a,.cf-menu>button{min-height:44px}}

/* ── motion system (2026-10-11: "looks plain, no animations") ─────────────
   One set of durations, easings and a stagger step, read by every surface
   (CSS here, JS through CFMotion, the Mini App through the same file) instead
   of the scattered .3s / .25s / cubic-bezier literals each stylesheet used to
   guess. Values are Syndicate Noir's (COMPONENTS.md "Motion & toasts"); the
   easings and --dur-fast/--dur/--dur-draw sit with the Noir tokens above.

   Two rules every class below obeys:
     - The RESTING state is the visible one. An entrance is a class script
       adds and removes on animationend (CFMotion.enter); nothing is parked
       at opacity 0 waiting for it, so a paused, hidden or printed page still
       shows its content.
     - prefers-reduced-motion shows the finished state: the classes stop
       animating and the content is simply there. */
:root{
  --dur-flash: .9s;            /* a price tick's glow, in and out            */
  --dur-enter: .6s;            /* a card, a row, a sheet arriving (--t-enter) */
  --dur-exit: .26s;            /* the same leaving -- always faster           */
  --dur-count: .9s;            /* a figure counting to its value (--t-count) */
  --dur-pop: .32s;             /* a like / follow / copy acknowledgement     */
  --stagger: 60ms;             /* between siblings entering together         */
  --stagger-max: 8;            /* siblings past this arrive with the 8th     */
}

/* enter: rise + fade, from script only (CFMotion.enter adds, then removes) */
@keyframes cf-enter-rise{from{opacity:0;transform:translateY(16px) scale(.985);filter:blur(4px)}to{opacity:1;transform:none;filter:none}}
@keyframes cf-enter-fade{from{opacity:0}to{opacity:1}}
@keyframes cf-enter-down{from{opacity:0;transform:translateY(-14px)}to{opacity:1;transform:none}}
@keyframes cf-enter-left{from{opacity:0;transform:translateX(28px)}to{opacity:1;transform:none}}
@keyframes cf-enter-right{from{opacity:0;transform:translateX(-28px)}to{opacity:1;transform:none}}
@keyframes cf-exit-left{from{opacity:1;transform:none}to{opacity:0;transform:translateX(-36px) rotate(-1.5deg)}}
@keyframes cf-exit-right{from{opacity:1;transform:none}to{opacity:0;transform:translateX(36px) rotate(1.5deg)}}
.cf-enter{animation:cf-enter-rise var(--dur-enter) var(--ease-out) var(--cf-delay,0s) both}
.cf-enter-fade{animation:cf-enter-fade var(--dur-enter) var(--ease-out) var(--cf-delay,0s) both}
.cf-enter-down{animation:cf-enter-down var(--dur-enter) var(--ease-out) var(--cf-delay,0s) both}
.cf-enter-left{animation:cf-enter-left var(--dur-enter) var(--ease-out) var(--cf-delay,0s) both}
.cf-enter-right{animation:cf-enter-right var(--dur-enter) var(--ease-out) var(--cf-delay,0s) both}
.cf-exit-left{animation:cf-exit-left var(--dur-exit) var(--ease-in) both}
.cf-exit-right{animation:cf-exit-right var(--dur-exit) var(--ease-in) both}

/* flash: a value that just moved tints up / down and settles back */
@keyframes cf-flash-up{0%{background-color:var(--upBg);color:var(--up);text-shadow:0 0 14px rgb(var(--up-rgb) / .8)}100%{background-color:transparent}}
@keyframes cf-flash-dn{0%{background-color:var(--dnBg);color:var(--dn);text-shadow:0 0 14px rgb(var(--dn-rgb) / .8)}100%{background-color:transparent}}
.cf-flash-up,.cf-flash-dn{border-radius:var(--r-badge)}
.cf-flash-up{animation:cf-flash-up var(--dur-flash) var(--ease-out)}
.cf-flash-dn{animation:cf-flash-dn var(--dur-flash) var(--ease-out)}

/* pop: an action acknowledged (like, follow, copy) */
@keyframes cf-pop{0%{transform:scale(1)}40%{transform:scale(1.18)}100%{transform:scale(1)}}
.cf-pop{animation:cf-pop var(--dur-pop) var(--ease-spring)}
/* a count that changed ticks up into place */
@keyframes cf-tick-up{from{transform:translateY(60%);opacity:.2}to{transform:none;opacity:1}}
@keyframes cf-tick-dn{from{transform:translateY(-60%);opacity:.2}to{transform:none;opacity:1}}
.cf-tick-up,.cf-tick-dn{display:inline-block}
.cf-tick-up{animation:cf-tick-up var(--dur-fast) var(--ease-out)}
.cf-tick-dn{animation:cf-tick-dn var(--dur-fast) var(--ease-out)}

/* a live dot: one soft pulse per new value (never an infinite loop) */
@keyframes cf-pulse{0%{box-shadow:0 0 0 0 var(--cf-pulse,rgb(var(--glow) / .55))}100%{box-shadow:0 0 0 12px transparent}}
.cf-pulse{animation:cf-pulse .7s var(--ease-out)}

/* the success mark: a ring and a tick that draw, used by the trade sheet */
.cf-mark{display:inline-block;width:44px;height:44px;color:var(--up)}
.cf-mark circle{stroke-dasharray:132;stroke-dashoffset:0}
.cf-mark path{stroke-dasharray:30;stroke-dashoffset:0}
.cf-mark.is-drawing circle{animation:cf-mark-ring .45s var(--ease-out) both}
.cf-mark.is-drawing path{animation:cf-mark-tick .3s var(--ease-out) .32s both}
@keyframes cf-mark-ring{from{stroke-dashoffset:132}to{stroke-dashoffset:0}}
@keyframes cf-mark-tick{from{stroke-dashoffset:30}to{stroke-dashoffset:0}}

/* "N new" pill: new items wait above the list instead of shoving it */
.cf-newpill{
  position:sticky;top:calc(var(--cf-sticky-top,72px) + 8px);z-index:30;
  display:flex;justify-content:center;height:0;overflow:visible;pointer-events:none;
}
.cf-newpill[hidden]{display:none}
.cf-newpill button{
  pointer-events:auto;display:inline-flex;align-items:center;gap:6px;
  height:36px;padding:0 16px;border-radius:var(--r-pill);cursor:pointer;
  border:1px solid rgb(var(--ion-rgb) / .45);background:var(--glass-strong);color:var(--ion);
  font:600 12.5px var(--font-mono);letter-spacing:.04em;
  box-shadow:var(--ion-glow),var(--shadow-3);animation:cf-enter-down var(--dur-enter) var(--ease-spring);
  -webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
}
.cf-newpill button:focus-visible{outline:2px solid var(--ion);outline-offset:2px}

/* skeleton shimmer: a loading block that says "loading", not "empty" */
@keyframes cf-shimmer{from{background-position:150% 0}to{background-position:-50% 0}}
.cf-skel{
  background:linear-gradient(90deg,rgb(var(--tint) / .04) 0%,rgb(var(--tint) / .1) 45%,rgb(var(--tint) / .04) 90%);
  background-size:200% 100%;animation:cf-shimmer 1.4s linear infinite;border-radius:var(--r-md);
}

@media (prefers-reduced-motion:reduce){
  .cf-enter,.cf-enter-fade,.cf-enter-down,.cf-enter-left,.cf-enter-right,
  .cf-flash-up,.cf-flash-dn,.cf-pop,.cf-tick-up,.cf-tick-dn,.cf-pulse,.cf-skel,
  .cf-newpill button{animation:none!important}
  .cf-exit-left,.cf-exit-right{animation:none!important;opacity:0}
  .cf-mark.is-drawing circle,.cf-mark.is-drawing path{animation:none!important}
}

/* Reduced motion: every Noir timing token is 0 -- no entrances, sweeps,
   ripples, magnet, shimmer or ring spin; the finished state shows. */
@media (prefers-reduced-motion:reduce){
  :root{--t-fast:0ms;--t-med:0ms;--t-slow:0ms;--t-enter:0ms;--t-count:0ms;--t-draw:0ms;--t-sweep:0ms;--t-ripple:0ms;--t-press:0ms}
  .cf-theme-toggle svg,.cf-menu.open{transition:none;animation:none}
}


/* ---- static/cf-noir.css ---- */
/* Cartel Family — SYNDICATE NOIR shared components (decided 2026-10-12).
 *
 * THE Noir component library. It began as the port of the prototype's
 * noir.css (spec COMPONENTS.md, both under /design/a/*, deleted 2026-10-15
 * once every surface wore it): the reference's `na-X` became the product's
 * `cf-X` (na-btn -> cf-btn, na-chip -> cf-chip, na-glass -> cf-glass,
 * na-tabs -> cf-tabs, na-sheet -> cf-sheet ...). Comments elsewhere that
 * name /design/a/* or static/design/a/* describe where a layout came from;
 * the classes and tokens they refer to live here and in cf-theme.css.
 *
 * Every value is a token from static/cf-theme.css; this file declares no
 * colour of its own. Loaded right after cf-theme.css on every surface
 * (noir_inject.py puts the <link> there), so any page, the Mini App, the admin
 * console and the landing can use these classes.
 *
 * Two rules every rule here keeps:
 *   - The RESTING state is the visible one. Entrances are classes script adds
 *     and removes (CFMotion.enter); nothing is parked at opacity 0.
 *   - Reduced motion is the finished state: no sweep, ripple, magnet,
 *     shimmer, pulse or spin; transitions off.
 */

/* ── glass panel: real depth, a 1px light edge on top ───────────────────── */
.cf-glass{
  position:relative;border-radius:var(--r-lg);
  background:linear-gradient(180deg,rgb(var(--raise) / .66),rgb(var(--raise) / .72) 38%,var(--glass));
  border:1px solid var(--glass-edge);box-shadow:var(--shadow-2);
  -webkit-backdrop-filter:blur(var(--blur)) saturate(var(--glass-saturate));
  backdrop-filter:blur(var(--blur)) saturate(var(--glass-saturate));
}
.cf-glass::before{
  content:'';position:absolute;inset:-1px;border-radius:inherit;padding:1px;pointer-events:none;
  background:var(--molten-edge);opacity:.9;
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;mask-composite:exclude;
}
.cf-panel{padding:var(--sp-5)}
.cf-panel-h{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-3);margin-bottom:var(--sp-4);flex-wrap:wrap}
.cf-panel-h h2,.cf-panel-h h3{margin:0;font:var(--fw-h3) var(--fs-h3)/var(--lh-h3) var(--font-display);letter-spacing:var(--tr-h3)}

/* ── live marker: the ion accent's one job ──────────────────────────────── */
.cf-live{display:inline-flex;align-items:center;gap:7px;font:600 var(--fs-micro)/1 var(--font-mono);letter-spacing:var(--tr-caps);color:var(--ion);text-transform:uppercase}
.cf-live::before{content:'';width:7px;height:7px;border-radius:50%;background:var(--ion);box-shadow:var(--ion-glow);animation:cf-beat 1.6s var(--ease-in-out) infinite}
.cf-live.is-off{color:var(--ink3)}
.cf-live.is-off::before{background:var(--text-4);box-shadow:none;animation:none}
@keyframes cf-beat{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.45;transform:scale(.7)}}

/* ── buttons: magnetic, light sweep, press, ripple ──────────────────────── */
.cf-btn{
  --mx:0px;--my:0px;
  position:relative;display:inline-flex;align-items:center;justify-content:center;gap:8px;
  min-height:var(--tap);padding:0 20px;border-radius:var(--r-pill);border:1px solid var(--glass-edge-hi);
  background:var(--ink-4);color:var(--ink);cursor:pointer;overflow:hidden;isolation:isolate;
  font:600 14px/1 var(--font-display);letter-spacing:.01em;white-space:nowrap;text-decoration:none;
  transform:translate(var(--mx),var(--my)) scale(var(--press,1));
  transition:transform var(--t-med) var(--ease-spring),box-shadow var(--t-med) var(--ease-out),background var(--t-med),border-color var(--t-med);
  box-shadow:var(--shadow-1);-webkit-tap-highlight-color:transparent;user-select:none;
}
.cf-btn svg{width:18px;height:18px;flex:none}
.cf-btn::after{ /* the light sweep */
  content:'';position:absolute;inset:-2px;z-index:-1;pointer-events:none;
  background:linear-gradient(105deg,transparent 30%,rgb(var(--sheen-rgb) / .38) 46%,rgb(var(--sheen-rgb) / .06) 54%,transparent 64%);
  transform:translateX(-120%);transition:transform 0s;
}
@media (hover:hover){
  .cf-btn:hover{border-color:rgb(var(--glow) / .45);box-shadow:var(--shadow-2),0 0 0 1px rgb(var(--glow) / .18)}
  .cf-btn:hover::after{transform:translateX(120%);transition:transform var(--t-sweep) var(--ease-out)}
}
.cf-btn:active{--press:.95;transition-duration:var(--t-press)}
.cf-btn[disabled],.cf-btn[aria-disabled="true"]{opacity:.45;cursor:not-allowed}
.cf-btn--primary{
  background:var(--molten);color:var(--on-molten);border-color:var(--molten-hi);
  box-shadow:0 1px 0 rgb(var(--sheen-rgb) / .5) inset,0 -2px 0 var(--molten-lo) inset,0 6px 22px rgb(var(--glow) / .32),0 2px 4px rgb(var(--shade) / .4);
  text-shadow:0 1px 0 rgb(var(--sheen-rgb) / .45);
}
@media (hover:hover){
  .cf-btn--primary:hover{box-shadow:0 1px 0 rgb(var(--sheen-rgb) / .55) inset,0 -2px 0 var(--molten-lo) inset,0 10px 34px rgb(var(--glow) / .45),0 2px 4px rgb(var(--shade) / .4);border-color:rgb(var(--sheen-rgb) / .8)}
}
/* The sweep (::after, z-index -1 inside the button's own stacking context)
   always paints UNDER the label; what can still wash the label out is its
   colour. A page's scoped `.page a{color}` (0,1,1) outranks `.cf-btn--primary`
   (0,1,0), so a molten link button took the gold link colour -- gold on gold,
   which read as "washed out" the moment the sheen passed (the docs hero).
   :link/:visited lift the molten label above any such rule. */
a.cf-btn--primary:link,a.cf-btn--primary:visited{color:var(--on-molten)}
.cf-btn--ghost{background:transparent;box-shadow:none}
.cf-btn--ion{background:rgb(var(--ion-rgb) / .08);border-color:rgb(var(--ion-rgb) / .35);color:var(--ion)}
.cf-btn--danger{background:var(--dn-dim);color:var(--dn);border-color:rgb(var(--dn-rgb) / .45)}
@media (hover:hover){.cf-btn--danger:hover{border-color:var(--dn);box-shadow:var(--shadow-2),0 0 0 1px rgb(var(--dn-rgb) / .3)}}
.cf-btn--sm{min-height:36px;padding:0 14px;font-size:13px}
.cf-btn--sm::before{content:'';position:absolute;inset:-4px}   /* 36px pill, 44px to a finger */
.cf-btn--block{width:100%}
.cf-btn--icon{width:var(--tap);padding:0}
.cf-btn--xl{min-height:54px;padding:0 28px;font-size:16px}

/* The ripple CFMotion spawns at the pointer. On a .cf-btn it lives inside
   the button; on any other control it is a fixed overlay clipped to the
   control's own box and radius, so the control itself is never restyled. */
.cf-ripple{
  position:absolute;border-radius:50%;pointer-events:none;z-index:-1;transform:translate(-50%,-50%) scale(0);
  background:radial-gradient(circle,rgb(var(--sheen-rgb) / .55),rgb(var(--sheen-rgb) / 0) 70%);
  animation:cf-ripple var(--t-ripple) var(--ease-out) forwards;
}
.cf-ripple-host{position:fixed;overflow:hidden;pointer-events:none;z-index:var(--z-popover)}
.cf-ripple-host .cf-ripple{z-index:0;background:radial-gradient(circle,rgb(var(--sheen-rgb) / .32),rgb(var(--sheen-rgb) / 0) 70%)}
@keyframes cf-ripple{to{transform:translate(-50%,-50%) scale(1);opacity:0}}

/* Product controls that were drawn as a flat gold fill before Noir: CFMotion
   marks each one whose computed fill IS the theme's --acc with .cf-molten,
   and it takes the molten fill and the sweep. Nothing is restyled by a
   colour literal, and a control the page later repaints keeps its own look. */
.cf-molten{
  background-image:linear-gradient(105deg,transparent 30%,rgb(var(--sheen-rgb) / .38) 46%,rgb(var(--sheen-rgb) / .06) 54%,transparent 64%),var(--molten)!important;
  background-size:300% 100%,100% 100%!important;
  background-position:100% 0,0 0!important;
  background-repeat:no-repeat!important;
  color:var(--on-molten)!important;
  border-color:var(--molten-hi)!important;
  text-shadow:0 1px 0 rgb(var(--sheen-rgb) / .45);
  box-shadow:0 1px 0 rgb(var(--sheen-rgb) / .5) inset,0 -2px 0 var(--molten-lo) inset,0 6px 22px rgb(var(--glow) / .28);
  transition:background-position var(--t-sweep) var(--ease-out),box-shadow var(--t-med) var(--ease-out),scale var(--t-press);
}
@media (hover:hover){
  .cf-molten:hover{background-position:0 0,0 0!important;box-shadow:0 1px 0 rgb(var(--sheen-rgb) / .55) inset,0 -2px 0 var(--molten-lo) inset,0 10px 34px rgb(var(--glow) / .45)}
}
.cf-molten:disabled,.cf-molten[aria-disabled="true"]{box-shadow:none}
/* press: the individual `scale` property, so it composes with whatever
   transform the control already has (a centred FAB keeps its translate) */
.cf-pressing{scale:.95;transition:scale var(--t-press) var(--ease-out)}

/* ── chips ──────────────────────────────────────────────────────────────── */
.cf-chip{
  display:inline-flex;align-items:center;gap:6px;height:24px;padding:0 9px;border-radius:var(--r-pill);
  background:rgb(var(--tint) / .05);border:1px solid var(--glass-edge);color:var(--ink2);
  font:600 10.5px/1 var(--font-mono);letter-spacing:.08em;text-transform:uppercase;white-space:nowrap;
}
.cf-chip i{width:6px;height:6px;border-radius:50%;background:var(--chain,var(--gold-400));box-shadow:0 0 8px var(--chain,transparent)}
.cf-chip--gold{color:var(--accent-text-strong);border-color:rgb(var(--glow) / .35);background:rgb(var(--glow) / .12)}
.cf-chip--ion{color:var(--ion);border-color:rgb(var(--ion-rgb) / .35);background:var(--ion-dim)}
.cf-chip--up{color:var(--up);border-color:rgb(var(--up-rgb) / .3);background:var(--up-dim)}
.cf-chip--dn{color:var(--dn);border-color:rgb(var(--dn-rgb) / .3);background:var(--dn-dim)}
button.cf-chip{cursor:pointer;min-height:32px;height:auto;padding:6px 12px;position:relative;transition:background var(--t-fast),color var(--t-fast),border-color var(--t-fast)}
button.cf-chip::before{content:'';position:absolute;inset:-6px -2px}
button.cf-chip[aria-pressed="true"]{color:var(--accent-text-strong);border-color:rgb(var(--glow) / .55);background:rgb(var(--glow) / .2)}
@media (hover:hover){button.cf-chip:hover{color:var(--ink);border-color:var(--glass-edge-hi)}}
.cf-chip[data-chain="solana"]{--chain:var(--chain-solana)}
.cf-chip[data-chain="base"]{--chain:var(--chain-base)}
.cf-chip[data-chain="bsc"]{--chain:var(--chain-bsc)}
.cf-chip[data-chain="arbitrum"]{--chain:var(--chain-arbitrum)}
.cf-chip[data-chain="polygon"]{--chain:var(--chain-polygon)}
.cf-chip[data-chain="robinhood"]{--chain:var(--chain-robinhood)}
.cf-chip[data-chain="ethereum"]{--chain:var(--chain-ethereum)}
.cf-chip[data-chain="monad"]{--chain:var(--chain-monad)}
.cf-chip[data-chain="hyperevm"]{--chain:var(--chain-hyperevm)}

/* ── avatars + token marks: API image over a designed fallback ──────────── */
.cf-ava{
  --s:40px;position:relative;flex:none;width:var(--s);height:var(--s);border-radius:50%;
  display:grid;place-items:center;overflow:hidden;color:var(--on-molten);
  font:700 calc(var(--s) * .4)/1 var(--font-display);background:var(--monogram,var(--molten));
  box-shadow:0 0 0 1px rgb(var(--tint) / .16),0 3px 10px rgb(var(--shade) / .45);
}
.cf-ava img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.cf-ava-wrap{position:relative;flex:none}
.cf-ava-wrap .cf-medal,.cf-medal-slot{position:absolute;right:-6px;bottom:-6px;line-height:0}
.cf-medal-slot:empty{display:none}
.cf-tok{
  --s:36px;position:relative;flex:none;width:var(--s);height:var(--s);border-radius:calc(var(--s) * .3);overflow:hidden;
  display:grid;place-items:center;background:var(--ink-4);box-shadow:0 0 0 1px var(--glass-edge-hi),var(--shadow-1);
}
.cf-tok svg{width:100%;height:100%}
.cf-tok img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.cf-faces{display:inline-flex}
.cf-faces .cf-ava{--s:22px;margin-left:-7px;box-shadow:0 0 0 2px var(--ink-3)}
.cf-faces .cf-ava:first-child{margin-left:0}

/* ── rank medallion (CFGame.medal draws the SVG) ────────────────────────── */
.cf-medal{display:inline-block;flex:none;line-height:0;filter:drop-shadow(0 3px 6px rgb(var(--shade) / .55))}
.cf-medal svg{display:block;overflow:visible}
.cf-medal .cf-sheen{transform:translateX(-140%) skewX(-18deg);transform-box:fill-box}
@media (hover:hover){
  .cf-medal:hover .cf-sheen,.cf-medal-host:hover .cf-sheen{transform:translateX(260%) skewX(-18deg);transition:transform 900ms var(--ease-out)}
}
.cf-medal.is-shining .cf-sheen{transform:translateX(260%) skewX(-18deg);transition:transform 900ms var(--ease-out)}

/* ── segmented tabs with a sliding molten indicator ─────────────────────── */
.cf-tabs{position:relative;display:inline-flex;gap:2px;padding:4px;border-radius:var(--r-pill);background:var(--ink-2);border:1px solid var(--glass-edge);max-width:100%;overflow-x:auto;scrollbar-width:none}
.cf-tabs::-webkit-scrollbar{display:none}
.cf-tab{position:relative;z-index:1;min-height:36px;padding:0 14px;border:0;border-radius:var(--r-pill);background:transparent;color:var(--ink2);cursor:pointer;font:600 13px/1 var(--font-display);white-space:nowrap;transition:color var(--t-med)}
.cf-tab::before{content:'';position:absolute;inset:-4px 0}
.cf-tab[aria-selected="true"]{color:var(--on-molten)}
@media (hover:hover){.cf-tab:not([aria-selected="true"]):hover{color:var(--ink)}}
.cf-tabs-ind{position:absolute;z-index:0;top:4px;bottom:4px;left:0;width:0;border-radius:var(--r-pill);background:var(--molten);box-shadow:0 4px 14px rgb(var(--glow) / .35);transition:transform var(--t-med) var(--ease-spring),width var(--t-med) var(--ease-out)}

/* ── card ───────────────────────────────────────────────────────────────── */
.cf-card{
  position:relative;padding:var(--sp-4);border-radius:var(--r-lg);
  background:linear-gradient(180deg,rgb(var(--raise) / .9),rgb(var(--raise) / .92));
  border:1px solid var(--glass-edge);box-shadow:var(--shadow-2);
  transition:transform var(--t-med) var(--ease-out),border-color var(--t-med),box-shadow var(--t-med);
}
@media (hover:hover){.cf-card.is-lift:hover,a.cf-card:hover{transform:translateY(-2px);border-color:rgb(var(--glow) / .22);box-shadow:var(--shadow-3)}}
.cf-card.is-new{animation:cf-arrive 700ms var(--ease-out)}
@keyframes cf-arrive{0%{box-shadow:0 0 0 1px var(--ion),0 0 30px rgb(var(--ion-rgb) / .35)}100%{box-shadow:var(--shadow-2)}}
.cf-well{padding:12px;border-radius:var(--r-md);background:var(--well);border:1px solid rgb(var(--tint) / .04)}

/* ── empty state: an engraved vault door, gently turning ────────────────── */
.cf-noir-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;padding:28px 16px;text-align:center;color:var(--ink3);font-size:13.5px}
.cf-noir-empty svg{width:54px;height:54px;opacity:.9}
.cf-noir-empty b{color:var(--ink2);font-weight:600}
.cf-empty-dial{transform-origin:32px 32px;animation:cf-dial 9s var(--ease-in-out) infinite alternate}
@keyframes cf-dial{from{transform:rotate(-30deg)}to{transform:rotate(60deg)}}

/* ── skeleton: shaped like what replaces it ─────────────────────────────── */
.cf-skel-noir,.cf-shimmer{position:relative;overflow:hidden;border-radius:var(--r-md);background:rgb(var(--tint) / .04);min-height:18px}
.cf-skel-noir::after,.cf-shimmer::after{content:'';position:absolute;inset:0;transform:translateX(-100%);background:linear-gradient(90deg,transparent,rgb(var(--tint) / .06),transparent);animation:cf-sweep 1.4s infinite}
@keyframes cf-sweep{to{transform:translateX(100%)}}

/* ── sheet: bottom sheet on a phone, drawer from 900px ──────────────────── */
.cf-scrim{position:fixed;inset:0;z-index:var(--z-sheet);background:rgb(var(--scrim-rgb) / .66);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);animation:cf-enter-fade var(--t-med) var(--ease-out)}
.cf-sheet{
  position:fixed;z-index:calc(var(--z-sheet) + 1);left:0;right:0;bottom:0;max-height:88vh;overflow:auto;overscroll-behavior:contain;
  padding:10px var(--sp-5) calc(var(--sp-6) + env(safe-area-inset-bottom,0px));border-radius:var(--r-xl) var(--r-xl) 0 0;
  background:linear-gradient(180deg,var(--sheet-hi),var(--sheet-lo));border:1px solid var(--glass-edge-hi);border-bottom:0;box-shadow:var(--shadow-3);
  color:var(--ink);animation:cf-sheet-up var(--t-slow) var(--ease-spring);touch-action:pan-y;
}
.cf-sheet.is-closing{animation:cf-sheet-down 240ms var(--ease-in-out) forwards}
@keyframes cf-sheet-up{from{transform:translateY(100%)}to{transform:none}}
@keyframes cf-sheet-down{to{transform:translateY(105%)}}
.cf-sheet-grab{width:44px;height:5px;margin:0 auto 14px;border-radius:3px;background:var(--ink-5)}
.cf-sheet h2{margin:0 0 4px;font:700 22px/1.2 var(--font-display);letter-spacing:-.02em}
.cf-sheet-sub{margin:0 0 var(--sp-4);color:var(--ink2);font-size:14px}
.cf-sheet-actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:var(--sp-4)}
.cf-sheet-actions .cf-btn{flex:1 1 160px}
@media (min-width:900px){
  .cf-sheet{left:auto;top:0;width:440px;max-height:none;border-radius:var(--r-xl) 0 0 var(--r-xl);border-bottom:1px solid var(--glass-edge-hi);border-right:0;padding-top:var(--sp-6);animation-name:cf-drawer-in}
  .cf-sheet.is-closing{animation-name:cf-drawer-out}
  .cf-sheet-grab{display:none}
}
@keyframes cf-drawer-in{from{transform:translateX(100%)}to{transform:none}}
@keyframes cf-drawer-out{to{transform:translateX(105%)}}

/* ── overlay: a centred moment (rank-up) ────────────────────────────────── */
.cf-overlay{
  position:fixed;inset:0;z-index:var(--z-overlay);display:grid;place-items:center;padding:20px;
  background:radial-gradient(circle at 50% 45%,rgb(var(--glow) / .22),rgb(var(--scrim-rgb) / .82) 60%);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);animation:cf-enter-fade 320ms var(--ease-out);
}
.cf-overlay.is-out{opacity:0;transition:opacity 240ms}
@keyframes cf-noir-pop{from{transform:scale(.7);opacity:0}to{transform:none;opacity:1}}

/* ── fields, inputs, presets, switch ────────────────────────────────────── */
.cf-field{display:grid;gap:6px;margin:12px 0}
.cf-field label,.cf-field>span{font:600 var(--fs-micro)/1 var(--font-mono);letter-spacing:var(--tr-caps);text-transform:uppercase;color:var(--ink3)}
.cf-presets{display:flex;gap:8px;flex-wrap:wrap}
.cf-input{
  min-height:var(--tap);padding:0 14px;border-radius:var(--r-md);background:var(--ink-2);border:1px solid var(--glass-edge-hi);
  color:var(--ink);font:500 16px/1 var(--font-mono);width:100%;box-sizing:border-box;
  transition:border-color var(--t-fast),box-shadow var(--t-fast);
}
.cf-input:focus-visible{outline:none;border-color:var(--gold-400);box-shadow:0 0 0 3px rgb(var(--glow) / .2)}
.cf-switch{position:relative;flex:none;width:52px;height:30px;padding:0;border-radius:15px;border:1px solid var(--glass-edge-hi);background:var(--ink-2);cursor:pointer;transition:background var(--t-med),border-color var(--t-med)}
.cf-switch::before{content:'';position:absolute;inset:-8px -4px}
.cf-switch i{position:absolute;top:3px;left:3px;width:22px;height:22px;border-radius:50%;background:var(--ink3);box-shadow:var(--shadow-1);transition:transform var(--t-med) var(--ease-spring),background var(--t-med)}
.cf-switch[aria-checked="true"]{background:rgb(var(--glow) / .25);border-color:rgb(var(--glow) / .6)}
.cf-switch[aria-checked="true"] i{transform:translateX(22px);background:var(--molten);box-shadow:0 0 12px rgb(var(--glow) / .6)}

/* ── table ──────────────────────────────────────────────────────────────── */
.cf-table-wrap{overflow-x:auto;max-width:100%}
.cf-table{width:100%;border-collapse:separate;border-spacing:0;font-size:13.5px}
.cf-table th{text-align:left;padding:0 10px 10px;font:600 10px/1 var(--font-mono);letter-spacing:.14em;text-transform:uppercase;color:var(--ink3);border-bottom:1px solid var(--glass-edge);white-space:nowrap}
.cf-table td{padding:12px 10px;border-bottom:1px solid rgb(var(--tint) / .05);vertical-align:middle}
.cf-table tbody tr{transition:background var(--t-fast)}
.cf-table tbody tr:hover{background:rgb(var(--tint) / .03)}
.cf-table .r{text-align:right;font-family:var(--font-mono);font-variant-numeric:tabular-nums}
.cf-cell-p{display:inline-flex;align-items:center;gap:8px;font-weight:600}

/* ── progress bar (curve, season, XP) ───────────────────────────────────── */
.cf-bar{position:relative;display:block;height:6px;border-radius:3px;background:rgb(var(--tint) / .06);overflow:hidden}
.cf-bar i{position:absolute;inset:0 auto 0 0;width:0;border-radius:inherit;background:var(--molten);box-shadow:0 0 10px rgb(var(--glow) / .5);transition:width 900ms var(--ease-out)}
.cf-bar.is-ion i{background:linear-gradient(90deg,rgb(var(--ion-rgb) / .3),var(--ion));box-shadow:var(--ion-glow)}

/* ── headings ───────────────────────────────────────────────────────────── */
.cf-eyebrow{display:inline-flex;align-items:center;gap:10px;font:600 var(--fs-micro)/1 var(--font-mono);letter-spacing:.22em;text-transform:uppercase;color:var(--accT)}
.cf-eyebrow::before{content:'';width:26px;height:1px;background:linear-gradient(90deg,transparent,var(--gold-400))}
.cf-h1{margin:0;font:var(--fw-h1) var(--fs-h1)/var(--lh-h1) var(--font-display);letter-spacing:var(--tr-h1)}
.cf-h2{margin:10px 0 8px;font:var(--fw-h2) var(--fs-h2)/var(--lh-h2) var(--font-display);letter-spacing:var(--tr-h2)}
.cf-lede{margin:0;max-width:60ch;color:var(--ink2);font-size:16px}

/* ── house-account badge (house_accounts.py): "House bot" / "Official" beside
   the name of a platform account, on every surface that shows a person. The
   payload decides (account_kind); static/cf-house.js draws it. ─────────── */
.cf-house{display:inline-flex;align-items:center;gap:4px;height:18px;max-width:max-content;padding:0 7px;border-radius:var(--r-full);
  font:700 9.5px/1 var(--font-mono);letter-spacing:.08em;text-transform:uppercase;white-space:nowrap;vertical-align:middle;
  color:var(--accent-text-strong);border:1px solid rgb(var(--glow) / .38);background:rgb(var(--glow) / .13);flex:none}
.cf-house svg{width:10px;height:10px;flex:none}
.cf-house--official{color:var(--on-molten);border-color:transparent;background:var(--molten)}
[data-theme="light"] .cf-house{color:var(--accT)}
.cf-house-note{margin:6px 0 0;font:500 13px/1.5 var(--font-ui);color:var(--ink2)}
.cf-house-note b{color:var(--ink);font-weight:700}
.cf-house-group{margin-top:14px;padding-top:10px;border-top:1px solid var(--glass-edge)}
.cf-house-group-h{display:flex;align-items:center;gap:8px;margin:0 0 6px;font:600 var(--fs-micro)/1 var(--font-mono);letter-spacing:.14em;text-transform:uppercase;color:var(--ink3)}

/* ── reduced motion: the finished state ─────────────────────────────────── */
@media (prefers-reduced-motion:reduce){
  .cf-live::before,.cf-skel-noir::after,.cf-shimmer::after,.cf-empty-dial{animation:none}
  .cf-btn,.cf-card,.cf-tabs-ind,.cf-bar i,.cf-switch,.cf-switch i,.cf-molten,.cf-pressing{transition:none}
  .cf-btn::after{display:none}
  .cf-ripple{display:none}
  .cf-btn{transform:none}
  .cf-sheet,.cf-scrim,.cf-overlay,.cf-card.is-new{animation:none}
  .cf-molten:hover{background-position:100% 0,0 0!important}
}

/* ── brand marks: a chain's or launchpad's real logo BESIDE its name ─────── */
/* (owner, 2026-10-13; brand_logos.py + cf-brand.js). Fixed box, so nothing
   shifts while it loads; the dot above stays only where no mark exists. A
   project that publishes its mark only as mono white / mono black ships both
   files: --dark is drawn on the dark theme, --light on the light one. */
.cf-logo{flex:none;display:inline-block;width:14px;height:14px;object-fit:contain;vertical-align:-2px;border-radius:3px;background:transparent}
.cf-chip .cf-logo{width:12px;height:12px;margin-left:-2px;vertical-align:-1px}
.cf-logo--lg{width:20px;height:20px;border-radius:5px}
.cf-logo--light{display:none}
.cf-logo-slot{display:none}   /* a dot-less placeholder cf-brand.js fills once the registry answers */
[data-theme="light"] .cf-logo--dark{display:none}
[data-theme="light"] .cf-logo--light{display:inline-block}
/* The Mini App outside Telegram follows a light OS theme with body.cf-light and no
   data-theme attribute: the light-theme mark must follow it there too. */
.cf-light .cf-logo--dark{display:none}
.cf-light .cf-logo--light{display:inline-block}
/* A pale mark (HyperEVM mint) vanishes on the light ground: it sits on a neutral dark plate from the tokens. */
[data-theme="light"] .cf-logo[src*="/chains/hyperevm"]{background:var(--ink-0);padding:1px;border-radius:50%}
[aria-disabled="true"] .cf-logo,[disabled] .cf-logo{opacity:.7}

/* ── Alive: XP chip, streak flame, season strip, success check (2026-10-14) ─
 * Fed by cf-toast.js's pulse. The resting state is the finished one; every
 * motion runs on a CHANGE only and not under prefers-reduced-motion. */
.cf-xpchip-wrap{position:relative;flex:none;margin-left:8px}
.cf-xpchip{position:relative;display:inline-flex;align-items:center;gap:6px;min-height:36px;padding:0 12px;border-radius:var(--r-pill,999px);
  border:1px solid var(--glass-edge-hi);background:var(--glass-bg,rgb(var(--sheen-rgb) / .06));color:var(--ink);font:600 12px/1 var(--font-mono);cursor:pointer}
.cf-xpchip b{font-weight:700}
.cf-xpchip small{color:var(--ink3);font-size:10px;letter-spacing:.08em}
.cf-xpchip:hover{border-color:var(--gold-300)}
.cf-xpchip:focus-visible{outline:2px solid var(--gold-300);outline-offset:2px}
.cf-xpchip-sep{width:1px;height:14px;background:var(--glass-edge-hi)}
.cf-flame{display:inline-grid;place-items:center;width:16px;height:16px;color:var(--ink3)}
.cf-flame svg{width:16px;height:16px}
.cf-flame.on{color:var(--gold-300);filter:drop-shadow(0 0 6px rgb(var(--glow) / .6))}
.cf-flame.risk{color:var(--ember,var(--gold-300))}
.cf-xpchip-pop{position:absolute;right:6px;top:-4px;pointer-events:none;color:var(--gold-200,var(--gold-300));font:700 12px/1 var(--font-mono)}
.cf-xpchip-pop.go{animation:cf-xp-pop .9s var(--ease-out) forwards}
.cf-xpchip.bump{animation:cf-xp-bump .5s var(--ease-spring)}
@keyframes cf-xp-pop{0%{opacity:0;transform:translateY(6px) scale(.8)}20%{opacity:1}100%{opacity:0;transform:translateY(-20px) scale(1.1)}}
@keyframes cf-xp-bump{0%{transform:scale(1)}40%{transform:scale(1.08)}100%{transform:scale(1)}}
.cf-xpp{position:absolute;right:0;top:calc(100% + 8px);z-index:var(--z-pop,9400);width:min(300px,calc(100vw - 32px));padding:14px;border-radius:var(--r-lg,16px);
  border:1px solid var(--glass-edge-hi);background:linear-gradient(180deg,var(--sheet-hi),var(--sheet-lo));box-shadow:var(--shadow-3);color:var(--ink)}
.cf-xpp[hidden]{display:none}
.cf-xpp-rank{display:flex;align-items:center;gap:10px}
.cf-xpp-rank b{display:block;font:700 16px/1.1 var(--font-display)}
.cf-xpp-rank small{color:var(--ink3);font:600 11px var(--font-mono)}
.cf-xpbar{height:8px;border-radius:99px;background:rgb(var(--sheen-rgb) / .1);overflow:hidden;margin:12px 0 6px}
.cf-xpbar i{display:block;height:100%;border-radius:99px;background:var(--molten-text,var(--gold-300));transition:width .7s var(--ease-out)}
.cf-xpbar i.glint{animation:cf-xp-glint .9s var(--ease-out)}
@keyframes cf-xp-glint{0%{filter:brightness(1.9)}100%{filter:none}}
.cf-xpp-next,.cf-xpp-season{margin:0 0 10px;font:500 12px/1.4 var(--font-body);color:var(--ink2)}
.cf-xpp-season{margin:8px 0 0}
.cf-xpp-streak{display:flex;align-items:center;gap:10px;padding-top:10px;border-top:1px solid var(--glass-edge-hi)}
.cf-xpp-streak b{display:block;font:700 13px var(--font-display)}
.cf-xpp-streak small{display:block;color:var(--ink3);font:500 11px/1.3 var(--font-body)}
.cf-xpp-streak .cf-flame{width:22px;height:22px}.cf-xpp-streak .cf-flame svg{width:22px;height:22px}
.cf-xpp-week{margin-left:auto;display:flex;gap:3px}
.cf-xpp-week i{width:7px;height:7px;border-radius:50%;background:rgb(var(--sheen-rgb) / .16)}
.cf-xpp-week i.on{background:var(--gold-300)}
.cf-xpp-week i.today{outline:1px solid var(--gold-300);outline-offset:1px}
@media (max-width:1024px){.cf-xpchip{min-height:44px}}
@media (max-width:640px){.cf-xpchip{padding:0 9px}.cf-xpchip small{display:none}}
/* the season strip on the feed */
.cf-race{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:10px 14px;border-radius:var(--r-lg,16px);border:1px solid var(--glass-edge-hi);
  background:var(--glass-bg,rgb(var(--sheen-rgb) / .05));font:500 13px var(--font-body);color:var(--ink2)}
.cf-race[hidden]{display:none}
.cf-race-k{font:600 var(--fs-micro,10px) var(--font-mono);letter-spacing:var(--tr-caps,.1em);text-transform:uppercase;color:var(--ink3)}
.cf-race-pos{font:700 20px/1 var(--font-display);color:var(--ink)}
.cf-race-track{flex:1 1 80px;min-width:80px;height:6px;border-radius:99px;background:rgb(var(--sheen-rgb) / .1);overflow:hidden}
.cf-race-track i{display:block;height:100%;background:var(--molten-text,var(--gold-300));border-radius:99px;transition:width .8s var(--ease-out)}
.cf-race-pts{font:600 12px var(--font-mono);color:var(--ink)}
.cf-race-link{color:var(--gold-300);font:600 12px var(--font-mono);text-decoration:none}
.cf-race.moved .cf-race-pos{animation:cf-xp-bump .7s var(--ease-spring);color:var(--gold-200,var(--gold-300))}
/* success check drawn on a confirmed trade / copy (sheets add .cf-check) */
.cf-check{display:inline-block;width:56px;height:56px;color:var(--ok,var(--gold-300))}
.cf-check circle,.cf-check path{fill:none;stroke:currentColor;stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round}
.cf-check circle{stroke-dasharray:151;stroke-dashoffset:0}
.cf-check path{stroke-dasharray:40;stroke-dashoffset:0}
.cf-check.draw circle{animation:cf-draw .55s var(--ease-out) both}
.cf-check.draw path{animation:cf-draw .4s var(--ease-out) .35s both}
@keyframes cf-draw{from{stroke-dashoffset:151}to{stroke-dashoffset:0}}
/* staggered arrival: the class is added from script and removed on end */
.cf-arrive{animation:cf-arrive .5s var(--ease-out) both;animation-delay:calc(var(--i,0) * 55ms)}
@keyframes cf-arrive{from{transform:translateY(10px)}to{transform:none}}
@media (prefers-reduced-motion:reduce){
  .cf-xpchip-pop.go,.cf-xpchip.bump,.cf-xpbar i.glint,.cf-race.moved .cf-race-pos,.cf-check.draw circle,.cf-check.draw path,.cf-arrive{animation:none}
  .cf-xpbar i,.cf-race-track i{transition:none}
}


/* ---- static/cf-charts.css ---- */
/* Cartel Family — shared chart primitives (see cf-charts.js), dressed in
   Syndicate Noir (COMPONENTS.md §16): every line carries a two-step glow
   trail in its own colour, the end point is a 9px dot ringed in the ground
   with the shared pulse, the readouts are glass with a gold edge. Tokens
   only; the line colour itself comes from cf-charts.js (read off <body>). */

/* the glow trail: the path's `color` is its stroke (set by cf-charts.js) */
.cf-line{filter:drop-shadow(0 0 4px color-mix(in srgb,currentColor 55%,transparent)) drop-shadow(0 0 12px color-mix(in srgb,currentColor 35%,transparent))}
.cf-line--spark{filter:drop-shadow(0 0 3px color-mix(in srgb,currentColor 50%,transparent))}

.cf-chart{position:relative;width:100%}
.cf-chart-svg{display:block;width:100%;height:100%;overflow:visible}

/* The tooltip is an HTML element rather than SVG text: it needs to stay
   upright and legibly sized while the SVG itself is stretched by
   preserveAspectRatio:none, which would distort any text drawn inside it. */
.cf-chart-tip{
  /* The design's readout: 132px wide, value over clock time, centred. */
  position:absolute;top:-6px;transform:translateX(-50%);box-sizing:border-box;
  width:132px;text-align:center;
  pointer-events:none;opacity:0;transition:opacity var(--t-fast,.13s);
  background:var(--glass-strong);border:1px solid rgb(var(--glow) / .3);border-radius:var(--r-sm);
  padding:6px 9px;white-space:nowrap;z-index:5;
  box-shadow:var(--shadow-3);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
}
.cf-chart-tip.on{opacity:1}
.cf-chart-tip b{
  display:block;color:var(--ink);font:500 12px/1.3 var(--font-num);
  font-variant-numeric:tabular-nums;overflow:hidden;text-overflow:ellipsis;
}
.cf-chart-tip i{display:block;color:var(--ink2);font:500 10px/1.3 var(--font-num);font-style:normal;margin-top:1px}

.cf-chart-end{position:absolute;width:7px;height:7px;border-radius:50%;
  transform:translate(-50%,-50%);pointer-events:none;z-index:2;
  box-shadow:0 0 0 3px rgb(var(--ground-rgb) / .85),0 0 14px currentColor;width:9px;height:9px}
/* The live pulse (cf-charts.js addPulse): a ring the size of the dot, grown
   and faded by ONE requestAnimationFrame loop for the page -- transform and
   opacity only. At rest it is invisible decoration; the dot is the mark. */
.cf-pulse-ring{position:absolute;inset:0;border-radius:50%;opacity:0;
  pointer-events:none;will-change:transform,opacity;transform-origin:50% 50%}
.cf-spark-end{position:absolute;width:5px;height:5px;border-radius:50%;
  transform:translate(-50%,-50%);pointer-events:none;z-index:2}
/* The latest value on the right edge (opts.lastLabel); slides with the line. */
.cf-chart-last{position:absolute;right:0;transform:translateY(-50%);z-index:3;
  font:600 11px/1.3 var(--font-num);color:var(--onAcc);
  padding:2px 6px;border-radius:6px;white-space:nowrap;pointer-events:none;
  font-variant-numeric:tabular-nums}
/* A redraw with a new series cross-fades: the old drawing on top, fading. */
.cf-chart-ghost{position:absolute;inset:0;pointer-events:none;z-index:1}

/* Label of the dashed gold entry line (CFCharts.area opts entry + entryLabel). */
.cf-chart-entry{
  position:absolute;left:8px;transform:translateY(-100%);margin-top:-4px;
  font:600 11px/1.3 var(--font-num);color:var(--onAcc);background:var(--acc);
  padding:2px 6px;border-radius:6px;white-space:nowrap;pointer-events:none;
}

/* Candles: OHLC readout top-left; the price under the pointer shown as
   gold pill on the right edge. */
.cf-ohlc{
  position:absolute;left:8px;top:8px;display:flex;gap:12px;flex-wrap:wrap;
  font:500 12px/1.3 var(--font-num);color:var(--ink2);background:var(--glass-strong);
  border:1px solid rgb(var(--glow) / .3);border-radius:var(--r-sm);padding:6px 10px;
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  pointer-events:none;opacity:0;transition:opacity .13s;z-index:4;max-width:calc(100% - 16px);
}
.cf-ohlc.on{opacity:1}
.cf-ohlc b{font-weight:500}
.cf-ohlc b.up{color:var(--up)}
.cf-ohlc b.down{color:var(--dn)}
.cf-chart-pricepill{
  position:absolute;right:0;transform:translateY(-50%);
  font:600 11px/1.3 var(--font-num);color:var(--onAcc);background:var(--acc);
  padding:3px 6px;border-radius:6px;pointer-events:none;opacity:0;z-index:4;
}
.cf-chart-pricepill.on{opacity:1}
.cf-candles{cursor:crosshair;touch-action:pan-y;user-select:none}

.cf-chart-empty{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:7px;min-height:120px;height:100%;color:var(--muted);
  font-size:12px;text-align:center;padding:18px 12px;
}
.cf-chart-empty svg{opacity:.5}

.cf-spark{display:block;width:100%;line-height:0}
/* The spark readout sits above the line so a finger does not cover it. */
.cf-spark{position:relative}
.cf-spark-tip{top:auto;bottom:calc(100% + 4px);padding:3px 7px;width:auto;min-width:0}
.cf-spark-tip b{font-size:11.5px}
.cf-spark-svg{display:block;width:100%;height:100%}

/* donut */
.cf-donut{display:flex;flex-direction:column;align-items:center;gap:12px}
.cf-donut-svg{display:block;width:168px;height:168px;max-width:100%}
.cf-donut-center{
  position:absolute;top:0;left:50%;transform:translateX(-50%);
  width:168px;height:168px;display:flex;flex-direction:column;
  align-items:center;justify-content:center;pointer-events:none;
}
.cf-donut-center b{
  color:var(--text);font-size:17px;font-weight:600;letter-spacing:-.02em;
  font-family:var(--font-mono);
}
.cf-donut-center i{color:var(--muted);font-size:10px;font-style:normal;
  text-transform:uppercase;letter-spacing:.12em;margin-top:2px}
.cf-donut-legend{display:flex;flex-wrap:wrap;gap:8px 14px;justify-content:center;width:100%}
.cf-dl-item{display:inline-flex;align-items:center;gap:6px;font-size:11px;color:var(--muted)}
.cf-dl-item i{width:8px;height:8px;border-radius:2px;flex:0 0 8px}
.cf-dl-item b{color:var(--text);font-weight:700;
  font-family:var(--font-mono)}

/* A card wrapper pages can reuse so charts sit consistently. */
.cf-chart-card{
  position:relative;border-radius:var(--r-lg);padding:16px 18px 14px;
  background:linear-gradient(180deg,rgb(var(--raise) / .66),rgb(var(--raise) / .72) 38%,var(--glass));
  border:1px solid var(--glass-edge);box-shadow:var(--shadow-2);
}
.cf-chart-head{display:flex;align-items:baseline;justify-content:space-between;
  gap:10px;margin-bottom:12px;flex-wrap:wrap}
.cf-chart-title{font:600 var(--fs-micro,11px)/1.2 var(--font-mono);letter-spacing:var(--tr-caps,.16em);
  text-transform:uppercase;color:var(--muted)}
.cf-chart-value{font-size:20px;font-weight:600;color:var(--text);letter-spacing:-.02em;
  font-family:var(--font-mono);font-variant-numeric:tabular-nums}
.cf-chart-delta{font-size:11.5px;font-weight:600;font-family:var(--font-mono)}
.cf-chart-delta.up{color:var(--green)}
.cf-chart-delta.down{color:var(--red)}
.cf-chart-delta.flat{color:var(--muted)}

@media (prefers-reduced-motion:reduce){
  .cf-chart-tip,.cf-ohlc{transition:none}
  .cf-pulse-ring,.cf-chart-ghost{display:none}
  .cf-line,.cf-line--spark{filter:none}
}
/* bars(): the optional label row under the slots (opts.ticks). */
.cf-chart-axis{position:relative;height:16px;margin-top:2px}
.cf-chart-axis span{position:absolute;top:0;transform:translateX(-50%);font:500 10px var(--font-num);color:var(--ink3);white-space:nowrap}

/* Keyboard readout (opts.keyboard; always on for heatmap and histogram):
   the chart is focusable and shows a visible focus ring. */
.cf-chart-kb{outline:none;border-radius:8px}
.cf-chart-kb:focus-visible{box-shadow:var(--focus-ring,0 0 0 2px var(--bg),0 0 0 4px var(--accT))}

/* donut(): a hovered / focused legend row (opts.hover). */
.cf-dl-item[tabindex]{cursor:pointer;border-radius:6px;padding:2px 4px;margin:-2px -4px}
.cf-dl-item.on{color:var(--text)}
.cf-dl-item[tabindex]:focus-visible{outline:2px solid var(--accT);outline-offset:1px}

/* heatmap(): squares keep their shape; a long range scrolls in its own box. */
.cf-heat{display:flex;flex-direction:column;gap:8px}
.cf-heat-scroll{overflow-x:auto;overflow-y:hidden;scrollbar-width:thin;padding-top:2px}
.cf-heat-svg{display:block;height:auto}
/* SVG text never wraps; it only must not inherit a nowrap meant for HTML text. */
.cf-heat-svg text{white-space:normal;user-select:none}
.cf-heat-legend{display:flex;align-items:center;gap:3px;justify-content:flex-end;
  font:500 10px var(--font-num);color:var(--ink3)}
.cf-heat-legend span{margin:0 4px}
.cf-heat-legend i{width:10px;height:10px;border-radius:2px;display:inline-block}
.cf-heat-tip{transform:translate(-50%,calc(-100% - 8px));width:auto;min-width:132px;max-width:220px}

/* histogram(): the marker's label rides above the plot. */
.cf-hist{height:100%}
.cf-hist-marker{position:absolute;top:0;transform:translateX(-50%);pointer-events:none;
  font:600 10px/1.3 var(--font-num);color:var(--onAcc);background:var(--acc);
  padding:1px 6px;border-radius:5px;white-space:nowrap}
.cf-hist-axis{height:18px;margin-top:0}


/* ── CFPriceChart (cf-price-chart.js): price pane, volume pane, readout ── */
.cf-pc{position:relative}
.cf-pc-wrap{position:relative;border-radius:12px;overflow:hidden;background:var(--s1)}
.cf-pc{outline:none;border-radius:12px}
.cf-pc:focus-visible{box-shadow:0 0 0 2px var(--bg),0 0 0 4px var(--accT)}
/* Candle mode's live dot: placed by transform on the library's coordinates. */
.cf-pc-dot{position:absolute;left:0;top:0;width:9px;height:9px;border-radius:50%;
  pointer-events:none;z-index:3;box-shadow:0 0 0 3px rgb(var(--ground-rgb) / .85),0 0 14px rgb(var(--glow) / .6)}
.cf-pc-price,.cf-pc-vol{position:relative;width:100%}
.cf-pc-vol{border-top:1px solid var(--line)}
.cf-pc-empty{display:flex;align-items:center;justify-content:center;height:100%;min-height:220px;
  color:var(--ink3);font:500 13px/1.4 var(--font-body);text-align:center;padding:0 16px}
.cf-pc-tip{position:absolute;top:10px;left:12px;z-index:4;pointer-events:none;opacity:0;transform:translateY(-4px);
  transition:opacity var(--t-fast,.14s),transform var(--t-fast,.14s);background:var(--glass-strong);border:1px solid rgb(var(--glow) / .3);border-radius:var(--r-sm);
  padding:7px 10px;box-shadow:var(--shadow-3);max-width:min(92%,420px);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}
.cf-pc-tip.on{opacity:1;transform:none}
.cf-pc-tip.right{left:auto;right:64px}
.cf-pc-tip i{display:block;font:500 10px/1.3 var(--font-num);color:var(--ink3);font-style:normal;letter-spacing:.02em}
.cf-pc-tip b{display:flex;flex-wrap:wrap;gap:4px 10px;font:600 12px/1.4 var(--font-num);color:var(--ink);
  font-variant-numeric:tabular-nums;margin-top:2px}
.cf-pc-tip em{display:inline-block;margin-top:2px;font:600 11px/1.3 var(--font-num);font-style:normal}
.cf-pc-tip em.up{color:var(--up)} .cf-pc-tip em.dn{color:var(--dn)}
.cf-pc-tip small{display:block;margin-top:2px;font:500 10px/1.3 var(--font-num);color:var(--ink2)}
/* Entrance: a left-to-right reveal on first paint, a crossfade on a rebuild.
   Both are added from script and removed on animationend; the resting state
   is fully visible, so a paused tab never leaves a chart hidden. */
.cf-pc-reveal{animation:cfPcReveal var(--t-draw,.7s) var(--ease-out) both}
@keyframes cfPcReveal{from{clip-path:inset(0 100% 0 0);opacity:.6}to{clip-path:inset(0 0 0 0);opacity:1}}
.cf-pc-swap{animation:cfPcSwap var(--t-med,.28s) var(--ease-out) both}
@keyframes cfPcSwap{from{opacity:.25;transform:translateY(4px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.cf-pc-reveal,.cf-pc-swap{animation:none}.cf-pc-tip{transition:none}}


/* ---- static/cf-trade-card.css ---- */
/* Cartel Family — THE trade card (see cf-trade-card.js), SYNDICATE NOIR.
 *
 * Drawn to the reference's person card (/design/a/app#feed, static/design/a
 * noir.css ".na-tc*"): a glass card (cf-card), a person row (44px avatar
 * with its rank medallion, @handle in display type, the rank chip + "68%
 * win · 2m ago" in mono, the side chip on the right -- Bought on the ion
 * accent), the token WELL (40px token mark, $SYM 17px, price · size, and the
 * figure in 20px mono on the right), the 34px curve under it, and the foot:
 * the faces of who else is in it, then Share (ghost icon), Buy (secondary)
 * and Copy (molten primary) -- all three are cf-btn from cf-noir.css.
 *
 * Every colour is a Noir token from cf-theme.css, so both themes come for
 * free. One card at every width; only the foot wraps on a narrow card.
 * Rendered by Home, Discover, Live Market and Calls alike.
 */

.tc{
  container:tc / inline-size;
  position:relative;
  display:flex;flex-direction:column;gap:0;
  padding:var(--sp-4, 16px);
  border-radius:var(--r-lg);
  background:linear-gradient(180deg, rgb(var(--raise) / .9), rgb(var(--raise) / .92));
  border:1px solid var(--glass-edge);
  box-shadow:var(--shadow-2);
  color:var(--text-1);
  font-family:var(--font-body, var(--font-display));
  box-sizing:border-box;
  transition:transform var(--t-med) var(--ease-out), border-color var(--t-med), box-shadow var(--t-med);
}
@media (hover:hover){
  .tc:hover{transform:translateY(-2px);border-color:rgb(var(--glow) / .22);box-shadow:var(--shadow-3)}
}

/* ── person row ────────────────────────────────────────────────────────── */
.tc-who{display:flex;align-items:center;gap:12px;min-width:0}
.tc-person{
  display:flex;align-items:center;gap:12px;min-width:0;flex:1 1 auto;
  color:inherit;text-decoration:none;border-radius:var(--r-md);
}
.tc-person:focus-visible,.tc-tok:focus-visible{outline:2px solid var(--gold-400);outline-offset:2px}
.tc-av-wrap{position:relative;flex:none;line-height:0}
.tc-av{
  width:44px;height:44px;flex:0 0 44px;border-radius:50%;object-fit:cover;
  background:var(--ink-4);display:flex;align-items:center;justify-content:center;
  box-shadow:0 0 0 1px rgb(var(--tint) / .16), 0 3px 10px rgb(var(--shade) / .45);
}
.tc-medal{position:absolute;right:-6px;bottom:-6px;line-height:0}
.tc-medal:empty{display:none}
.tc-ini{font:700 15px/1 var(--font-display);color:var(--on-molten)}
/* Initials discs: the molten monogram the reference draws (warm, never
   candy). The per-wallet hue classes stay for the surfaces that read them. */
.tc .tc-ini{background:var(--molten);color:var(--on-molten)}
.tc-av-empty{background:rgb(var(--tint) / .04);border:1px dashed var(--text-4);color:var(--text-3);box-sizing:border-box;box-shadow:none}
.tc-av-empty svg{width:20px;height:20px}
.tc-id{display:flex;flex-direction:column;gap:3px;min-width:0}
.tc-name-row{display:flex;align-items:center;gap:6px;min-width:0}
.tc-name{
  font:600 15px/1.25 var(--font-display);color:var(--text-1);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;
}
.tc-person:hover .tc-name{color:var(--accent-text-strong)}
.tc-verified{width:13px;height:13px;flex:0 0 13px;color:var(--accent-text)}
.tc-meta{
  display:flex;align-items:center;gap:6px;min-width:0;
  font:500 12px/1.4 var(--font-mono);color:var(--text-3);font-variant-numeric:tabular-nums;
}
.tc-meta-t{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.tc-rankchip{flex:none;display:inline-flex}
.tc-rankchip:empty{display:none}
.is-nobody .tc-name{color:var(--text-2)}
/* the side chip: .cf-chip's shape, uppercase mono */
.tc-pill{
  margin-left:auto;flex:0 0 auto;white-space:nowrap;
  display:inline-flex;align-items:center;height:24px;padding:0 9px;border-radius:var(--r-pill);
  font:600 10.5px/1 var(--font-mono);letter-spacing:.08em;text-transform:uppercase;
  background:rgb(var(--tint) / .05);border:1px solid var(--glass-edge);color:var(--text-2);
}
.tc-pill-bought{color:var(--ion);border-color:rgb(var(--ion-rgb) / .35);background:var(--ion-dim)}
.tc-pill-sold{color:var(--text-2)}
.tc-pill-called,.tc-pill-launched{color:var(--accent-text-strong);border-color:rgb(var(--glow) / .35);background:rgb(var(--glow) / .12)}
.tc-pill-graduated{color:var(--up);border-color:rgb(var(--up-rgb) / .3);background:var(--up-dim)}

/* ── the token well ────────────────────────────────────────────────────── */
.tc-trade{
  display:grid;align-items:center;
  grid-template-columns:minmax(0,1fr) auto;
  column-gap:12px;
  margin:14px 0 12px;padding:12px;
  border-radius:var(--r-md);background:var(--well);border:1px solid rgb(var(--tint) / .04);
}
.tc-tok{display:flex;align-items:center;gap:12px;min-width:0;color:inherit;text-decoration:none;border-radius:var(--r-sm)}
.tc-tok:hover .tc-sym{color:var(--accent-text-strong)}
.tc-logo{
  width:40px;height:40px;flex:0 0 40px;border-radius:12px;object-fit:cover;background:var(--ink-4);
  box-shadow:0 0 0 1px var(--glass-edge-hi), var(--shadow-1);
}
.tc .tc-logo.tc-ini{background:var(--ink-4);color:var(--accent-text-strong);font:700 15px/1 var(--font-display)}
.tc-logo.tc-ini,.tc-face.tc-ini{display:flex;align-items:center;justify-content:center}
.tc-tok-id{display:flex;flex-direction:column;gap:3px;min-width:0}
.tc-sym{
  display:flex;align-items:center;gap:6px;min-width:0;
  font:700 17px/1.1 var(--font-display);letter-spacing:-.01em;color:var(--text-1);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.tc-chain{
  display:inline-flex;align-items:center;height:20px;padding:0 7px;border-radius:var(--r-pill);
  font:600 9.5px/1 var(--font-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--text-2);
  background:rgb(var(--tint) / .05);border:1px solid var(--glass-edge);
}
.tc-px{
  font:500 12px/1.4 var(--font-mono);color:var(--text-3);
  font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.tc-px-v{color:var(--text-2)}
.tc-spark{position:relative;height:34px;min-width:0;margin:-2px 0 10px}
.tc-spark .cf-spark-svg{width:100%;height:100%;overflow:visible}
.tc-spark-none{
  display:flex;align-items:center;justify-content:center;height:100%;
  font:500 11px/1.2 var(--font-mono);color:var(--text-4);text-align:center;
}
.tc-fig{display:flex;flex-direction:column;align-items:flex-end;gap:3px;text-align:right;min-width:0}
.tc-fig-v{
  font:600 20px/1.1 var(--font-mono);font-variant-numeric:tabular-nums;white-space:nowrap;letter-spacing:-.02em;
}
.tc-fig-v.up{color:var(--green);text-shadow:0 0 14px rgb(var(--up-rgb) / .25)}
.tc-fig-v.down{color:var(--dn)}
.tc-fig-v.flat{color:var(--text-1)}
.tc-fig-sub{font:500 11px/1.3 var(--font-mono);color:var(--text-3);white-space:nowrap}

.tc-cap{margin:0 0 12px;font:400 14px/1.5 var(--font-body, var(--font-display));color:var(--text-2)}

/* ── compact market facts (token surfaces) ─────────────────────────────── */
.tc-stats{
  display:grid;grid-template-columns:repeat(4,minmax(0,1fr));margin:0 0 12px;gap:8px;
}
.tc-stats>div{min-width:0;padding:8px 10px;border-radius:var(--r-sm);background:var(--well)}
.tc-stats dt{font:600 10px/1.3 var(--font-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--text-3)}
.tc-stats dd{
  margin:4px 0 0;font:600 13px/1.3 var(--font-mono);color:var(--text-1);
  font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}

/* ── the foot: who else is in it, then the actions ─────────────────────── */
.tc-social{display:flex;align-items:center;gap:10px;flex-wrap:wrap;min-width:0}
.tc-faces{display:inline-flex;align-items:center;flex:0 0 auto}
.tc-face{
  width:22px;height:22px;border-radius:50%;object-fit:cover;background:var(--ink-4);
  box-shadow:0 0 0 2px var(--ink-3);font-size:8px;
}
.tc-face + .tc-face{margin-left:-7px}
.tc-also{
  font:500 12.5px/1.3 var(--font-display);color:var(--text-2);
  min-width:0;flex:1 1 120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.tc-rep{font:500 12px/1.3 var(--font-mono);color:var(--text-3);padding:0 4px;white-space:nowrap;flex:0 0 auto}
.tc-acts{margin-left:auto;display:flex;gap:8px;flex:0 0 auto}
/* The buttons ARE cf-btn (cf-noir.css: magnet, sweep, press, ripple); this
   keeps only what the card adds: the copying state and the disabled one. */
.tc-btn svg{width:16px;height:16px;flex:none}
.tc-btn.cf-btn--icon svg{width:17px;height:17px}
.tc-btn.cf-btn--icon{width:36px;min-width:36px;padding:0;border-color:var(--glass-edge-hi)}
.tc-btn:focus-visible{outline:2px solid var(--gold-400);outline-offset:2px}
.tc-copy.is-copying{
  background:var(--up-dim)!important;color:var(--up)!important;border-color:rgb(var(--up-rgb) / .45)!important;
  box-shadow:none!important;text-shadow:none!important;
}
.tc-copy.is-copying svg{display:none}
.tc-copy:disabled{opacity:.5;cursor:default}

/* ── a launch: the bonding curve inside the well ─────────────────────────
   (launch_feed.py). The bar is the curve's own progress to graduation from
   the pool account; unknown reads "reading curve…", never 0%. */
.tc-launch .tc-trade,.tc-graduated .tc-trade{grid-template-columns:minmax(0,1fr) auto;row-gap:10px}
.tc-launch .tc-tok,.tc-graduated .tc-tok{grid-row:1;grid-column:1}
.tc-launch .tc-fig,.tc-graduated .tc-fig{grid-row:1;grid-column:2}
.tc-curve{grid-row:2;grid-column:1 / -1;display:flex;align-items:center;gap:10px;min-width:0}
.tc-curve-bar{display:block;flex:1 1 auto;min-width:48px;height:6px;border-radius:3px;background:rgb(var(--tint) / .06);overflow:hidden}
.tc-curve-bar i{display:block;height:100%;border-radius:inherit;background:var(--molten);box-shadow:0 0 10px rgb(var(--glow) / .5)}
.tc-curve.is-grad .tc-curve-bar i{background:var(--up);box-shadow:0 0 10px rgb(var(--up-rgb) / .4)}
.tc-curve.is-unknown .tc-curve-bar i{width:100%;background:rgb(var(--tint) / .08);box-shadow:none}
.tc-curve-t{flex:0 1 auto;font:500 11.5px/1.2 var(--font-mono);color:var(--text-2);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;font-variant-numeric:tabular-nums}
.tc-curve.is-grad .tc-curve-t{color:var(--up)}
.tc[data-tc-href]{cursor:pointer}
.tc[data-tc-href] .tc-social{cursor:default}
.tc-buy{min-width:70px}
@media (prefers-reduced-motion:no-preference){
  .tc.tc-in .tc-curve-bar i{animation:tcGrow .6s cubic-bezier(.2,.8,.2,1)}
}
@keyframes tcGrow{from{transform:scaleX(0)}to{transform:none}}
.tc-curve-bar i{transform-origin:left center}

/* A narrow card (a 320-360 phone): the chain chip and price line give way
   before the symbol; the foot wraps its actions onto their own line. */
@container tc (max-width:340px){
  .tc-fig-v{font-size:17px}
  .tc-chain{display:none}
  .tc-curve-t{max-width:62%}
}

/* ── entrance ─────────────────────────────────────────────────────────
   MOVEMENT ONLY, never opacity: app-ux.css pauses animations on a hidden
   tab, and a card parked at opacity 0 waiting for one stays invisible in a
   background tab, a thumbnail or a screenshot (CLAUDE.md). The class is
   added from script, removed on animationend and by a timer, and never
   added under reduced motion. */
@media (prefers-reduced-motion:no-preference){
  .tc.tc-in{animation:tcIn .5s var(--ease-out, cubic-bezier(.2,.8,.2,1))}
}
@media (prefers-reduced-motion:reduce){
  .tc{transition:none}
  .tc:hover{transform:none}
}
@keyframes tcIn{from{transform:translateY(12px)}to{transform:none}}

/* Touch: the person and the token are links, and each is a 44px target.
   The rows pull in by the added height, so the card measures as drawn. */
@media (pointer:coarse){
  .tc-person{min-height:44px;margin-top:-2px;margin-bottom:-2px;}
  .tc-tok{min-height:44px;margin-top:-2px;margin-bottom:-2px;}
}

/* Touch: the actions are 44px boxes, not only 44px hit areas. */
@media (pointer:coarse), (hover:none){
  .tc-btn.cf-btn--sm{ min-height:44px; }
  .tc-btn.cf-btn--icon{ width:44px; min-width:44px; }
}


/* ---- static/home-feed.css ---- */
/* Cartel Family — the Feed (/), SYNDICATE NOIR (2026-10-12).
 *
 * Drawn to the reference feed (/design/a/app#feed; static/design/a/app.css
 * ".na-feed-grid", ".na-side", ".na-mover", ".na-newpill"): one people-first
 * column of person cards (cf-trade-card.css, max 780) beside a 340px live
 * side column of glass panels -- Movers, Top traders, Auto Bot, This season,
 * Top callers -- that drops under the feed below 1180px and off a phone.
 * The product's own pieces stay, restyled: the portfolio strip (a glass
 * panel with its curve), your open positions, the segmented tabs with the
 * molten indicator (cf-tabs; CFMotion.tabs places it), the composer, the
 * paid slot, Load more, and the ion "N new" pill.
 *
 * Every colour is a Noir token; every figure on the page comes from an
 * endpoint (home-feed.js), and each card and chart has a real empty state in
 * the same shape. Nothing rests at opacity 0: entrances are a class added by
 * script and removed when they end, and reduced motion is the finished state. */

.cf-home{ margin:0; background:var(--bg); color:var(--text-1); font-family:var(--font-body, var(--font-display)); }

.hf-wrap{ max-width:1360px; margin:0 auto; padding:6px clamp(16px, 2.6vw, 36px) 40px; box-sizing:border-box; }
.hf-grid{ display:grid; grid-template-columns:minmax(0, 780px) 340px; justify-content:space-between; gap:24px; align-items:start; }
.hf-col-main{ min-width:0; display:flex; flex-direction:column; gap:14px; }
.hf-side{ min-width:0; display:grid; grid-template-columns:minmax(0, 1fr); gap:14px; align-content:start; }

.hf-note{
  background:rgb(var(--ion-rgb) / .06); border:1px solid rgb(var(--ion-rgb) / .22); border-radius:var(--r-md);
  padding:12px 16px; font:500 13.5px/1.4 var(--font-display); color:var(--text-2);
}
.hf-note[hidden]{ display:none; }

/* ── portfolio strip: a glass panel with its curve ────────────────────── */
.hf-pf{
  position:relative; border-radius:var(--r-lg); padding:16px 18px 12px;
  background:linear-gradient(180deg, rgb(var(--raise) / .66), rgb(var(--raise) / .72) 38%, var(--glass));
  border:1px solid var(--glass-edge); box-shadow:var(--shadow-2);
  -webkit-backdrop-filter:blur(var(--blur)) saturate(var(--glass-saturate)); backdrop-filter:blur(var(--blur)) saturate(var(--glass-saturate));
  display:flex; flex-direction:column; gap:8px;
}
.hf-pf-top{ display:flex; align-items:flex-start; gap:12px; flex-wrap:wrap; }
.hf-pf-id{ display:flex; flex-direction:column; gap:6px; flex:1; min-width:180px; }
.hf-pf-k{ align-self:flex-start; font:600 10px/1 var(--font-mono); letter-spacing:.14em; text-transform:uppercase; color:var(--text-3); text-decoration:none; }
.hf-pf-k:hover{ color:var(--accent-text-strong); }
.hf-pf-v{ font:600 30px/1.05 var(--font-mono); letter-spacing:-.03em; color:var(--text-1); font-variant-numeric:tabular-nums; }
.hf-pf-v-guest{ font:600 20px/1.3 var(--font-display); color:var(--text-2); }
.hf-pf-d{ font:600 13px/1 var(--font-mono); color:var(--text-3); font-variant-numeric:tabular-nums; }
.is-guest .hf-pf-d{ font:500 13.5px/1.4 var(--font-display); }
.hf-pf-d.up{ color:var(--up); }
.hf-pf-d.down{ color:var(--dn); }
.hf-pf-rng{ flex:none; }
.hf-pf-rng .hf-rng{ min-height:32px; padding:0 12px; font:600 12px/1 var(--font-mono); letter-spacing:.04em; }
.hf-rng:focus-visible{ outline:2px solid var(--gold-400); outline-offset:2px; }
.hf-pf-chart{ height:64px; position:relative; }
/* The shared empty state has a 120px min-height and 18px padding; in this
   64px box it overflowed, and its caption sat on the card's bottom border. */
.hf-pf-chart .cf-chart-empty{ height:64px; min-height:0; padding:6px 12px; box-sizing:border-box; gap:5px; }
.hf-pf-partial{ font:600 12px/1.4 var(--font-mono); color:var(--pro); }
.hf-pf-partial[hidden]{ display:none; }

/* ── your positions ───────────────────────────────────────────────────── */
/* One sideways row of open positions (home-feed.js loadHolds), the shape
   the Mini App's .tg-holds draws. Hidden until there is something open. */
.hf-holds{ display:flex; flex-direction:column; gap:8px; min-width:0; }
.hf-holds[hidden]{ display:none; }
.hf-holds-head{ display:flex; align-items:center; gap:10px; padding:0 2px; }
.hf-holds-head h2{ margin:0; flex:1; min-width:0; font:600 16px/1.2 var(--font-display); letter-spacing:-.01em; color:var(--text-1); }
.hf-holds-n{ font:500 12px/normal var(--font-mono); color:var(--text-3); margin-left:4px; }
.hf-holds-note{ font:500 12px/normal var(--font-mono); color:var(--text-3); }
.hf-holds-row{
  display:flex; gap:10px; overflow-x:auto; scrollbar-width:none; padding:2px 2px 4px;
  scroll-snap-type:x proximity; overscroll-behavior-x:contain;
}
.hf-holds-row::-webkit-scrollbar{ display:none; }
/* With a mouse there is no swipe: a thin bar says the row scrolls. */
@media (hover:hover) and (pointer:fine){
  .hf-holds-row{ scrollbar-width:thin; scrollbar-color:var(--glass-edge-hi) transparent; padding-bottom:8px; }
  .hf-holds-row::-webkit-scrollbar{ display:block; height:6px; }
  .hf-holds-row::-webkit-scrollbar-thumb{ background:var(--glass-edge-hi); border-radius:3px; }
}
.hf-hold{
  flex:none; display:flex; align-items:center; gap:10px; scroll-snap-align:start;
  padding:8px 8px 8px 12px; border-radius:var(--r-md); background:var(--ink-3); border:1px solid var(--glass-edge);
  max-width:280px; box-sizing:border-box; transition:border-color var(--t-fast), transform var(--t-med) var(--ease-out);
}
@media (hover:hover){ .hf-hold:hover{ border-color:rgb(var(--glow) / .3); transform:translateY(-2px); } }
.hf-hold-main{
  display:flex; align-items:center; gap:10px; min-height:44px; min-width:0;
  color:inherit; text-decoration:none; border-radius:var(--r-sm);
}
a.hf-hold-main:hover .hf-hold-t > b{ color:var(--accent-text-strong); }
.hf-hold-main:focus-visible{ outline:2px solid var(--gold-400); outline-offset:2px; }
.hf-hold-t{ display:flex; flex-direction:column; gap:2px; min-width:0; }
.hf-hold-t > b{ font:600 14px/1.3 var(--font-display); color:var(--text-1); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.hf-hold-ch{ font:600 9.5px/1 var(--font-mono); font-style:normal; color:var(--text-3); letter-spacing:.08em; margin-left:2px; }
.hf-hold-v{ font:600 13px/1.3 var(--font-mono); color:var(--text-1); font-variant-numeric:tabular-nums; white-space:nowrap; }
.hf-hold-v.is-dim{ color:var(--text-3); font:500 12px/1.3 var(--font-display); }
.hf-hold-pl{ font:500 11.5px/1.3 var(--font-mono); color:var(--text-3); font-variant-numeric:tabular-nums; white-space:nowrap; }
.hf-hold-pl.up{ color:var(--up); }
.hf-hold-pl.down{ color:var(--dn); }
.hf-hold-sell{
  flex:none; min-height:36px; padding:0 14px; border-radius:var(--r-pill); cursor:pointer;
  background:var(--dn-dim); color:var(--dn); border:1px solid rgb(var(--dn-rgb) / .45);
  font:600 13px/1 var(--font-display);
  transition:border-color var(--t-fast), box-shadow var(--t-fast);
}
.hf-hold-sell:hover{ border-color:var(--dn); box-shadow:0 0 0 1px rgb(var(--dn-rgb) / .3); }
.hf-hold-sell:focus-visible{ outline:2px solid var(--gold-400); outline-offset:2px; }

/* ── tabs: the reference's segmented pill (cf-tabs) ───────────────────── */
.hf-sub{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin:6px 0 4px; }
.hf-tabs.cf-tabs{ flex:none; }
.hf-tab:focus-visible{ outline:2px solid var(--gold-400); outline-offset:2px; }
/* Freshness. A fresh feed draws nothing here; the note appears only once the
   last answer is over 90s old (or the server stopped answering), which the
   reader must be told about. */
.hf-live{ display:none; margin-left:auto; flex:none; align-items:center; gap:7px; padding:0 4px; font:600 10.5px/1 var(--font-mono); letter-spacing:.12em; text-transform:uppercase; color:var(--pro); white-space:nowrap; }
.hf-live.is-stale{ display:flex; }
.hf-live-dot{ width:7px; height:7px; border-radius:50%; background:var(--pro); }

/* ── composer (markup from cf-posts.js, composer-only mount) ──────────── */
.hf-comp:empty{ display:none; }
.hf-comp .cf-comp{
  border-radius:var(--r-lg); padding:14px 16px; margin:0;
  background:linear-gradient(180deg, rgb(var(--raise) / .9), rgb(var(--raise) / .92));
  border:1px solid var(--glass-edge); box-shadow:var(--shadow-2);
}

/* ── the cards ────────────────────────────────────────────────────────── */
.hf-feed, .hf-posts{ display:flex; flex-direction:column; gap:14px; }
.hf-feed[hidden], .hf-posts[hidden]{ display:none; }
.hf-feed > [data-cf-promoted]{ margin:0; }

/* skeletons: shaped like the card that replaces them, a light sweep */
.hf-skel{
  position:relative; overflow:hidden;
  background:linear-gradient(180deg, rgb(var(--raise) / .9), rgb(var(--raise) / .92));
  border:1px solid var(--glass-edge); border-radius:var(--r-lg);
  padding:16px; display:grid; grid-template-columns:44px 160px; gap:14px 12px; align-items:center;
}
.hf-skel i{ width:44px; height:44px; border-radius:50%; background:rgb(var(--tint) / .05); }
.hf-skel b{ height:14px; border-radius:7px; background:rgb(var(--tint) / .05); }
.hf-skel s{ grid-column:1/-1; height:64px; border-radius:var(--r-md); background:var(--well); }
.hf-skel u{ grid-column:1/-1; width:60%; height:14px; border-radius:7px; background:rgb(var(--tint) / .05); }
.hf-skel::after, .hf-row-skel::after{
  content:''; position:absolute; inset:0; transform:translateX(-100%);
  background:linear-gradient(90deg, transparent, rgb(var(--tint) / .06), transparent);
}
@media (prefers-reduced-motion:no-preference){
  .hf-skel::after, .hf-row-skel::after{ animation:hf-sweep 1.4s infinite; }
}
@keyframes hf-sweep{ to{ transform:translateX(100%); } }

/* Empty / error: the card's own shape. */
.hf-empty{
  background:linear-gradient(180deg, rgb(var(--raise) / .9), rgb(var(--raise) / .92));
  border:1px solid var(--glass-edge); border-radius:var(--r-lg); box-shadow:var(--shadow-2);
  padding:16px; display:flex; flex-direction:column; gap:12px;
}
.hf-empty-who{ display:flex; align-items:center; gap:12px; }
.hf-empty-av{ width:44px; height:44px; border-radius:50%; border:1px dashed var(--text-4); box-sizing:border-box; flex:none; }
.hf-empty-t{ display:flex; flex-direction:column; gap:3px; }
.hf-empty-t b{ font:600 16px/1.3 var(--font-display); color:var(--text-1); }
.hf-empty-t span{ font:500 12px/1.4 var(--font-mono); color:var(--text-3); }
.hf-empty-acts{ display:flex; gap:8px; }
.hf-empty.is-error{ padding:28px; align-items:center; text-align:center; gap:10px; }
.hf-empty.is-error b{ font:600 18px/1.3 var(--font-display); color:var(--text-1); }
.hf-empty.is-error code{ font:500 13px/1.4 var(--font-mono); color:var(--text-2); }

/* The empty/error actions: cf-btn's shape, drawn here for the markup
   home-feed.js writes (secondary, and the molten primary). */
.hf-btn{
  flex:1; min-height:44px; display:flex; align-items:center; justify-content:center;
  padding:0 20px; border-radius:var(--r-pill); cursor:pointer; text-decoration:none;
  font:600 14px/1 var(--font-display); background:var(--ink-4); color:var(--text-1);
  border:1px solid var(--glass-edge-hi); box-shadow:var(--shadow-1);
}
.hf-btn-primary{
  background:var(--molten); color:var(--on-molten); border-color:var(--molten-hi);
  box-shadow:0 1px 0 rgb(var(--sheen-rgb) / .5) inset, 0 -2px 0 var(--molten-lo) inset, 0 6px 22px rgb(var(--glow) / .32);
}
.hf-btn:focus-visible{ outline:2px solid var(--gold-400); outline-offset:2px; }
.hf-empty.is-error .hf-btn{ flex:none; }

.hf-more{
  min-height:44px; border-radius:var(--r-pill); border:1px solid var(--glass-edge-hi); background:var(--ink-4);
  color:var(--text-1); font:600 14px/1 var(--font-display); cursor:pointer; box-shadow:var(--shadow-1);
  transition:border-color var(--t-fast);
}
.hf-more:hover{ border-color:rgb(var(--glow) / .45); }
.hf-more:focus-visible{ outline:2px solid var(--gold-400); outline-offset:2px; }
.hf-more[hidden]{ display:none; }

/* Card entrance: added by script, removed on animationend. Movement only. */
@media (prefers-reduced-motion:no-preference){
  .hf-in{ animation:hf-in .45s var(--ease-out, cubic-bezier(.2,.9,.25,1)); }
}
@keyframes hf-in{ from{ transform:translateY(10px); } to{ transform:none; } }

/* ── the side column: glass panels (cf-glass cf-panel) ────────────────── */
.hf-card{ min-width:0; }
.hf-card.cf-panel{ padding:18px 16px 14px; }
.hf-card-head.cf-panel-h{ margin-bottom:10px; padding:0 4px; }
.hf-card-head h2{ margin:0; font:600 17px/1.2 var(--font-display); letter-spacing:-.01em; color:var(--text-1); }
.hf-link{ font:600 13px/1 var(--font-display); color:var(--accent-text); text-decoration:none; }
.hf-link:hover{ color:var(--accent-text-strong); }
.hf-link:focus-visible{ outline:2px solid var(--gold-400); outline-offset:2px; border-radius:4px; }
.hf-caps{ font:600 10px/1 var(--font-mono); letter-spacing:.16em; text-transform:uppercase; color:var(--text-3); }
.hf-card-more{ display:block; margin:8px 4px 0; }
.hf-list{ display:grid; grid-template-columns:minmax(0, 1fr); gap:2px; }
.hf-row-skel{ position:relative; overflow:hidden; height:44px; margin:4px; border-radius:var(--r-md); background:rgb(var(--tint) / .04); }
.hf-list-empty, .hf-panel-note{ margin:4px 4px 10px; padding:0; font:500 13px/1.45 var(--font-display); color:var(--text-3); }
.hf-panel-empty{ padding:14px 8px; }
.hf-panel-empty svg{ width:44px; height:44px; color:var(--accent-text); }

/* a row: the reference's .na-mover (52px, the curve and the move on the right) */
.hf-row{
  display:flex; align-items:center; gap:10px; padding:6px 8px; min-height:52px;
  box-sizing:border-box; width:100%; color:inherit; text-decoration:none;
  background:none; border:0; border-radius:var(--r-md); text-align:left; font:inherit; cursor:pointer;
  transition:background var(--t-fast);
}
button.hf-row:hover, a.hf-row:hover, .hf-row:hover{ background:rgb(var(--tint) / .04); }
.hf-row:focus-visible{ outline:2px solid var(--gold-400); outline-offset:-2px; }
.hf-rank{ width:16px; flex:none; text-align:right; font:600 12px/1 var(--font-mono); color:var(--text-4); }
.hf-av{
  position:relative; width:34px; height:34px; border-radius:50%; flex:none; overflow:hidden;
  display:flex; align-items:center; justify-content:center;
  font:700 13px/1 var(--font-display); color:var(--on-molten); background:var(--molten);
  box-shadow:0 0 0 1px rgb(var(--tint) / .16), 0 3px 10px rgb(var(--shade) / .45);
}
.hf-av-wrap{ position:relative; flex:none; line-height:0; }
.hf-medal{ position:absolute; right:-5px; bottom:-5px; line-height:0; }
.hf-medal:empty{ display:none; }
.hf-av img, .hf-tok img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; display:block; }
.hf-row-link{ display:flex; flex:none; border-radius:50%; }
a.hf-who{ text-decoration:none; color:inherit; }
.hf-tok{
  position:relative; width:34px; height:34px; border-radius:11px; flex:none; overflow:hidden;
  display:flex; align-items:center; justify-content:center;
  background:var(--ink-4); box-shadow:0 0 0 1px var(--glass-edge-hi), var(--shadow-1);
  font:700 13px/1 var(--font-display); color:var(--accent-text-strong);
}
.hf-who{ display:flex; flex-direction:column; gap:2px; min-width:0; flex:1; }
.hf-who > b{ font:600 14px/1.2 var(--font-display); color:var(--text-1); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.hf-who > span{ font:500 11.5px/1.3 var(--font-mono); color:var(--text-3); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.hf-who > span.up{ color:var(--up); }
.hf-who > span.down{ color:var(--dn); }
.hf-score{ flex:none; font:600 14px/1 var(--font-mono); color:var(--accent-text-strong); }
/* Copy on a trader row: the molten primary, small. */
.hf-copy{
  position:relative; min-height:36px; padding:0 14px; flex:none; display:flex; align-items:center;
  border-radius:var(--r-pill); cursor:pointer; border:1px solid var(--molten-hi);
  background:var(--molten); color:var(--on-molten); font:600 13px/1 var(--font-display);
  box-shadow:0 1px 0 rgb(var(--sheen-rgb) / .5) inset, 0 -2px 0 var(--molten-lo) inset, 0 4px 14px rgb(var(--glow) / .28);
  text-shadow:0 1px 0 rgb(var(--sheen-rgb) / .45);
}
.hf-copy::before{ content:''; position:absolute; inset:-4px; }
.hf-copy.is-copying{ background:var(--up-dim); color:var(--up); border-color:rgb(var(--up-rgb) / .45); box-shadow:none; text-shadow:none; }
.hf-copy:focus-visible{ outline:2px solid var(--gold-400); outline-offset:2px; }
.hf-spark{ width:72px; height:28px; flex:none; }
.hf-spark .cf-chart-empty{ display:none; }
.hf-chg{ min-width:58px; flex:none; text-align:right; font:600 13px/1 var(--font-mono); color:var(--text-2); font-variant-numeric:tabular-nums; }
.hf-chg.up{ color:var(--up); }
.hf-chg.down{ color:var(--dn); }

/* Auto Bot */
.hf-bot-top{ display:flex; justify-content:space-between; align-items:baseline; gap:10px; padding:0 4px; }
.hf-bot-top b{ font:600 24px/1.1 var(--font-mono); letter-spacing:-.03em; color:var(--text-1); }
.hf-bot-top b.up{ color:var(--up); }
.hf-bot-top b.down{ color:var(--dn); }
.hf-bot-top small{ font:500 11.5px/1.3 var(--font-mono); color:var(--text-3); }
.hf-bot-chart{ height:96px; margin:8px 0 12px; }
.hf-bot-chart .cf-chart-empty{ min-height:96px; height:96px; padding:6px; box-sizing:border-box; }

/* Top callers: the reference's .na-call */
.hf-call{ display:grid; grid-template-columns:auto minmax(0, 1fr) auto; gap:12px; align-items:center; padding:6px 4px; }
.hf-call-t{ min-width:0; }
.hf-call-t b{ display:block; font:600 14px/1.25 var(--font-display); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.hf-call-t a{ color:inherit; text-decoration:none; }
.hf-call-t a:hover{ color:var(--accent-text-strong); }
.hf-call-t small{ display:block; color:var(--text-3); font:500 11.5px/1.35 var(--font-mono); }
.hf-call-t .cf-bar{ margin-top:7px; height:4px; }
.hf-call em{ font:700 20px/1 var(--font-mono); font-style:normal; color:var(--text-2); }
.hf-call em.up{ color:var(--up); text-shadow:0 0 14px rgb(var(--up-rgb) / .35); }

/* ── responsive ───────────────────────────────────────────────────────── */
/* Under 1180 the side column moves under the feed, its panels side by side
   (the reference's breakpoint). */
@media (max-width:1180px){
  .hf-grid{ grid-template-columns:minmax(0, 1fr); }
  .hf-side{ grid-template-columns:repeat(auto-fit, minmax(280px, 1fr)); }
}
@media (max-width:767px){
  .hf-wrap{ padding:4px 16px 24px; }
  .hf-col-main .cf-phone-hub{ margin:0 -16px; padding:2px 16px; }
  /* The positions row scrolls under the screen edge, like the hub chips,
     so the next chip peeking in says "there is more". */
  .hf-holds-row{ margin:0 -16px; padding:2px 16px 4px; scroll-padding:0 16px; }
  /* The phone Feed has no side column: Top traders live on Traders and
     Leaderboard, movers on Live Market -- both one chip away above. */
  .hf-side{ display:none; }
  .hf-live{ display:none; }
  .hf-sub .hf-tabs{ max-width:100%; }
  .hf-pf-v{ font-size:26px; }
  .hf-pf-id{ min-width:130px; }
}

/* Touch: 44px targets. */
@media (pointer:coarse), (hover:none){
  .hf-pf-rng .hf-rng::before{ content:''; position:absolute; inset:-6px 0; }
  .hf-hold-sell{ min-height:44px; }
  .hf-link{ display:inline-flex; align-items:center; min-height:44px; margin:-14px 0; }
  .hf-card-more{ display:flex; margin:0 4px; }
  /* "Portfolio" is a link to the wallet; its line becomes a 44px hit box
     that takes no extra room. */
  .hf-pf-k{ display:flex; align-items:center; align-self:flex-start; min-height:44px; margin:-17px 0; }
}

@media (prefers-reduced-motion:reduce){
  .hf-hold, .hf-hold-sell, .hf-row, .hf-more{ transition:none; }
  .hf-hold:hover{ transform:none; }
}

/* "N new cards" (home-feed.js): the reference's ion pill, sticky under the
   top bar, pressed to load them. It never inserts under the reader. */
.hf-new{
  position:sticky; top:84px; z-index:6; align-self:center; display:inline-flex; align-items:center; gap:8px;
  margin:0 auto; min-height:40px; padding:0 16px; border-radius:var(--r-pill);
  border:1px solid rgb(var(--ion-rgb) / .45); background:rgb(var(--ion-ground) / .9); color:var(--ion);
  font:600 13px/1 var(--font-display); cursor:pointer;
  box-shadow:0 8px 24px rgb(var(--shade) / .5), 0 0 18px rgb(var(--ion-rgb) / .2);
  -webkit-backdrop-filter:blur(10px); backdrop-filter:blur(10px);
  animation:hfNewIn 420ms var(--ease-spring, cubic-bezier(.2,.9,.25,1.05));
}
.hf-new[hidden]{ display:none; }
.hf-new:hover{ border-color:var(--ion); }
.hf-new:focus-visible{ outline:2px solid var(--ion); outline-offset:2px; }
@keyframes hfNewIn{ from{ transform:translateY(-10px) scale(.96); } to{ transform:none; } }
@media (max-width:767px){ .hf-new{ top:68px; } }
@media (prefers-reduced-motion:reduce){ .hf-new{ animation:none; } }

/* side panel buttons: the full panel width, border included */
.hf-side .cf-btn{ box-sizing:border-box; max-width:100%; }

/* Touch: the side rows and their actions are 44px boxes. */
@media (pointer:coarse), (hover:none){
  .hf-row-link{ min-width:44px; min-height:44px; align-items:center; justify-content:center; }
  a.hf-who{ min-height:44px; justify-content:center; }
  .hf-copy{ min-height:44px; }
  .hf-side .cf-btn--sm{ min-height:44px; }
  .hf-caps{ min-width:44px; justify-content:flex-end; }
}


/* ---- static/cf-posts.css ---- */
/* Cartel Family — the public post composer and the posts feed.
 *
 * Both of these already existed on the server and had worked for months. They
 * were unreachable: their only caller lived inside templates/dashboard.html +
 * static/dashboard.js, the single document that used to BE the app, and when
 * the redesign replaced `/` with the feed that document stopped being served.
 * The routes still answered 200 the whole time. An audit found 74 endpoints in
 * the same position; this restores the social ones.
 *
 * Every colour is a cf-theme token. --accent is the brand (violet), --green
 * and --red mean gain and loss and nothing else, and a literal here would be
 * right in one theme and wrong in the other.
 */

/* ── composer ──────────────────────────────────────────────────────────── */
/* The design's (02-feed): a 36px avatar beside the text, then + Image,
   @ Mention and $ Token chips under it (indented to the text on desktop,
   full width on a phone) with Post on the right. */
.cf-comp{
  background:var(--s1); border:1px solid var(--line); border-radius:16px;
  padding:12px 14px; margin-bottom:14px;
}
.cf-comp-row{ display:flex; gap:10px; align-items:flex-start; }
.cf-comp-av{
  width:36px; height:36px; flex:0 0 36px; border-radius:50%; overflow:hidden;
  display:flex; align-items:center; justify-content:center;
  /* --ink, not white: the disc mixes into --s2 and is pale on light. */
  font:700 12px/1 var(--font-ui); color:var(--ink);
  background:color-mix(in srgb, var(--series-4) 45%, var(--s2));
}
.cf-comp-av img{ width:100%; height:100%; object-fit:cover; display:block; }
.cf-comp-av-guest{ background:none; border:2px dashed var(--ink3); box-sizing:border-box; }
.cf-comp-main{ flex:1; min-width:0; }
.cf-comp-in{
  width:100%; box-sizing:border-box; min-height:48px; resize:none; margin:0;
  background:transparent; border:0; outline:none; padding:8px 0 0;
  color:var(--ink); font:500 15px/1.4 var(--font-ui);
}
.cf-comp-in::placeholder{ color:var(--ink3); opacity:1; }
.cf-comp-guest-t{ color:var(--ink3); }

.cf-comp-preview{ position:relative; margin-top:10px; }
.cf-comp-preview img{
  width:100%; max-height:280px; object-fit:cover; display:block;
  border-radius:12px; border:1px solid var(--line);
}
.cf-comp-drop{
  position:absolute; top:8px; right:8px; width:28px; height:28px; border-radius:50%;
  border:0; cursor:pointer; background:var(--scrim); color:#fff;
  font:700 15px/1 var(--font-ui);
}

.cf-comp-bar{ display:flex; align-items:center; flex-wrap:wrap; gap:6px; margin-top:10px; }
.cf-comp-chip{
  position:relative; height:32px; padding:0 10px; display:flex; align-items:center;
  border:0; border-radius:8px; background:var(--s2); cursor:pointer; white-space:nowrap;
  font:600 12px/1 var(--font-ui); color:var(--ink2);
  transition:color .14s ease;
}
.cf-comp-chip:hover{ color:var(--ink); }
.cf-comp-icon input{ position:absolute; width:1px; height:1px; opacity:0; }
.cf-comp-count{
  margin-left:auto; font:500 11px/1 var(--font-num); color:var(--ink3);
  font-variant-numeric:tabular-nums; display:none;
}
/* The count appears only near the limit, so it never costs the chips room. */
.cf-comp-count.is-near, .cf-comp-count.is-over{ display:block; }
.cf-comp-count.is-near + .cf-comp-send, .cf-comp-count.is-over + .cf-comp-send{ margin-left:0; }
.cf-comp-count.is-near{ color:var(--pro); }
.cf-comp-count.is-over{ color:var(--dn); }
.cf-comp-send{
  height:36px; padding:0 18px; display:flex; align-items:center;
  border:0; border-radius:10px; cursor:pointer; text-decoration:none;
  font:700 13px/1 var(--font-ui); background:var(--acc); color:var(--onAcc);
  margin-left:auto;
}
.cf-comp-send:disabled{ background:var(--s2); color:var(--ink3); cursor:default; }
.cf-comp-connect{ margin-left:auto; }
.cf-comp-send:focus-visible,.cf-comp-chip:focus-visible,.cf-comp-icon:focus-within{ outline:2px solid var(--acc); outline-offset:2px; }

/* The composer's own status line. A post that failed must say why, in the
   server's words, and leave what was typed alone so it can be retried. */
.cf-comp-say{ margin-top:9px; font:500 12.5px/1.5 var(--font-ui); color:var(--ink2); }
.cf-comp-say[data-kind="error"]{ color:var(--dn); }
.cf-comp-say[data-kind="ok"]{ color:var(--up); }
.cf-comp-say:empty{ display:none; }

@media (max-width:767px){
  /* The chips run the full width of the card on a phone. */
  .cf-comp-bar{ margin-left:-46px; }
}

/* Touch: 44px targets, the design's drawn sizes. Each control's hit box
   grows with a transparent border and its fill stays clipped to the drawn
   32/36px shape; negative margins keep the drawn 6px spacing, and the bar
   sits 6px higher so the chips' drawn tops stay where they were. */
@media (pointer:coarse), (hover:none){
  .cf-comp-bar{ gap:0; margin-top:4px; }
  .cf-comp-chip{
    height:44px; box-sizing:border-box; margin-right:-6px;
    border:6px solid transparent; background-clip:padding-box; border-radius:14px;
  }
  .cf-comp-bar > .cf-comp-chip:first-child{ margin-left:-6px; }
  .cf-comp-send, .cf-comp-send:disabled{
    height:44px; box-sizing:border-box; margin-right:-4px;
    border:4px solid transparent; background-clip:padding-box; border-radius:14px;
  }
  .cf-comp-drop{ width:44px; height:44px; top:0; right:0; border:8px solid transparent; background-clip:padding-box; }
}

/* ── a post ────────────────────────────────────────────────────────────── */
.cf-post{
  background:var(--bg2); border:1px solid var(--border); border-radius:17px;
  padding:15px; margin-bottom:12px;
}
.cf-post-hd{ display:flex; align-items:center; gap:11px; }
.cf-post-av{
  width:36px; height:36px; flex:0 0 36px; border-radius:var(--r-pill); overflow:hidden;
  display:flex; align-items:center; justify-content:center;
  font:800 12px var(--font-sans); color:var(--m3-on-primary,#fff);
  background:linear-gradient(135deg, var(--accent-cta), var(--m3-primary-fixed-dim,var(--accent-cta)));
}
.cf-post-av img{ width:100%; height:100%; object-fit:cover; display:block; }
.cf-post-id{ min-width:0; display:flex; flex-direction:column; gap:2px; }
.cf-post-name{
  display:flex; align-items:center; gap:6px;
  font:700 13.5px var(--font-sans); color:var(--text);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.cf-post-when{ font:500 11px var(--font-mono); color:var(--dim); }
.cf-post-verified{
  width:14px; height:14px; flex:0 0 14px; border-radius:var(--r-pill);
  background:var(--accent-cta); color:var(--m3-on-primary,#fff);
  display:grid; place-items:center;
}
.cf-post-verified svg{ width:8px; height:8px; }
.cf-post-del{
  margin-left:auto; border:0; background:transparent; cursor:pointer;
  color:var(--dim); font:600 11.5px var(--font-sans); padding:4px 8px; border-radius:8px;
}
.cf-post-del:hover{ color:var(--red); background:var(--bg3); }

.cf-post-body{
  margin-top:11px; font-size:14px; line-height:1.55; color:var(--text);
  white-space:pre-wrap; overflow-wrap:anywhere;
}
.cf-post-img{
  margin-top:11px; width:100%; max-height:420px; object-fit:cover; display:block;
  border-radius:12px; border:1px solid var(--border);
}

/* A trade that came through the social feed keeps the feed's own language
   rather than becoming a third kind of card. */
.cf-post-trade{
  margin-top:11px; display:flex; align-items:baseline; gap:10px; flex-wrap:wrap;
  padding:10px 12px; border-radius:12px; background:var(--bg3); border:1px solid var(--border);
}
.cf-post-trade b{ font:700 13.5px var(--font-mono); }
.cf-post-trade .pnl{ margin-left:auto; font:700 13px var(--font-mono); color:var(--green); }
.cf-post-trade .pnl.down{ color:var(--red); }

.cf-post-ft{
  display:flex; align-items:center; gap:6px; margin-top:12px;
  padding-top:11px; border-top:1px solid var(--border);
}
.cf-post-act{
  display:inline-flex; align-items:center; gap:7px;
  border:0; background:transparent; cursor:pointer; color:var(--muted);
  font:600 12px var(--font-sans); padding:6px 10px; border-radius:9px;
  transition:color .14s ease, background .14s ease;
}
.cf-post-act:hover{ background:var(--bg3); color:var(--text); }
.cf-post-act:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
.cf-post-act svg{ width:15px; height:15px; }
/* Liked is the ONE place --red is not a loss on this surface, which is why it
   is a fill on an icon rather than a number. */
.cf-post-act.is-on{ color:var(--red); }
.cf-post-act.is-on svg{ fill:currentColor; }
.cf-post-views{ margin-left:auto; font:500 11px var(--font-mono); color:var(--dim); }

/* ── replies ───────────────────────────────────────────────────────────── */
.cf-post-replies{ margin-top:11px; padding-top:11px; border-top:1px solid var(--border); }
.cf-post-replies[hidden]{ display:none; }
.cf-reply{ display:flex; gap:10px; padding:8px 0; }
.cf-reply-av{
  width:26px; height:26px; flex:0 0 26px; border-radius:var(--r-pill); overflow:hidden;
  display:flex; align-items:center; justify-content:center;
  font:800 9px var(--font-sans); color:var(--m3-on-primary,#fff);
  background:linear-gradient(135deg, var(--accent-cta), var(--m3-primary-fixed-dim,var(--accent-cta)));
}
.cf-reply-av img{ width:100%; height:100%; object-fit:cover; display:block; }
.cf-reply-b{ min-width:0; flex:1; }
.cf-reply-who{ font:700 12px var(--font-sans); }
.cf-reply-when{ font:500 10px var(--font-mono); color:var(--dim); margin-left:6px; }
.cf-reply-t{
  font-size:13px; line-height:1.5; color:var(--muted); margin-top:3px;
  white-space:pre-wrap; overflow-wrap:anywhere;
}
.cf-reply-form{ display:flex; gap:8px; margin-top:9px; }
.cf-reply-form input{
  flex:1; min-width:0; box-sizing:border-box;
  background:var(--bg3); border:1px solid var(--border2); border-radius:11px;
  padding:9px 12px; color:var(--text); font:500 13px var(--font-sans); outline:none;
}
.cf-reply-form input:focus{ border-color:var(--accent); }
.cf-reply-form button{
  border:0; border-radius:11px; padding:9px 15px; cursor:pointer;
  font:700 12.5px var(--font-sans); color:var(--m3-on-primary,#fff);
  background:var(--accent-cta);
}
.cf-reply-form button:disabled{ opacity:.45; cursor:default; }

/* ── list states ───────────────────────────────────────────────────────── */
.cf-posts-state{
  text-align:center; padding:34px 18px; color:var(--muted);
  font-size:13.5px; line-height:1.6;
}
.cf-posts-state h3{ font-size:15px; font-weight:700; color:var(--text); margin-bottom:7px; }
.cf-posts-state button{
  margin-top:13px; border:1px solid var(--border2); background:var(--bg3); color:var(--text);
  border-radius:11px; padding:9px 17px; cursor:pointer; font:600 12.5px var(--font-sans);
}
.cf-posts-more{
  width:100%; margin-top:4px; border:1px solid var(--border2); background:var(--bg2);
  color:var(--muted); border-radius:12px; padding:11px; cursor:pointer;
  font:600 12.5px var(--font-sans);
}
.cf-posts-more:hover{ color:var(--text); border-color:var(--border); }
.cf-posts-more[hidden]{ display:none; }

@media (prefers-reduced-motion:reduce){
  .cf-comp-send, .cf-comp-icon, .cf-post-act{ transition:none; }
}
@media (max-width:560px){
  .cf-post{ border-radius:14px; padding:13px; }
}

/* The author's own post while it is being written: drawn at once, quieter
   until the server's stored row replaces it. Visible at rest, never parked. */
.cf-post.is-pending{ opacity:.72; }
.cf-post.is-pending .cf-post-when{ color:var(--acc, currentColor); }
/* A post in the For-you stream sits between trade cards: the stream's own 14px gap, no margin of its own. */
.hf-feed > .cf-post{ margin:0; }


/* ---- static/cf-rich.css ---- */
/* Cartel Family — rich post text (cf-rich.js): the links a post's words
   become, and the composer's @ / $ autocomplete popover.
   Every colour is a cf-theme token; nothing here is right in one theme only. */

/* ── the words ─────────────────────────────────────────────────────────── */
.cf-rich{
  color:var(--accent-text, var(--acc)); text-decoration:none; font-weight:600;
  border-radius:4px; transition:color var(--dur-fast, .16s) var(--ease-out, ease), background-color var(--dur-fast, .16s) var(--ease-out, ease);
}
.cf-rich:hover{ text-decoration:underline; text-underline-offset:2px; }
.cf-rich:focus-visible{ outline:none; box-shadow:var(--focus-ring, 0 0 0 2px var(--acc)); }
.cf-rich-t, .cf-rich-a{
  font-family:var(--font-mono); font-weight:600; font-size:.95em; letter-spacing:.01em;
  padding:0 .28em; margin:0 -.05em;
  background:color-mix(in srgb, var(--acc) 12%, transparent);
}
.cf-rich-t:hover, .cf-rich-a:hover{ background:color-mix(in srgb, var(--acc) 20%, transparent); text-decoration:none; }
/* Not a token we can name: the word still goes somewhere useful (the market
   search), but it is drawn as a question, never as a trade. */
.cf-rich-t.is-unresolved{
  color:var(--ink2); background:transparent; border-bottom:1px dashed var(--ink3); border-radius:0; padding:0;
}
.cf-rich-t.is-unresolved:hover{ color:var(--ink); border-bottom-color:var(--ink2); background:transparent; }
.cf-rich-a b{ font-weight:700; }
.cf-rich-addr{ opacity:.85; }
.cf-rich-l{ overflow-wrap:anywhere; font-weight:500; }
/* The Mini App draws these as buttons (its screens open in place). */
button.cf-rich{ appearance:none; border:0; background:transparent; font:inherit; cursor:pointer; display:inline; line-height:inherit; margin:0; min-height:0; }
button.cf-rich-m{ padding:0; }
button.cf-rich-t, button.cf-rich-a{ background:color-mix(in srgb, var(--acc) 12%, transparent); }

/* ── the autocomplete ──────────────────────────────────────────────────── */
.cf-rich-host{ position:relative; }
.cf-rich-pop{
  position:absolute; z-index:40; box-sizing:border-box;
  max-height:min(50vh, 316px); overflow-y:auto; overscroll-behavior:contain;
  padding:6px; border-radius:14px;
  background:var(--s2, var(--s1)); border:1px solid var(--line);
  box-shadow:var(--cf-modal-shadow, 0 18px 48px rgba(0,0,0,.45));
}
.cf-rich-pop.is-enter{ animation:cfRichIn var(--dur-fast, .16s) var(--ease-out, ease) both; }
@keyframes cfRichIn{ from{ opacity:0; transform:translateY(-4px); } to{ opacity:1; transform:none; } }
.cf-rich-row{
  display:flex; align-items:center; gap:10px; width:100%; box-sizing:border-box;
  min-height:36px; padding:6px 8px; border:0; border-radius:10px; text-align:left;
  background:transparent; color:var(--ink); font:500 13.5px/1.25 var(--font-ui); cursor:pointer;
}
.cf-rich-row:hover, .cf-rich-row.is-sel{ background:color-mix(in srgb, var(--acc) 14%, transparent); }
.cf-rich-row.is-sel .cf-rich-p{ color:var(--accent-text, var(--acc)); }
.cf-rich-row:focus-visible{ outline:none; box-shadow:var(--focus-ring, 0 0 0 2px var(--acc)); }
.cf-rich-tile{
  width:26px; height:26px; flex:0 0 26px; border-radius:50%; object-fit:cover;
  display:inline-flex; align-items:center; justify-content:center;
  background:color-mix(in srgb, var(--acc) 18%, var(--s1)); color:var(--ink);
  font:700 11px/1 var(--font-ui);
}
.cf-rich-main{ display:flex; flex-direction:column; gap:1px; min-width:0; }
.cf-rich-p{ font-family:var(--font-mono); font-weight:600; font-size:13px; }
.cf-rich-s{
  display:inline-flex; align-items:center; gap:5px; color:var(--ink3); font-size:11.5px;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.cf-rich-chain{ width:12px; height:12px; border-radius:50%; flex:0 0 12px; }
@media (pointer: coarse){
  .cf-rich-row{ min-height:44px; font-size:14.5px; }
  .cf-rich-tile{ width:30px; height:30px; flex-basis:30px; }
}
@media (prefers-reduced-motion: reduce){
  .cf-rich, .cf-rich-pop.is-enter{ animation:none; transition:none; }
}


/* ---- static/cf-promoted.css ---- */
/* Cartel Family — promoted token placements (PAID). Styles for cf-promoted.js.
 *
 * SYNDICATE NOIR promoted card (owner, 2026-10-16: the thin gold box "looks
 * plain"). A glass panel with a slow conic edge in the brand ramp (one turn in 6s), a soft
 * ember glow behind the token's logo, the token's real figures and curve,
 * the molten Buy with its light sweep and a ghost Chart. ONE component; the
 * host carries the size: .is-card (feed, Discover, Calls), .is-row (Traders,
 * Leaderboard), .is-banner (Live Market). The layout follows the slot's OWN
 * width (container queries), so a 300px aside and a 1200px column both fit.
 *
 * Every colour here is a cf-theme.css token. A literal would be correct in one
 * theme and wrong in the other, and this block has to stay legible in both
 * because its whole job is to be read as an advertisement.
 *
 * The disclosure is the word "Promoted" on amber on every card, plus "Paid
 * placement" beside it. The design is explicit: paid placement always carries
 * the word "Promoted" on amber — never the gain colour (a paid label painted
 * like a profit reads as a positive signal) and never the brand fill (which
 * reads as the platform's endorsement). The pill's label is --onPro, the
 * ink for an amber FILL (--on-gold failed AA on it in light mode); focus
 * rings are --gold. The molten fill is on the Buy BUTTON only, as on every
 * primary action in the product.
 *
 * Reduced motion is the finished state: the edge rests, no ember breath, no
 * sweep, no entrance; the figures and the curve are drawn in full.
 */

@property --cf-promo-a { syntax: '<angle>'; inherits: false; initial-value: 0deg; }

.cf-promo {
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* Mounted into containers of very different widths (a full-width column,
     a 300px aside), so the card lays out on its OWN width. */
  container-type: inline-size;
  flex: 0 0 auto;
  margin: 0;
}
.cf-promo[hidden] { display: none; }

/* ── the panel ──────────────────────────────────────────────────────────── */
.cf-promo-card {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding: 16px;
  border-radius: var(--r-lg, 20px);
  color: var(--ink);
  font-family: var(--font-ui);
  background:
    radial-gradient(260px 160px at 44px 64px, rgb(var(--glow) / .16), transparent 70%),
    linear-gradient(180deg, rgb(var(--raise) / .66), rgb(var(--raise) / .72) 38%, var(--glass));
  border: 1px solid var(--glass-edge);
  box-shadow: var(--shadow-2), 0 10px 36px rgb(var(--glow) / .14);
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--glass-saturate));
  backdrop-filter: blur(var(--blur)) saturate(var(--glass-saturate));
}
/* The edge: a conic sweep of the brand ramp (--glow, so it follows the
   brand and both themes) masked to a 2px ring, one slow turn. */
.cf-promo-card::before {
  content: '';
  position: absolute;
  inset: -1px;
  z-index: -1;
  border-radius: inherit;
  padding: 2px;
  pointer-events: none;
  background: conic-gradient(from var(--cf-promo-a),
    rgb(var(--glow) / .3) 0deg, rgb(var(--glow) / 1) 45deg, rgb(var(--sheen-rgb) / .95) 62deg,
    rgb(var(--glow) / .85) 80deg, rgb(var(--glow) / .3) 140deg, rgb(var(--glow) / .3) 200deg,
    rgb(var(--glow) / .8) 250deg, rgb(var(--glow) / .3) 320deg);
  -webkit-mask: linear-gradient(black 0 0) content-box, linear-gradient(black 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(black 0 0) content-box, linear-gradient(black 0 0);
  mask-composite: exclude;
  animation: cf-promo-spin 6s linear infinite;
}
@keyframes cf-promo-spin { to { --cf-promo-a: 360deg; } }

/* ── head: the disclosure, then where it trades ─────────────────────────── */
.cf-promo-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 10px;
  min-width: 0;
}
.cf-promo-badge {
  flex: 0 0 auto;
  font: 800 11px/1.3 var(--font-ui);
  letter-spacing: .02em;
  color: var(--onPro);   /* amber FILL label: see --onPro in cf-theme.css */
  background: var(--pro);
  padding: 4px 9px;
  border-radius: var(--r-badge, 6px);
}
.cf-promo-note {
  font: 600 11px/1.3 var(--font-mono, var(--font-num));
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink2);
}
.cf-promo-tags {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-left: auto;
  min-width: 0;
}
.cf-promo-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 24px;
  padding: 0 9px;
  border-radius: var(--r-pill, 999px);
  background: rgb(var(--tint) / .06);
  border: 1px solid var(--glass-edge);
  font: 600 12px/1 var(--font-ui);
  color: var(--ink2);
  white-space: nowrap;
}
.cf-promo-tag .cf-logo { width: 14px; height: 14px; flex: none; }

/* ── body: the card size by default ─────────────────────────────────────── */
.cf-promo-body {
  display: grid;
  margin-top: 14px;
  gap: 12px 16px;
  align-items: center;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas:
    "id    quote"
    "spark spark"
    "stats here"
    "acts  acts";
}
.cf-promo-id {
  grid-area: id;
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  color: inherit;
  text-decoration: none;
  border-radius: var(--r-md, 14px);
}
a.cf-promo-id:hover .cf-promo-sym { text-decoration: underline; }

.cf-promo-logo {
  --s: 48px;
  position: relative;
  flex: none;
  width: var(--s);
  height: var(--s);
  border-radius: calc(var(--s) * .3);
  display: grid;
  place-items: center;
  background: var(--molten);
  color: var(--on-molten);
  box-shadow: 0 0 0 1px var(--glass-edge-hi), 0 4px 14px rgb(var(--shade) / .4);
}
/* The ember behind the logo: a soft, breathing warmth, never a ring. */
.cf-promo-logo::before {
  content: '';
  position: absolute;
  inset: -18px;
  z-index: -1;
  border-radius: 50%;
  background: radial-gradient(circle, rgb(var(--glow) / .55), rgb(var(--glow) / 0) 66%);
  filter: blur(4px);
  pointer-events: none;
  animation: cf-promo-ember 3.6s var(--ease-in-out, ease-in-out) infinite alternate;
}
@keyframes cf-promo-ember { from { opacity: .55; transform: scale(.9); } to { opacity: 1; transform: scale(1.08); } }
.cf-promo-letter { font: 800 calc(var(--s) * .42)/1 var(--font-display, var(--font-ui)); }
.cf-promo-logo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
  background: var(--ink-4);
}

.cf-promo-names { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.cf-promo-sym {
  font: 800 18px/1.15 var(--font-display, var(--font-ui));
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cf-promo-name {
  font: 500 13px/1.3 var(--font-ui);
  color: var(--ink2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cf-promo-quote {
  grid-area: quote;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
  min-width: 0;
}
.cf-promo-price {
  font: 700 18px/1.1 var(--font-num, var(--font-mono));
  color: var(--ink);
  white-space: nowrap;
}
.cf-promo-price.is-up { animation: cf-promo-up .9s var(--ease-out, ease-out); }
.cf-promo-price.is-dn { animation: cf-promo-dn .9s var(--ease-out, ease-out); }
@keyframes cf-promo-up { from { color: var(--up); } }
@keyframes cf-promo-dn { from { color: var(--dn); } }
.cf-promo-chg {
  font: 700 12px/1 var(--font-num, var(--font-mono));
  padding: 4px 7px;
  border-radius: var(--r-pill, 999px);
  white-space: nowrap;
}
.cf-promo-chg.up { color: var(--up); background: var(--up-dim, var(--upBg)); }
.cf-promo-chg.dn { color: var(--dn); background: var(--dn-dim, var(--dnBg)); }
.cf-promo-chg.flat { color: var(--ink3); background: rgb(var(--tint) / .06); }
.cf-promo-chg i { font-style: normal; opacity: .7; margin-right: 4px; font-weight: 600; }

.cf-promo-spark {
  grid-area: spark;
  position: relative;
  height: 40px;
  min-width: 0;
}
.cf-promo-spark .cf-spark-svg { width: 100%; height: 100%; display: block; }
.cf-promo-nochart {
  display: flex;
  align-items: center;
  height: 100%;
  font: 500 12px/1.3 var(--font-ui);
  color: var(--ink3);
  border-top: 1px dashed var(--line);
  border-bottom: 1px dashed var(--line);
  padding: 0 4px;
}

.cf-promo-stats {
  grid-area: stats;
  display: flex;
  gap: 18px;
  margin: 0;
  min-width: 0;
}
.cf-promo-stats div { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.cf-promo-stats dt {
  font: 600 10px/1 var(--font-mono, var(--font-num));
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink3);
}
.cf-promo-stats dd {
  margin: 0;
  font: 700 14px/1.1 var(--font-num, var(--font-mono));
  color: var(--ink);
  white-space: nowrap;
}

.cf-promo-here {
  grid-area: here;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  min-width: 0;
}
.cf-promo-faces { display: inline-flex; }
.cf-promo-face {
  position: relative;
  width: 22px;
  height: 22px;
  margin-left: -6px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  overflow: hidden;
  font: 700 10px/1 var(--font-display, var(--font-ui));
  color: var(--on-molten);
  background: var(--molten);
  box-shadow: 0 0 0 2px var(--ink-3);
}
.cf-promo-face:first-child { margin-left: 0; }
.cf-promo-face img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.cf-promo-here-t { font: 500 12px/1.3 var(--font-ui); color: var(--ink2); white-space: nowrap; }
.cf-promo-here-t b { color: var(--ink); font-weight: 700; }

.cf-promo-acts {
  grid-area: acts;
  display: flex;
  gap: 10px;
  min-width: 0;
}
.cf-promo-acts .cf-btn { min-height: var(--tap, 44px); }
.cf-promo-buy { flex: 1 1 auto; font-weight: 700; }
.cf-promo-chart { flex: 0 0 auto; padding: 0 18px; }
/* The molten Buy carries the sweep on its own, every few seconds, not only
   on hover: it is the one thing on the card to press. */
.cf-promo-buy::after { animation: cf-promo-sweep 6s var(--ease-out, ease-out) 1.4s infinite; }
@keyframes cf-promo-sweep {
  0% { transform: translateX(-120%); }
  16%, 100% { transform: translateX(120%); }
}

/* ── the row (Traders, Leaderboard) and the banner (Live Market) ───────── */
@container (min-width: 600px) {
  .cf-promo.is-row .cf-promo-body,
  .cf-promo.is-banner .cf-promo-body {
    grid-template-columns: minmax(180px, 1.3fr) minmax(120px, 1fr) auto;
    grid-template-areas:
      "id    spark quote"
      "stats here  acts";
  }
  .cf-promo.is-row .cf-promo-here,
  .cf-promo.is-banner .cf-promo-here { justify-content: flex-start; }
  .cf-promo.is-row .cf-promo-acts .cf-btn,
  .cf-promo.is-banner .cf-promo-acts .cf-btn { flex: 0 0 auto; }
  .cf-promo.is-row .cf-promo-buy,
  .cf-promo.is-banner .cf-promo-buy { min-width: 132px; }
}
@container (min-width: 980px) {
  .cf-promo.is-row .cf-promo-body,
  .cf-promo.is-banner .cf-promo-body {
    grid-template-columns: minmax(200px, 1.2fr) minmax(140px, 1fr) auto auto auto auto;
    grid-template-areas: "id spark quote stats here acts";
    gap: 12px 22px;
  }
}
.cf-promo.is-banner .cf-promo-card { padding: 18px 20px; }
.cf-promo.is-banner .cf-promo-logo { --s: 56px; }
.cf-promo.is-banner .cf-promo-sym { font-size: 20px; }
.cf-promo.is-banner .cf-promo-spark { height: 48px; }

/* A narrow slot (the 300px Discover aside, a 320px phone): one column. */
@container (max-width: 340px) {
  .cf-promo-body {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "id" "quote" "spark" "stats" "here" "acts";
  }
  .cf-promo-quote { flex-direction: row; align-items: center; justify-content: flex-start; gap: 8px; }
  .cf-promo-here { justify-content: flex-start; }
  .cf-promo-tags { margin-left: 0; }
}

/* ── the entrance: added by script, taken off again; never a resting state */
.cf-promo-in .cf-promo-card { animation: cf-promo-enter .55s var(--ease-out, ease-out); }
@keyframes cf-promo-enter { from { opacity: 0; transform: translateY(10px) scale(.985); } }

/* ── unsold: the slot offering itself, at the server's price ───────────── */
.cf-promo-card.is-sell {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  min-height: 40px;
  padding: 12px 16px;
  border-radius: var(--r-card, 14px);
}
.cf-promo-card.is-sell::before { animation: none; opacity: .55; }
/* Unsold (CFFeed / CFDiscover): "Promote your token here" 700 15 beside the
   pill, the price line "— SOL · 24h" in mono 12, then the outlined action. */
.cf-promo-card.is-sell .cf-promo-sym { flex: 0 0 auto; min-width: 0; font: 700 15px/1.3 var(--font-ui); white-space: normal; }
.cf-promo-card.is-sell .cf-promo-desc { flex: 1 1 0; font: 500 12px/1.3 var(--font-num); }

.cf-promo-desc {
  flex: 1 1 0;
  min-width: 0;
  font: 500 13px/1.3 var(--font-ui);
  color: var(--ink2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Unsold: the design's outlined "Buy this slot" -- 40px inside a 1px amber
   line, 700 13 in --pro like the pill. Gold here read as the platform's own
   button; the design keeps paid placement amber. The line is an inset
   shadow so a touch screen can hang a 44px hit area on it. */
.cf-promo-sell {
  flex: 0 0 auto;
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 40px;
  padding: 0 16px;
  border-radius: var(--r-control, 10px);
  font: 700 13px/1 var(--font-ui);
  cursor: pointer;
  text-decoration: none;
  box-sizing: border-box;
  color: var(--pro);
  background: transparent;
  border: 0;
  box-shadow: inset 0 0 0 1px var(--pro);
}
.cf-promo-sell:hover { background: var(--proBg); filter: brightness(1.12); }

.cf-promo-sell:focus-visible,
.cf-promo-id:focus-visible,
.cf-promo-own:focus-visible,
.cf-promo-acts .cf-btn:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

.cf-promo-own {
  align-self: flex-end;
  display: inline-flex;
  align-items: center;
  min-height: 28px;
  font: 600 12px/1.3 var(--font-ui);
  color: var(--accT);
  text-decoration: none;
}
.cf-promo-own:hover { text-decoration: underline; }

/* The Leaderboard's UNSOLD row: flush in the list, no card of its own, the
   action as a text link. A sold promotion there is the full row card. */
.cf-promo[data-cf-promoted-variant="row"] .cf-promo-card.is-sell {
  border: 0;
  border-radius: 0;
  padding: 12px 16px;
  min-height: 0;
  background: none;
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.cf-promo[data-cf-promoted-variant="row"] .cf-promo-card.is-sell::before { display: none; }
.cf-promo[data-cf-promoted-variant="row"] .cf-promo-card.is-sell .cf-promo-sym { font-size: 13px; }
.cf-promo[data-cf-promoted-variant="row"] .cf-promo-sell {
  height: auto;
  padding: 0;
  box-shadow: none;
  border-radius: 0;
  background: none;
  line-height: normal;
}
.cf-promo[data-cf-promoted-variant="row"] .cf-promo-sell:hover { background: none; }
.cf-promo[data-cf-promoted-variant="row"].is-empty .cf-promo-own { display: none; }

@container (max-width: 300px) {
  .cf-promo-card.is-sell .cf-promo-desc { flex-basis: 100%; order: 3; }
  .cf-promo-sell { order: 2; }
}

/* Touch: the unsold slot's call to action is a 44px target. The drawn face
   stays 40px: the extra height is transparent border above and below. */
@media (pointer: coarse) {
  .cf-promo-card.is-sell .cf-promo-sell {
    height: 44px;
    border-top: 2px solid transparent; border-bottom: 2px solid transparent;
    background-clip: padding-box;
    border-radius: 10px / 12px;
    margin-top: -2px; margin-bottom: -2px;
  }
  .cf-promo[data-cf-promoted-variant="row"] .cf-promo-sell { min-height: 44px; margin-top: -14px; margin-bottom: -14px; }
  .cf-promo-own { min-height: 44px; }
}

@media (prefers-reduced-motion: reduce) {
  .cf-promo-card::before,
  .cf-promo-logo::before,
  .cf-promo-buy::after,
  .cf-promo-in .cf-promo-card,
  .cf-promo-price.is-up,
  .cf-promo-price.is-dn { animation: none; }
}

/* ── the official token (promo_cards.official_mint): the platform's own,
   labelled in the BRAND fill -- it is ours, not a paid placement, so it
   never borrows the amber that means "Promoted". ──────────────────────── */
.cf-promo-badge.is-official {
  color: var(--on-molten);
  background: var(--molten);
  box-shadow: 0 0 0 1px var(--molten-hi), 0 4px 14px rgb(var(--glow) / .35);
}

/* ── several promotions in a single-card slot: one shown, rotating ─────── */
.cf-promo-rot { display: grid; }
.cf-promo-rot > .cf-promo-card {
  grid-area: 1 / 1;
  visibility: hidden;
  opacity: 0;
  transition: opacity .45s var(--ease-out, ease-out), visibility 0s linear .45s;
}
.cf-promo-rot > .cf-promo-card.is-shown {
  visibility: visible;
  opacity: 1;
  transition: opacity .45s var(--ease-out, ease-out);
}
.cf-promo-dots { display: flex; justify-content: center; gap: 2px; margin-top: -2px; }
.cf-promo-dot {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  border-radius: var(--r-pill, 999px);
}
.cf-promo-dot i {
  display: block;
  width: 7px;
  height: 7px;
  border-radius: var(--r-pill, 999px);
  background: rgb(var(--tint) / .28);
  transition: width .3s var(--ease-out, ease-out), background .3s;
}
.cf-promo-dot[aria-selected="true"] i { width: 20px; background: var(--acc); }
.cf-promo-dot:focus-visible { outline: 2px solid var(--gold); outline-offset: 0; }
@media (pointer: coarse) { .cf-promo-dot { width: 44px; height: 44px; } }
@media (prefers-reduced-motion: reduce) {
  .cf-promo-rot > .cf-promo-card, .cf-promo-rot > .cf-promo-card.is-shown, .cf-promo-dot i { transition: none; }
}


/* ---- static/cf-saved.css ---- */
/* Cartel Family — Saved tokens (static/cf-saved.js). Syndicate Noir: glass
   rows on the page's ground, the molten Buy, mono figures that tick. Every
   colour is a token from cf-theme.css; reduced motion is the finished state. */
.cf-saved{display:flex;flex-direction:column;gap:10px;min-width:0}
.cf-saved[hidden]{display:none}
.cf-saved-head{display:flex;align-items:center;gap:10px;padding:0 2px}
.cf-saved-head h2{margin:0;flex:1;min-width:0;font:600 16px/1.2 var(--font-display);letter-spacing:-.01em;color:var(--text-1)}
.cf-saved-n{font:500 12px/normal var(--font-mono);color:var(--text-3);margin-left:4px}
.cf-saved-all{font:600 12px/1 var(--font-mono);color:var(--accent-text-strong,var(--acc));text-decoration:none;letter-spacing:.04em}
.cf-saved-all:hover{text-decoration:underline}
.cf-saved-rows{display:flex;flex-direction:column;gap:8px;min-width:0}
.cf-saved-row{
  display:grid;grid-template-columns:minmax(0,1fr) auto auto;align-items:center;gap:12px;
  padding:10px 12px;border-radius:16px;min-height:60px;
  background:linear-gradient(180deg,var(--card-hi),var(--card-lo) 60%);
  border:1px solid var(--glass-edge);box-shadow:var(--shadow-1);
  transition:transform var(--t-med,.2s),opacity var(--t-med,.2s),border-color var(--t-med,.2s);
}
.cf-saved-row:hover{border-color:var(--glass-edge-hi)}
.cf-saved-row.is-leaving{opacity:.35;transform:scale(.98);pointer-events:none}
.cf-saved-id{display:flex;align-items:center;gap:10px;min-width:0;text-decoration:none;color:inherit}
.cf-saved-id:focus-visible{outline:2px solid var(--acc);outline-offset:2px;border-radius:12px}
.cf-saved-disc{width:40px;height:40px;flex:none;display:grid;place-items:center;border-radius:12px;overflow:hidden;
  background:var(--ink-4,var(--s2));color:var(--text-2);box-shadow:0 0 0 1px var(--glass-edge-hi);font:700 15px var(--font-display)}
.cf-saved-disc img{width:100%;height:100%;object-fit:cover;display:block}
.cf-saved-name{display:flex;flex-direction:column;gap:2px;min-width:0}
.cf-saved-name b{display:flex;align-items:center;gap:6px;min-width:0;font:700 15px/1.2 var(--font-display);color:var(--text-1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cf-saved-chain{height:20px;padding:0 8px;font:600 10px/1 var(--font-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--text-2)}
.cf-saved-sub{font:500 12px/1.3 var(--font-mono);color:var(--text-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cf-saved-px{display:flex;flex-direction:column;align-items:flex-end;gap:2px;min-width:0}
.cf-saved-price{font:600 15px/1.1 var(--font-mono);letter-spacing:-.01em;color:var(--text-1);white-space:nowrap}
.cf-saved-price.is-dim{font:500 12px/1.1 var(--font-mono);color:var(--text-3)}
.cf-saved-chg{font:600 12px/1.2 var(--font-mono);white-space:nowrap;min-height:14px}
.cf-saved .up{color:var(--up)}.cf-saved .dn{color:var(--dn)}.cf-saved .flat{color:var(--text-3)}
.cf-saved-acts{display:flex;align-items:center;gap:6px;flex:none}
.cf-saved-ib{color:var(--text-2)}
.cf-saved-ib:hover{color:var(--text-1)}
.cf-saved-x:hover{color:var(--dn)}
@keyframes cf-sv-up{0%{color:var(--up);text-shadow:0 0 14px rgb(var(--up-rgb) / .5)}100%{color:var(--text-1)}}
@keyframes cf-sv-dn{0%{color:var(--dn);text-shadow:0 0 14px rgb(var(--dn-rgb) / .5)}100%{color:var(--text-1)}}
.cf-saved-price.tick-up{animation:cf-sv-up 1.1s ease-out}
.cf-saved-price.tick-dn{animation:cf-sv-dn 1.1s ease-out}
/* empty + loading: a real state, never a plausible row */
.cf-saved-empty{display:flex;flex-direction:column;align-items:center;gap:8px;text-align:center;padding:28px 18px;
  border-radius:16px;border:1px dashed var(--glass-edge-hi);color:var(--text-2);font:500 13px/1.5 var(--font-display)}
.cf-saved-empty b{font:700 16px/1.2 var(--font-display);color:var(--text-1)}
.cf-saved-empty .cf-btn{margin-top:6px;min-height:44px}
.cf-saved-empty.err{border-color:rgb(var(--dn-rgb) / .4)}
.cf-saved-glyph{font-size:28px;line-height:1;color:var(--accent-text-strong,var(--acc))}
.cf-saved-skel{display:flex;flex-direction:column;gap:8px}
.cf-saved-skel i{display:block;height:60px;border-radius:16px;background:var(--s1);border:1px solid var(--glass-edge)}
@media (prefers-reduced-motion:no-preference){
  .cf-saved-skel i{background:linear-gradient(90deg,var(--s1),var(--s2),var(--s1));background-size:200% 100%;animation:cf-sv-shim 1.4s linear infinite}
  @keyframes cf-sv-shim{to{background-position:-200% 0}}
}
/* the strip (home feed): the same rows as chips, one horizontal lane */
.cf-saved--strip .cf-saved-rows{flex-direction:row;overflow-x:auto;scroll-snap-type:x proximity;scrollbar-width:none;padding-bottom:2px}
.cf-saved--strip .cf-saved-rows::-webkit-scrollbar{display:none}
.cf-saved--strip .cf-saved-row{flex:0 0 auto;scroll-snap-align:start;grid-template-columns:auto auto auto;min-height:56px;padding:8px 10px 8px 10px;gap:10px}
.cf-saved--strip .cf-saved-disc{width:32px;height:32px;border-radius:10px;font-size:13px}
.cf-saved--strip .cf-saved-name b{font-size:14px}
.cf-saved--strip .cf-saved-sub{display:none}
.cf-saved--strip .cf-saved-acts .cf-saved-ib{display:none}
@media (hover:hover){ .cf-saved--strip .cf-saved-row:hover .cf-saved-ib{display:inline-flex} }
@media (max-width:767px){
  .cf-saved--list .cf-saved-row{grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"id px" "acts acts";row-gap:8px}
  .cf-saved--list .cf-saved-id{grid-area:id}.cf-saved--list .cf-saved-px{grid-area:px}
  .cf-saved--list .cf-saved-acts{grid-area:acts;justify-content:flex-end}
  .cf-saved--list .cf-saved-acts .cf-btn--primary{flex:1 1 auto}
  .cf-saved--strip .cf-saved-rows{margin:0 -16px;padding:2px 16px 4px;scroll-padding:0 16px}
}


/* ---- static/cf-new-launches.css ---- */
/* "New on Cartel Family" (cf-new-launches.js). Theme tokens only. The strip
 * scrolls sideways on the feed (its edge fades to say so); in Discover's
 * side column it is a list. Bars slide to a new value; entrance rests
 * visible and reduced motion never animates. */
[data-cf-new-launches]{margin:0 0 16px;min-width:0}
[data-cf-new-launches][hidden]{display:none}
.nl-h{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin:0 0 10px}
.nl-h h2{margin:0;font:700 16px/1.2 var(--font-ui);color:var(--ink)}
.nl-all{font:600 12px var(--font-ui);color:var(--acc);text-decoration:none;min-height:44px;display:inline-flex;align-items:center}
.nl-all:hover,.nl-all:focus-visible{text-decoration:underline}
.nl-list{display:flex;gap:10px;overflow-x:auto;scrollbar-width:none;padding:2px 2px 4px;
  -webkit-mask-image:linear-gradient(90deg,var(--ink) calc(100% - 32px),transparent);mask-image:linear-gradient(90deg,var(--ink) calc(100% - 32px),transparent)}
.nl-list::-webkit-scrollbar{display:none}
.nl-card{flex:0 0 228px;display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"link link" "curve buy";align-items:center;
  gap:8px 10px;padding:12px;border-radius:14px;background:var(--s1);border:1px solid var(--line, var(--s2));min-width:0}
.nl-link{grid-area:link;display:grid;grid-template-columns:36px minmax(0,1fr) auto;align-items:center;gap:10px;color:var(--ink);text-decoration:none;min-height:44px}
.nl-link:focus-visible{outline:none;box-shadow:var(--focus-ring);border-radius:10px}
.nl-img{width:36px;height:36px;border-radius:10px;object-fit:cover;background:var(--s2)}
.nl-img--none{display:flex;align-items:center;justify-content:center;font:700 12px var(--font-ui);color:var(--ink2)}
.nl-main{display:flex;flex-direction:column;min-width:0}
.nl-main b{font:700 14px/1.2 var(--font-ui)}
.nl-main small{font:500 11px/1.3 var(--font-ui);color:var(--ink3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nl-mc{font:700 13px var(--font-num, var(--font-mono));color:var(--ink)}
.nl-curve{grid-area:curve;height:6px;border-radius:3px;background:var(--s2);overflow:hidden}
.nl-curve i{display:block;height:100%;width:var(--p);background:var(--acc);border-radius:3px;transition:width .6s cubic-bezier(.2,.7,.2,1)}
.nl-grad{grid-area:curve;justify-self:start;font:700 10px/1.3 var(--font-ui);padding:2px 6px;border-radius:5px;color:var(--up);background:var(--upBg)}
.nl-buy{grid-area:buy;min-height:44px}
/* Discover's side column: the same cards, stacked. */
[data-cf-new-launches="list"] .nl-list{flex-direction:column;overflow:visible;-webkit-mask-image:none;mask-image:none}
[data-cf-new-launches="list"] .nl-card{flex:none}
.nl-in{animation:nl-in .5s cubic-bezier(.2,.7,.2,1) both}
@keyframes nl-in{from{opacity:.001;transform:translateY(8px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion: reduce){.nl-curve i{transition:none}.nl-in{animation:none}}


/* ---- static/cf-signin-methods.css ---- */
/* Get-started sheet: the passkey, EVM-wallet, password and "secure your
   sign-in" screens added by wallet-onboarding.js. Tokens only (cf-theme.css);
   a literal colour works in one theme and breaks the other. Injected by
   passkeys.py beside cf-passkey.js. */
.oa-ob-modal .oa-ob-remember{margin:14px 0 4px;justify-content:center}
.oa-ob-modal .oa-ob-pk{display:flex;flex-direction:column;gap:10px}
.oa-ob-modal .oa-ob-pk-lead{margin:0;font:600 14px/1.45 var(--font-ui);color:var(--ink)}
.oa-ob-modal .oa-ob-pk-lead[data-kind="bad"]{color:var(--dn)}
.oa-ob-modal .oa-ob-pk-note{margin:0;font:500 12.5px/1.5 var(--font-ui);color:var(--ink2)}
.oa-ob-modal .oa-ob-pk-note b{color:var(--ink);font-weight:700}
.oa-ob-modal .oa-ob-secure{display:flex;flex-direction:column;gap:12px}
.oa-ob-modal .oa-ob-secure .oa-ob-method[disabled]{opacity:.55;cursor:not-allowed}
.oa-ob-modal .oa-ob-mnote[data-kind="good"]{color:var(--up)}
.oa-ob-modal .oa-ob-mnote[data-kind="bad"]{color:var(--dn)}
.oa-ob-modal .oa-ob-secure-pw{display:flex;flex-direction:column;gap:8px}
.oa-ob-modal .oa-ob-secure-pw[hidden]{display:none}
.oa-ob-modal .oa-ob-inline-btn{
  align-self:flex-start;min-height:44px;padding:0 16px;border-radius:10px;border:1px solid var(--line);
  background:var(--acc);color:var(--onAcc);font:700 13px var(--font-ui);cursor:pointer}
.oa-ob-modal .oa-ob-inline-btn:disabled{opacity:.6;cursor:progress}


/* ---- static/cf-modal.css ---- */
/* Cartel Family — the one modal / dialog / bottom-sheet surface.
 *
 * CLAUDE.md, "Design system": *one* set of modals and sheets. Before this file
 * the app had `.s-modal` duplicated verbatim into six templates (each with a
 * slightly different `.s-title`), a bespoke `.oa-ob-*` shell for wallet
 * onboarding, `.gd-modal-*`, `.w-modal-*`, `.lm-token-modal`, `.pt-sheet-*`
 * and more — none of which agreed on padding, radius, close-button position,
 * focus handling or where an error message goes.
 *
 * Shape follows static/cf-trade-sheet.js, which already got this right:
 * centred dialog from 768px up, bottom sheet below it, same scrim, same
 * swipe-to-dismiss, same reduced-motion behaviour. This is that behaviour
 * generalised, not a second system next to it.
 *
 * COLOURS: tokens from cf-theme.css only. A literal works in one theme and
 * breaks the other (`.pt-nb-more-item{color:#c7ccd4}` was legible on dark and
 * nearly invisible on light). The one colour defined here is --cf-scrim,
 * because cf-theme.css ships no scrim token — and it is declared for BOTH
 * themes below, in all three of the theme states cf-theme.css defines
 * (system / forced light / forced dark), so it cannot have that bug.
 */

:root{
  --cf-scrim:rgba(3,8,14,.74);
  --cf-modal-shadow:0 24px 64px rgba(0,0,0,.55);
}
:root[data-theme="light"] body.cf-themable,
html:not([data-theme]) body.cf-themable.cf-light{
  --cf-scrim:rgba(11,20,32,.44);
  --cf-modal-shadow:0 18px 48px rgba(11,20,32,.18);
}
@media (prefers-color-scheme: light){
  :root:not([data-theme]) body.cf-themable{
    --cf-scrim:rgba(11,20,32,.44);
    --cf-modal-shadow:0 18px 48px rgba(11,20,32,.18);
  }
}

/* ── layer ──────────────────────────────────────────────────────────────
 * One layer per open modal. Stacking (a modal opened from a modal) is just
 * another layer at a higher z-index; nothing about the scroll lock or the
 * focus trap is per-instance state that a second instance could corrupt.
 * Above cf-trade-sheet (9001) and above app-ux.css's forced 1500 for the
 * legacy shells, so a confirm raised from either one is never buried.
 */
.cf-modal-layer{
  position:fixed;inset:0;z-index:9400;
  display:flex;align-items:center;justify-content:center;
  /* Safe-area aware, so a dialog never sits under a notch or a home
     indicator. The side gutter stays 16px at every width. */
  padding:calc(var(--space-md,16px) + env(safe-area-inset-top,0px))
          var(--space-md,16px)
          calc(var(--space-md,16px) + env(safe-area-inset-bottom,0px));
  font-family:var(--font-ui,system-ui,-apple-system,sans-serif);
}


.cf-modal-scrim{
  position:absolute;inset:0;
  background:var(--scrim,var(--cf-scrim));
  opacity:0;transition:opacity .3s ease;
}
.cf-modal-layer.cf-on .cf-modal-scrim{opacity:1}

/* ── the sheet (DESIGN_PROMPT §4) ───────────────────────────────────────
 * Desktop: a 440px right drawer, full height. Phone: a bottom sheet, 22px top
 * corners, a 5px grab handle, max-height 90%. Both move on .38s
 * var(--ease-spring). A small confirm (size "sm") stays a centred dialog on
 * desktop -- a one-line question does not need a drawer. Measured from the
 * design's sheet shell; every colour is a design token.
 */
.cf-modal{
  position:relative;
  display:flex;flex-direction:column;
  width:100%;max-width:440px;max-height:100%;
  background:var(--s1);
  color:var(--ink);
  border:0;
  border-radius:16px;
  box-shadow:var(--e2);
  overflow:hidden;
  opacity:0;transform:translateY(8px) scale(.98);
  transition:opacity .2s ease,transform .38s var(--ease-spring);
  text-align:left;
}
.cf-modal-layer.cf-on .cf-modal{opacity:1;transform:none}
.cf-modal:focus{outline:none}
.cf-modal[data-size="sm"]{max-width:380px;border:1px solid var(--line)}

@media (min-width:768px){
  .cf-modal-layer:has(.cf-modal:not([data-size="sm"])){align-items:stretch;justify-content:flex-end;padding:0}
  .cf-modal:not([data-size="sm"]){
    max-width:440px;height:100%;max-height:none;border-radius:0;
    border-left:1px solid var(--line);box-shadow:-20px 0 60px rgba(0,0,0,.35);
    opacity:1;transform:translateX(100%);
  }
  .cf-modal[data-size="lg"]{max-width:520px}
  .cf-modal-layer.cf-on .cf-modal:not([data-size="sm"]){transform:none}
}

/* Grip is sheet-only. */
.cf-modal-grip{display:none}

/* ── header: title 18/800, a 36px round close ─────────────────────────── */
.cf-modal-head{
  display:flex;align-items:center;gap:10px;
  padding:10px 20px 6px;
  flex:0 0 auto;
}
.cf-modal-heading{min-width:0;flex:1;display:flex;flex-direction:column;gap:2px}
.cf-modal-title{margin:0;font:800 18px/1.3 var(--font-ui);color:var(--ink)}
.cf-modal-sub{margin:0;font:500 13px/1.45 var(--font-ui);color:var(--ink2)}

.cf-modal-back,.cf-modal-x{
  flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;
  width:36px;height:36px;margin:0;padding:0;
  border:0;border-radius:50%;
  background:var(--s2);color:var(--ink2);cursor:pointer;
  transition:color .14s,background .14s;
}
.cf-modal-back:hover,.cf-modal-x:hover{color:var(--ink)}
.cf-modal-back svg{width:17px;height:17px;display:block}
.cf-modal-x svg{width:14px;height:14px;display:block}
.cf-modal-x:focus-visible,.cf-modal-back:focus-visible,
.cf-modal-act:focus-visible{outline:2px solid var(--acc);outline-offset:2px}
/* On touch widths the 36px disc keeps its size and takes a 44px tap: the
   fill is clipped to the content box, as navbar.css draws the avatar. The
   negative margin keeps the header's geometry unchanged. */
@media (pointer:coarse),(hover:none),(max-width:1024px){
  .cf-modal-back,.cf-modal-x{
    width:44px;height:44px;margin:-4px;padding:4px;box-sizing:border-box;background-clip:content-box;
  }
}

/* ── body ───────────────────────────────────────────────────────────── */
.cf-modal-body{
  flex:1 1 auto;min-height:0;
  padding:8px 20px 24px;
  overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;
  font:500 14px/1.45 var(--font-ui);color:var(--body);
}
.cf-modal-body:empty{padding-bottom:8px}
.cf-modal-body p{margin:0 0 10px}
.cf-modal-body p:last-child{margin-bottom:0}
.cf-modal-body strong,.cf-modal-body b{color:var(--ink);font-weight:700}
.cf-modal-body a{color:var(--accT)}

/* Explicit empty state: say there is nothing rather than draw something
   plausible (CLAUDE.md, "no invented data, ever"). */
.cf-modal-empty{display:flex;flex-direction:column;align-items:center;gap:6px;padding:24px 16px;text-align:center}
.cf-modal-empty-mark{
  width:40px;height:40px;border-radius:50%;border:1px dashed var(--ink3);
  display:grid;place-items:center;color:var(--ink2);margin-bottom:2px;
}
.cf-modal-empty-mark svg{width:16px;height:16px;display:block}
.cf-modal-empty-title{font:700 14px var(--font-ui);color:var(--ink)}
.cf-modal-empty-text{font:500 13px/1.5 var(--font-ui);color:var(--ink2);max-width:34ch}

/* Field primitives, so a migrated sheet does not have to bring its own. */
.cf-modal-field{display:block;margin:0 0 12px}
.cf-modal-label{display:block;margin:0 0 6px;font:600 12px/1.3 var(--font-ui);color:var(--ink2)}
.cf-modal-input,.cf-modal-textarea{
  box-sizing:border-box;width:100%;
  background:var(--bg);color:var(--ink);
  border:1px solid var(--line);border-radius:12px;
  font:500 15px/1.4 var(--font-num);
  padding:12px;outline:none;min-height:48px;
}
.cf-modal-textarea{min-height:96px;resize:none;font-size:13px;line-height:1.5}
.cf-modal-select{
  box-sizing:border-box;width:100%;min-height:48px;
  background:var(--bg);color:var(--ink);
  border:1px solid var(--line);border-radius:12px;
  font:600 14px/1.4 var(--font-ui);padding:11px 12px;outline:none;
}
.cf-modal-input:focus,.cf-modal-textarea:focus,.cf-modal-select:focus{border-color:var(--acc)}
.cf-modal-input::placeholder,.cf-modal-textarea::placeholder{color:var(--ink2)}
.cf-modal-input:disabled,.cf-modal-select:disabled{opacity:.6;cursor:not-allowed}

/* input + trailing button (Max, paste, scan). */
.cf-modal-row{display:flex;gap:8px;align-items:stretch}
.cf-modal-row .cf-modal-input{flex:1;min-width:0}
.cf-modal-row-btn{
  flex:0 0 auto;min-width:64px;border:0;border-radius:12px;
  background:var(--s2);color:var(--accT);font:700 12px/1 var(--font-ui);cursor:pointer;
}
.cf-modal-row-btn:disabled{opacity:.45;cursor:not-allowed}

/* Secondary line under a field: chain, balance, unit. */
.cf-modal-meta{
  display:flex;justify-content:space-between;gap:10px;margin-top:6px;
  font:500 12px/1.35 var(--font-num);color:var(--ink2);
}
.cf-modal-meta .cf-accent{color:var(--accT)}

.cf-modal-stat{display:flex;gap:8px;margin:0 0 12px}
.cf-modal-stat>div{flex:1;min-width:0;background:var(--bg);border:1px solid var(--line);border-radius:12px;padding:10px}
.cf-modal-stat dt{margin:0 0 2px;font:600 11px var(--font-ui);color:var(--ink2)}
.cf-modal-stat dd{
  margin:0;font:500 16px/1.2 var(--font-num);font-variant-numeric:tabular-nums;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;
}
.cf-modal-stat dd.cf-accent{color:var(--accT)}

.cf-modal-copy{
  display:flex;align-items:center;gap:8px;background:var(--bg);border:1px solid var(--line);
  border-radius:14px;padding:12px 14px;margin:0 0 6px;
}
.cf-modal-copy code{flex:1;min-width:0;word-break:break-all;font:500 13px/1.5 var(--font-num);color:var(--ink)}
.cf-modal-copy button{
  flex:0 0 auto;width:36px;height:36px;display:grid;place-items:center;border:0;border-radius:10px;
  background:var(--s2);color:var(--ink2);cursor:pointer;transition:color .14s;
}
.cf-modal-copy button:hover{color:var(--ink)}
.cf-modal-copy button.cf-done{color:var(--up)}
.cf-modal-copy button svg{width:15px;height:15px;display:block}

.cf-modal-hint{min-height:15px;margin:0 0 4px;font:700 12px/15px var(--font-ui);color:var(--accT)}

.cf-modal-check{
  display:flex;align-items:center;gap:10px;margin:14px 0 0;
  font:600 14px/1.4 var(--font-ui);color:var(--ink);cursor:pointer;
}
.cf-modal-check input{flex:0 0 auto;width:22px;height:22px;margin:0;accent-color:var(--acc);cursor:pointer}

/* ── footer: actions, and the message that belongs WITH them ────────────
 * The failure text sits immediately above the button that produced it. */
.cf-modal-foot{
  flex:0 0 auto;padding:0 20px 20px;
  padding-bottom:calc(20px + env(safe-area-inset-bottom,0px));
  display:flex;flex-direction:column;gap:10px;
}
.cf-modal-foot[hidden]{display:none}

.cf-modal-note{display:flex;align-items:flex-start;gap:8px;padding:10px 12px;border-radius:12px;font:500 13px/1.5 var(--font-ui);border:0}
.cf-modal-note[hidden]{display:none}
.cf-modal-note svg{flex:0 0 auto;width:15px;height:15px;margin-top:2px;display:block}
.cf-modal-note[data-kind="error"]{color:var(--dn);background:var(--dnBg)}
.cf-modal-note[data-kind="success"]{color:var(--up);background:var(--upBg)}
.cf-modal-note[data-kind="info"]{color:var(--ink2);background:var(--s2)}

.cf-modal-actions{display:flex;gap:8px;flex-wrap:wrap}
.cf-modal-actions:empty{display:none}

.cf-modal-act{
  flex:1 1 auto;min-width:120px;min-height:48px;
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  border:0;border-radius:12px;font:700 14px/1 var(--font-ui);
  cursor:pointer;padding:0 16px;transition:opacity .14s,background .14s,color .14s;
}
/* The class rule above would beat the UA's [hidden]{display:none}; this
   re-asserts it with more specificity so setAction({hidden:true}) hides. */
.cf-modal-act[hidden]{display:none}

/* The accent is a FILL with ink text (--onAcc), never a text colour. */
.cf-modal-act[data-variant="primary"]{background:var(--acc);color:var(--onAcc)}
.cf-modal-act[data-variant="primary"][data-full="1"]{min-height:54px;border-radius:14px;font-weight:800;font-size:15px}
.cf-modal-act[data-variant="ghost"]{background:var(--s2);color:var(--ink)}
/* Destructive is outlined, so no single foreground has to read on a red fill
   in both themes. */
.cf-modal-act[data-variant="danger"]{background:transparent;color:var(--dn);border:1px solid var(--dn)}
.cf-modal-act:disabled{background:var(--s2);color:var(--ink2);cursor:not-allowed}
.cf-modal-act[data-full="1"]{flex:1 1 100%}

/* Busy: the spinner joins the label, so the button never changes width. */
.cf-modal-spin{
  width:14px;height:14px;flex:0 0 auto;border-radius:50%;
  border:2px solid currentColor;border-top-color:transparent;
  animation:cf-modal-spin .62s linear infinite;
}
@keyframes cf-modal-spin{to{transform:rotate(360deg)}}

/* An action waiting on a dependency it does not have yet says so, and cannot
   be pressed. */
.cf-modal-act[data-pending="1"]{cursor:progress}

/* ── phone: bottom sheet ────────────────────────────────────────────── */
@media (max-width:767px){
  .cf-modal-layer{align-items:flex-end;padding:0}
  .cf-modal,.cf-modal[data-size="sm"]{
    /* dvh, not vh: on a phone the URL bar collapses and expands. */
    max-width:none;width:100%;max-height:90dvh;
    border:0;border-top:1px solid var(--line);
    border-radius:22px 22px 0 0;
    transform:translateY(100%) scale(1);
    transition:transform .38s var(--ease-spring);
    opacity:1;
  }
  .cf-modal-layer.cf-on .cf-modal{transform:translateY(0)}
  .cf-modal.cf-drag{transition:none}
  .cf-modal-grip{
    display:block;flex:0 0 auto;width:40px;height:5px;margin:10px auto 0;
    border-radius:3px;background:var(--line);
  }
  .cf-modal-head{padding-top:10px}
  .cf-modal-act{min-width:0}
  /* A phone keyboard must never hide the primary action. */
  .cf-modal-foot{position:sticky;bottom:0;background:var(--s1)}
  /* 16px minimum or iOS zooms the whole sheet on focus. */
  .cf-modal-input,.cf-modal-textarea{font-size:16px}
}

/* ── reduced motion: the finished state ─────────────────────────────── */
@media (prefers-reduced-motion:reduce){
  .cf-modal,.cf-modal-scrim{transition:none}
  .cf-modal,.cf-modal-layer .cf-modal,.cf-modal-layer .cf-modal:not([data-size="sm"]){transform:none;opacity:1}
  .cf-modal-layer:not(.cf-on){opacity:0}
  .cf-modal-spin{animation-duration:1.4s}
}


/* ---- static/wallet-onboarding.css ---- */
/* Cartel Family — "Get started" (DESIGN_PROMPT §4), inside the shared sheet.
 *
 * There is no dialog in this file. The frame, the scrim, the heading, the
 * footer, the focus trap, the scroll lock and the phone bottom sheet all come
 * from cf-modal.css / cf-modal.js — the app's one sheet system. What is here
 * is only what is specific to the onboarding steps, scoped under
 * `.oa-ob-modal`, which the script stamps on the dialog element. Measured
 * from CFFlows.dc.html.
 *
 * COLOURS: design tokens from cf-theme.css only. This stylesheet is injected
 * into EVERY HTML response, so one literal here is a literal everywhere, and
 * the app has a light and a dark palette. The method tiles take token
 * colours rather than each wallet's brand hex for the same reason.
 */

/* ── the chooser: pick a method ────────────────────────────────────────── */
.oa-ob-modal .cf-modal-act[hidden]{display:none}
.oa-ob-modal .cf-modal-body{display:flex;flex-direction:column;gap:14px}

/* ── the join screen (owner, 2026-10-15): mark, title, pitch, three feature
   rows, one molten button, one outlined button, a footnote. The dialog's
   own heading stays for assistive tech and is hidden visually here; the ✕
   keeps the top-right corner. */
.oa-ob-modal.oa-ob-chooser .cf-modal-heading{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.oa-ob-modal.oa-ob-chooser .cf-modal-head{padding-bottom:0}
.oa-ob-modal.oa-ob-chooser .cf-modal-x{margin-left:auto}
.oa-ob-modal .oa-ob-join{display:flex;flex-direction:column;align-items:center;gap:14px;text-align:center;padding-top:2px}
.oa-ob-modal .oa-ob-mark{
  position:relative;width:64px;height:64px;border-radius:18px;overflow:hidden;flex:none;background:var(--s2);
  box-shadow:0 0 0 1px var(--line),0 10px 28px var(--accBg);
}
/* The kit's small lockup crop (cf-rail.css): the Boss Bull's face fills the
   tile; the whole icon at this size is mostly dark padding. */
.oa-ob-modal .oa-ob-mark img{position:absolute;width:118%;height:118%;max-width:none;left:-9%;top:-8%;display:block;object-fit:cover}
.oa-ob-modal .oa-ob-title{margin:-2px 0 0;font:700 24px/1.15 var(--font-display);letter-spacing:-.02em;color:var(--ink)}
.oa-ob-modal .oa-ob-pitch{margin:-4px 0 0;max-width:38ch;font:500 14px/1.5 var(--font-ui);color:var(--ink2)}
.oa-ob-modal .oa-ob-feats{list-style:none;margin:2px 0 0;padding:0;width:100%;display:flex;flex-direction:column;gap:14px;text-align:left}
.oa-ob-modal .oa-ob-feat{display:flex;align-items:flex-start;gap:14px}
.oa-ob-modal .oa-ob-feat-ico{width:44px;height:44px;border-radius:50%;flex:none;display:grid;place-items:center;background:var(--accBg);color:var(--accT)}
.oa-ob-modal .oa-ob-feat-ico svg{width:22px;height:22px;display:block}
.oa-ob-modal .oa-ob-feat-text{display:grid;gap:2px;min-width:0;padding-top:2px}
.oa-ob-modal .oa-ob-feat-text b{font:700 15px/1.3 var(--font-ui);color:var(--ink)}
.oa-ob-modal .oa-ob-feat-text span{font:500 13px/1.45 var(--font-ui);color:var(--ink2)}
.oa-ob-modal .oa-ob-ctas{width:100%;display:flex;flex-direction:column;gap:10px;margin-top:2px}
/* The labels name every method ("Sign in with Telegram, X, Google or Apple"),
   so the pill may wrap at 320px instead of clipping. */
.oa-ob-modal .oa-ob-cta{white-space:normal;line-height:1.25;padding:12px 18px;min-height:54px;height:auto}
.oa-ob-modal .oa-ob-foot{margin:0;max-width:42ch;font:500 12px/1.5 var(--font-ui);color:var(--ink2)}
@media (prefers-reduced-motion:no-preference){
  /* A short rise, position only: a paused animation (app-ux.css pauses a
     hidden tab) leaves the rows visible, never parked at opacity 0. */
  .oa-ob-modal .oa-ob-feat{animation:oaObRise .5s var(--ease-out,ease-out) both}
  .oa-ob-modal .oa-ob-feat:nth-child(2){animation-delay:.06s}
  .oa-ob-modal .oa-ob-feat:nth-child(3){animation-delay:.12s}
  @keyframes oaObRise{from{transform:translateY(8px)}to{transform:none}}
}

.oa-ob-modal .oa-ob-methods{display:flex;flex-direction:column;gap:14px}
.oa-ob-modal .oa-ob-method{
  min-height:56px;display:flex;align-items:center;gap:12px;padding:0 14px;width:100%;
  background:var(--bg);border:1px solid var(--line);border-radius:14px;cursor:pointer;
  color:var(--ink);text-align:left;transition:border-color .14s;
}
.oa-ob-modal .oa-ob-method:hover:not(:disabled){border-color:var(--acc)}
.oa-ob-modal .oa-ob-method:focus-visible{outline:2px solid var(--acc);outline-offset:2px}
.oa-ob-modal .oa-ob-method:disabled{cursor:progress;opacity:.6}
.oa-ob-modal .oa-ob-code{
  position:relative;width:36px;height:36px;border-radius:10px;flex:none;display:flex;align-items:center;justify-content:center;
  background:var(--s2);border:1px solid var(--line);color:var(--ink2);overflow:hidden;
}
/* Our own methods draw a single-stroke glyph; a third-party brand draws its
   own mark (CFBrand.wallet), which replaces the generic wallet glyph. */
.oa-ob-modal .oa-ob-glyph{width:20px;height:20px;flex:none}
.oa-ob-modal .oa-ob-code .cf-logo{width:24px;height:24px;margin:0;vertical-align:0;border-radius:6px;object-fit:contain}
.oa-ob-modal .oa-ob-code:has(.cf-logo) .oa-ob-glyph{display:none}
.oa-ob-modal .oa-ob-method:hover:not(:disabled) .oa-ob-code{border-color:var(--acc)}
.oa-ob-modal .oa-ob-method:hover:not(:disabled) .oa-ob-glyph{color:var(--acc)}
.oa-ob-modal .oa-ob-mlabel{font:700 15px var(--font-ui);flex:1;min-width:0}
/* The note wraps on the right (46% at most) rather than riding over the label at 320px. */
.oa-ob-modal .oa-ob-mnote{font:500 12px/1.3 var(--font-ui);color:var(--ink2);flex:none;max-width:46%;text-align:right}

/* The three big rows (the "Sign in" step): Telegram, X, Google (Apple when
   configured). 64px, a 40px mark tile, the label at 16/700; the lit edge is
   the one gold line the Noir component library draws on a primary control. */
.oa-ob-modal .oa-ob-primary{gap:10px}
.oa-ob-modal .oa-ob-method.is-primary{
  min-height:64px;padding:0 16px;gap:14px;border-radius:16px;background:var(--s1);
  border-color:var(--line);position:relative;
}
.oa-ob-modal .oa-ob-method.is-primary .oa-ob-code{width:40px;height:40px;border-radius:12px}
.oa-ob-modal .oa-ob-method.is-primary .oa-ob-code .cf-logo{width:26px;height:26px}
.oa-ob-modal .oa-ob-method.is-primary .oa-ob-mlabel{font-size:16px}
.oa-ob-modal .oa-ob-method.is-primary::after{
  content:"";position:absolute;left:14px;right:14px;top:-1px;height:1px;opacity:0;
  background:linear-gradient(90deg,transparent,var(--acc),transparent);transition:opacity .16s;
}
.oa-ob-modal .oa-ob-method.is-primary:hover:not(:disabled)::after,
.oa-ob-modal .oa-ob-method.is-primary:focus-visible::after{opacity:1}

@media (prefers-reduced-motion:reduce){
  .oa-ob-modal .oa-ob-method.is-primary::after{transition:none}
}

.oa-ob-modal .oa-ob-foot-note,
.oa-ob-modal .oa-ob-security-note,.oa-ob-modal .oa-ob-lock-note{
  display:flex;align-items:center;justify-content:center;gap:7px;
  font:500 12px var(--font-ui);color:var(--ink2);
}
.oa-ob-modal .oa-ob-foot-note svg,.oa-ob-modal .oa-ob-security-note svg,
.oa-ob-modal .oa-ob-lock-note svg{width:14px;height:14px;flex:0 0 auto}
.oa-ob-modal .oa-ob-foot-note b{padding:0 2px;color:var(--ink2);font-weight:700}
.oa-ob-modal .oa-ob-security-note{justify-content:flex-start}

/* ── Telegram login mounts here ─────────────────────────────────────── */
.oa-ob-modal .oa-ob-tg{background:var(--bg);border:1px solid var(--line);border-radius:14px;padding:16px}

/* ── create: progress, warning, the keys (revealed on demand) ─────────── */
.oa-ob-modal .oa-ob-progress{
  display:grid;grid-template-columns:auto 1fr auto 1fr auto;align-items:start;gap:8px;
}
.oa-ob-modal .oa-ob-progress-line{height:1px;background:var(--line);margin-top:13px}
.oa-ob-modal .oa-ob-step{display:grid;justify-items:center;gap:5px;color:var(--ink2);font:600 11px var(--font-ui);white-space:nowrap}
.oa-ob-modal .oa-ob-step-dot{
  display:grid;place-items:center;width:26px;height:26px;border-radius:50%;
  background:var(--s2);color:var(--ink2);font:700 11px var(--font-ui);
}
.oa-ob-modal .oa-ob-step.done,.oa-ob-modal .oa-ob-step.active{color:var(--accT)}
.oa-ob-modal .oa-ob-step.done .oa-ob-step-dot,
.oa-ob-modal .oa-ob-step.active .oa-ob-step-dot{background:var(--acc);color:var(--onAcc)}

.oa-ob-modal .oa-ob-warning{
  display:grid;grid-template-columns:22px 1fr;align-items:center;gap:10px;
  padding:10px 12px;border:1px solid var(--proLine);border-radius:12px;background:var(--proBg);
  font:600 13px/1.45 var(--font-ui);color:var(--ink);
}
.oa-ob-modal .oa-ob-shield{width:20px;height:22px;color:var(--pro)}

.oa-ob-modal .oa-ob-fields{display:flex;flex-direction:column;gap:10px;background:var(--bg);
  border:1px solid var(--line);border-radius:14px;padding:14px}
.oa-ob-modal .oa-ob-field-card{display:flex;flex-direction:column;gap:6px}
.oa-ob-modal .oa-ob-field-label{font:500 12px var(--font-num);color:var(--ink2)}
.oa-ob-modal .oa-ob-value-row{display:flex;align-items:stretch;gap:6px;min-width:0}
.oa-ob-modal .oa-ob-value{
  display:flex;align-items:center;min-width:0;min-height:44px;flex:1;
  border-radius:10px;background:var(--s2);color:var(--ink);padding:0 12px;
  font:500 13px/1.5 var(--font-num);
}
.oa-ob-modal .oa-ob-value-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.oa-ob-modal .oa-ob-secret-input{
  box-sizing:border-box;width:100%;min-width:0;border:0;outline:0;
  background:transparent;color:var(--ink);font:500 13px/1 var(--font-num);
}
.oa-ob-modal .oa-ob-secret-input[type=password]{letter-spacing:.14em}
.oa-ob-modal .oa-ob-icon-btn,.oa-ob-modal .oa-ob-show-btn{
  display:flex;align-items:center;justify-content:center;gap:5px;flex:0 0 auto;min-height:44px;
  border:0;border-radius:10px;background:var(--s2);color:var(--accT);
  font:700 12px/1 var(--font-ui);cursor:pointer;
}
.oa-ob-modal .oa-ob-icon-btn{width:44px}
.oa-ob-modal .oa-ob-show-btn{padding:0 12px}
.oa-ob-modal .oa-ob-icon-btn.copied{color:var(--up)}
.oa-ob-modal .oa-ob-icon-btn:focus-visible,.oa-ob-modal .oa-ob-show-btn:focus-visible{outline:2px solid var(--acc);outline-offset:2px}
.oa-ob-modal .oa-ob-icon{width:17px;height:17px;display:block}
.oa-ob-modal .oa-ob-check{margin:0}

/* ── import: base58 / JSON array, validated live ────────────────────── */
.oa-ob-modal .oa-ob-seg{display:flex;background:var(--s2);border-radius:10px;padding:2px}
.oa-ob-modal .oa-ob-seg button{
  flex:1;height:34px;border:0;border-radius:8px;background:transparent;
  font:700 13px var(--font-ui);color:var(--ink2);cursor:pointer;
}
.oa-ob-modal .oa-ob-seg button.on{background:var(--s1);color:var(--ink)}
.oa-ob-modal .oa-ob-seg button:focus-visible{outline:2px solid var(--acc);outline-offset:2px}
.oa-ob-modal .cf-modal-body>.cf-modal-label{margin:0 0 -8px}
.oa-ob-modal textarea.oa-ob-secret{min-height:96px}
.oa-ob-modal textarea.oa-ob-bad{border-color:var(--dn)}
.oa-ob-modal .oa-ob-keymsg{font:600 12px var(--font-ui);color:var(--ink2);margin-top:-6px}
.oa-ob-modal .oa-ob-keymsg[data-kind="bad"]{color:var(--dn)}
.oa-ob-modal .oa-ob-keymsg[data-kind="good"]{color:var(--up)}
.oa-ob-modal .oa-ob-label-optional small{font-size:11px;font-weight:600;color:var(--ink2)}

@media (max-width:767px){
  /* The reveal button keeps its 44px target but drops the word. */
  .oa-ob-modal .oa-ob-show-btn{width:44px;padding:0;font-size:0}
  .oa-ob-modal .oa-ob-show-btn .oa-ob-icon{width:19px;height:19px}
}
@media (max-width:370px){
  .oa-ob-modal .oa-ob-progress{gap:4px}
  .oa-ob-modal .oa-ob-step{font-size:10px}
}

/* ── the pairing-code sheet (cf-wallet-connect.js, 2026-10-12) ──────────
   The home-screen app types the code the signing page shows. Tokens only. */
.cf-pair-sheet .cf-pair-lede{margin:0 0 14px;font:500 14px/1.5 var(--font-ui);color:var(--body,var(--ink))}
.cf-pair-sheet .cf-pair-input{
  height:56px;text-align:center;
  font:700 26px/1 var(--font-num);letter-spacing:.18em;text-transform:uppercase;
  color:var(--ink);font-variant-numeric:tabular-nums;
}
.cf-pair-sheet .cf-pair-fine{margin:10px 0 0;font:500 12px/1.45 var(--font-ui);color:var(--ink2)}
.cf-pair-sheet .cf-pair-steps{margin:0;padding:0 0 0 20px;display:grid;gap:8px;
  font:500 14px/1.45 var(--font-ui);color:var(--body,var(--ink))}
.cf-pair-sheet .cf-pair-steps b{color:var(--ink);font-weight:700}
.cf-pair-sheet .cf-pair-steps li::marker{color:var(--accT);font-weight:700}

