/* ═══════════════════════════════════════════
   JETONOMY DESIGN TOKENS
   The ONE place every --jt-* custom property is declared.
   Theme-adaptive: inherits from the host theme / WP theme.json,
   falls back to neutral defaults.
   ═══════════════════════════════════════════

   Why this is its own stylesheet, loaded as handle `jetonomy-tokens`:

   Blocks (Login, Navigation, Feed, Compose) render on ANY page — a
   page-builder canvas, a widget area, a landing page — while jetonomy.css
   only loads on /community/ routes. The tokens therefore cannot live in
   jetonomy.css, or a block on a landing page renders unstyled. They used to
   be duplicated into blocks.css as a parallel --jtb-* layer for exactly this
   reason; that duplication is what this file replaces. Both `jetonomy` and
   `jetonomy-blocks` declare this handle as a dependency, so there is one
   declaration and it reaches every page a Jetonomy surface can appear on —
   and a landing page with one login widget does not download the ~90KB
   community stylesheet to get its colours.

   DECLARE ON :root ONLY — never `:root, .jt-app`.

   :root is <html>, an ancestor of every element, so adding `.jt-app` buys no
   extra reach. What it DOES buy is a bug: a .jt-app nested inside another
   .jt-app (the Login block carries the class and can render inside the
   community sidebar) RE-DECLARES the whole token set at its own scope instead
   of inheriting it. Same reasoning for dark mode: reassign on the class the
   host theme puts on <body> so every descendant inherits, with no per-block,
   per-component rule anywhere. Adding a component to this file's selector list
   is always the wrong fix — see the CSS Token Rules in CLAUDE.md. */

  :root {
    /* Typography — BuddyNext first, then WP theme.json, then inherit for classic themes */
    --jt-font: var(--font-body, var(--wp--preset--font-family--body, inherit));
    --jt-font-heading: var(--font-display, var(--wp--preset--font-family--heading, inherit));
    --jt-font-mono: var(--wp--preset--font-family--monospace, ui-monospace, SFMono-Regular, Menlo, monospace);

    /* Colors — adopt the active theme's own brand token first so the plugin
       reads as native (and follows the theme's dark mode automatically when the
       theme flips its tokens), then WP theme.json, then the popular page-builder
       themes, then a neutral fallback. Verified host-theme brand-token map:
         BuddyX / BuddyX Pro 5.1+ → --bx-color-accent (flip on [data-bx-mode="dark"])
         Reign 8.0+               → --reign-colors-theme
         BuddyNext                → --brand
         Any "primary"-slug theme → --wp--preset--color--primary (TT3, classic themes)
         Astra                    → --ast-global-color-0
         Kadence                  → --global-palette1
         Blocksy                  → --theme-palette-color-1
         GeneratePress / "accent" → --wp--preset--color--accent
       Canonical recipe: wp-plugin-development skill, ux-foundation
       "Host-Theme Token Adoption". A var() chain picks the first DEFINED token,
       and these are mutually exclusive per active theme, so order only sets
       precedence for the rare theme exposing two. */
    /* Adopt the host theme's brand colour. Owners cannot be made to run BuddyX or
       Reign, so the chain walks the tokens the popular themes actually expose,
       then WP's own presets, then the Appearance -> Accent default. An explicit
       accent in Appearance is emitted inline by palette_css() and outranks all
       of this. Verified against 11 themes; --nv-primary-accent (Neve) was being
       missed, which is why Neve sites rendered the fallback instead of their brand. */
    --jt-accent: var(--bx-color-accent, var(--reign-colors-theme, var(--brand, var(--wp--preset--color--primary, var(--ast-global-color-0, var(--global-palette1, var(--theme-palette-color-1, var(--nv-primary-accent, var(--wp--preset--color--accent, #0073aa)))))))));

    /* Readable text ON --jt-accent, derived from whatever colour we ended up
       adopting. This CANNOT be computed in PHP: --jt-accent usually resolves to a
       theme token the browser only learns at runtime, so the server never sees it.
       Hardcoding white failed WCAG AA on 7 of 11 themes measured — including Reign,
       whose lavender put white text at 2.13 on the "Create free account" button.
       Pull L out of the accent, snap it past the threshold, chroma 0 => pure
       black/white. 0.57 is not a guess: sweeping 0.40–0.80 against the real
       accents of 11 themes, 0.56–0.58 is the only band where all 11 clear AA, and
       0.57 centres it for themes we have not seen. Older engines keep the plain
       white fallback below (no worse than today). */
    --jt-accent-fg: var(--jt-white);
    --jt-accent-hover-fg: var(--jt-white);
    --jt-accent-hover: #2563EB;
    --jt-accent-hover: color-mix(in srgb, var(--jt-accent) 85%, black);
    --jt-accent-light: #EFF6FF;
    --jt-accent-light: color-mix(in srgb, var(--jt-accent) 10%, white);
    --jt-accent-muted: #DBEAFE;
    --jt-accent-muted: color-mix(in srgb, var(--jt-accent) 15%, white);

    --jt-text: var(--bx-color-fg, var(--text-1, var(--wp--preset--color--contrast, #1a1a1a)));
    --jt-text-secondary: #4B5563;
    --jt-text-secondary: color-mix(in srgb, var(--jt-text) 70%, transparent);
    /* Bumped from 60% → 65% so any text using --jt-text-tertiary against
       the default light bg passes WCAG AA 4.5:1 (was 3.48:1 at 60%). */
    --jt-text-tertiary: #6B7280;
    --jt-text-tertiary: color-mix(in srgb, var(--jt-text) 65%, transparent);

    --jt-bg: var(--bx-color-bg-elevated, var(--bg, var(--wp--preset--color--base, #ffffff)));
    --jt-bg-subtle: #F9FAFB;
    --jt-bg-subtle: color-mix(in srgb, var(--jt-text) 3%, var(--jt-bg));
    --jt-bg-muted: #F3F4F6;
    --jt-bg-muted: color-mix(in srgb, var(--jt-text) 6%, var(--jt-bg));
    --jt-bg-hover: #F9FAFB;
    --jt-bg-hover: color-mix(in srgb, var(--jt-text) 4%, var(--jt-bg));

    --jt-border: rgba(0,0,0,0.1);
    --jt-border: color-mix(in srgb, var(--jt-text) 10%, transparent);
    --jt-border: var(--bx-color-border, color-mix(in srgb, var(--jt-text) 10%, transparent));
    --jt-border-strong: rgba(0,0,0,0.18);
    --jt-border-strong: color-mix(in srgb, var(--jt-text) 18%, transparent);

    /* Semantic colors — BuddyNext first, then hardcoded fallback */
    --jt-success: var(--green, #16a34a);
    --jt-success-light: var(--green-bg, #dcfce7);
    --jt-warn: var(--amber, #ca8a04);
    --jt-warn-light: var(--amber-bg, #fef9c3);
    --jt-danger: var(--red, #dc2626);
    --jt-danger-light: var(--red-bg, #fee2e2);

    /* Trust level colors */
    --jt-tl0: #9ca3af;
    --jt-tl1: #60a5fa;
    --jt-tl2: #34d399;
    --jt-tl3: #a78bfa;
    --jt-tl4: #f472b6;
    --jt-tl5: #fbbf24;

    /* Badge tiers */
    --jt-badge-bronze: #cd7f32;
    --jt-badge-silver: #9ca3af;
    --jt-badge-gold: #f59e0b;

    /* Radius — BuddyNext first, then WP custom, then hardcoded */
    --jt-radius: var(--r-md, var(--wp--custom--border-radius, 8px));
    --jt-radius-sm: var(--r-sm, calc(var(--jt-radius) * 0.5));
    --jt-radius-lg: var(--r-lg, calc(var(--jt-radius) * 1.5));
    --jt-radius-full: var(--r-full, 9999px);

    /* Surface — a card is a distinct surface that sits on the page, not the
       page colour itself. BuddyNext (the Community OS) owns --surface/--canvas;
       read it first so cards match exactly when running on it, with a matching
       standalone fallback (clean white card lifting off a faintly tinted
       canvas). Shared Wbcom standard: cards read --jt-surface, never --jt-bg. */
    --jt-surface: var(--surface, var(--jt-bg));
    --jt-canvas: var(--canvas, color-mix(in srgb, var(--jt-text) 2%, var(--jt-bg)));

    /* Elevation — soft, layered shadows matching BuddyNext's --bn-shadow-*.
       Shared standard: components pick a token, never a literal box-shadow, so
       elevation is uniform across BuddyNext, Jetonomy, MediaVerse, Listora, and
       Career Board. BuddyNext-first, with a matching standalone fallback. */
    --jt-shadow-xs: var(--bn-shadow-xs, 0 1px 2px rgba(16, 24, 40, 0.04));
    --jt-shadow-sm: var(--bn-shadow-sm, 0 1px 2px rgba(16, 24, 40, 0.04), 0 2px 4px rgba(16, 24, 40, 0.04));
    --jt-shadow-md: var(--bn-shadow-md, 0 2px 4px rgba(16, 24, 40, 0.04), 0 8px 16px rgba(16, 24, 40, 0.06));
    --jt-shadow-lg: var(--bn-shadow-lg, 0 8px 16px rgba(16, 24, 40, 0.06), 0 24px 48px rgba(16, 24, 40, 0.08));

    /* Spacing scale — used across every component for uniform rhythm.
       Do not add `px` values directly to components; pick a token. */
    --jt-space-1: 4px;
    --jt-space-2: 8px;
    --jt-space-3: 12px;
    --jt-space-4: 16px;
    --jt-space-5: 20px;
    --jt-space-6: 24px;
    --jt-space-8: 32px;
    --jt-space-10: 40px;
    --jt-space-12: 48px;

    /* Landing offset for deep-linked anchors (#reply-{id} from notifications,
       emails, JSON-LD). Host themes commonly pin a sticky header that CSS
       cannot measure, so a target scrolled flush to y=0 lands UNDER it — the
       reply is on screen but its author row is covered. The default clears a
       typical sticky header (the reference themes run 88-130px); a theme or
       owner with taller/no chrome overrides this one token rather than
       patching every anchor. Erring large is deliberate: too small hides
       content, too large only adds harmless breathing room above the target. */
    --jt-scroll-offset: 140px;

    /* Typography scale — rem-based so OS/theme zoom is respected.
       Components pick a token, never a literal rem value.
       Mobile breakpoint adjusts the visible size via the `fluid` vars. */
    --jt-text-2xs: 0.6875rem;   /* 11px — pill, caption */
    --jt-text-xs:  0.75rem;     /* 12px — meta, tag */
    --jt-text-sm:  0.8125rem;   /* 13px — secondary */
    --jt-text-base: 0.9375rem;  /* 15px — body, card title mobile */
    --jt-text-md:  1rem;        /* 16px — body desktop */
    --jt-text-lg:  1.0625rem;   /* 17px — card title desktop */
    --jt-text-xl:  1.125rem;    /* 18px — section title mobile */
    --jt-text-2xl: 1.25rem;     /* 20px — section title desktop, page title mobile */
    --jt-text-3xl: 1.75rem;     /* 28px — page title desktop */

    /* Line heights */
    --jt-leading-tight: 1.2;
    --jt-leading-snug:  1.35;
    --jt-leading-normal: 1.5;

    /* Tap target minimum — apply via min-height on interactive elements */
    --jt-tap: 40px;

    /* Transitions */
    --jt-ease: cubic-bezier(0.22, 1, 0.36, 1);
    --jt-dur: 0.15s;

    /* Constants — absolute values that do NOT adapt to the active theme */
    --jt-white: #ffffff;                 /* text/icons on colored backgrounds */
    --jt-code-bg: #1e1e1e;              /* code block bg — always dark (syntax highlighter) */
    --jt-code-fg: #d4d4d4;              /* code block text — always light */

    /* Warning variants */
    --jt-warn-dark: #7c5c00;
    --jt-warn-dark: color-mix(in srgb, var(--jt-warn) 80%, black);
    --jt-warn-border: #ffe082;
    --jt-warn-border: color-mix(in srgb, var(--jt-warn) 50%, white);
  }

  /* Derive readable text on the adopted accent. Split from the block above
     because relative colour syntax must be feature-gated: engines without it
     would drop the declaration and fall back to --jt-white, which is exactly
     the current (broken-on-light-accents) behaviour — never worse. */
  @supports (color: oklch(from red l c h)) {
    :root {
      --jt-accent-fg: oklch(from var(--jt-accent) clamp(0, (0.57 - l) * 1000, 1) 0 h);
      /* Hover is the accent mixed 85% toward black, i.e. strictly darker, so the
         black/white choice can flip against it. Derive it from the hover colour
         rather than reusing --jt-accent-fg and hoping. */
      --jt-accent-hover-fg: oklch(from var(--jt-accent-hover) clamp(0, (0.57 - l) * 1000, 1) 0 h);
    }
  }

  /* Dark mode — class-driven by the theme ONLY. The host theme decides
     whether its visitors see dark or light, and Jetonomy mirrors that
     decision via the .jt-dark class. We deliberately do NOT honor the
     browser's `prefers-color-scheme: dark` — a forum embedded in a
     light-themed site should stay light even on an OS-dark visitor;
     anything else creates a jarring contrast against the surrounding
     theme chrome and gets reported as a bug. The host theme's dark
     toggle is the single source of truth.

     Reassigned on the class itself — the class the host theme puts on <body> —
     NOT on `.jt-dark .jt-app`. Every Jetonomy surface is a descendant of that
     element, so all of them inherit: the app, the blocks wherever they render,
     and the BuddyPress integration surfaces (.jt-bp-forum, .jt-bp-recent,
     .jt-bp-topic-row) that sit inside BP-owned templates outside .jt-app. A
     `.jt-dark [class*="jt-bp-"]` escape hatch used to enumerate that last group
     specifically; inheriting from <body> covers it, so it is gone.

     [data-theme="dark"] is honoured alongside .jt-dark because blocks.css
     already supported it while jetonomy.css did not — a theme that signals dark
     only via the attribute got a half-dark plugin. One list, both signals. */
  .jt-dark,
  [data-theme="dark"] {
    --jt-text: #e5e5e5;
    --jt-text-secondary: rgba(229, 229, 229, 0.75);
    /* Bumped from 0.4 → 0.6 so text using --jt-text-tertiary passes WCAG AA
       on the dark surface (was 3.07:1 at 0.4, now ≈ 4.65:1). */
    --jt-text-tertiary: rgba(229, 229, 229, 0.6);
    --jt-bg: #171717;
    --jt-bg-subtle: #1e1e1e;
    --jt-bg-muted: #262626;
    --jt-bg-hover: #1f1f1f;
    --jt-border: rgba(255, 255, 255, 0.1);
    --jt-border-strong: rgba(255, 255, 255, 0.18);
    --jt-success-light: #052e16;
    --jt-warn-light: #422006;
    --jt-danger-light: #450a0a;
    /* Danger text on the dark --jt-bg (#171717) needs a lighter red than the
       light-mode #dc2626 to pass WCAG AA (#dc2626 on #171717 is 3.71:1, fails
       the 4.5 threshold). #ef4444 (Tailwind red-500) lands at 5.33:1 and stays
       recognisable as red. Used on .jt-more-dropdown__item--danger (Block user),
       destructive confirm buttons, and any other "danger" foreground in dark. */
    --jt-danger: #ef4444;
    /* Accent tints must invert in dark mode: the default light-mode
       recipe mixes accent with white, producing a near-white/mint wash
       (--jt-accent-muted ≈ #DBEAFE). On a dark panel that lands as a
       jarringly bright patch for unread notifications, pinned rows,
       vote hover, composer focus ring, tag hover, and accent badges.
       Re-derive both tints against the dark surface so they stay subtle
       tinted backgrounds that only a little lighter than the panel,
       not patches that scream. */
    --jt-accent-light: color-mix(in srgb, var(--jt-accent) 12%, #171717);
    --jt-accent-muted: color-mix(in srgb, var(--jt-accent) 18%, #171717);
    /* Warn-dark flips to a warm light tint in dark mode. It is used as
       text on the dark --jt-warn-light surface (locked-space banner,
       .jt-notice-warning). The light-mode default (color-mix warn 80%,
       black) stays olive and fails WCAG contrast against the dark warn
       background; this re-derives against white so the copy stays
       legible. */
    --jt-warn-dark: color-mix(in srgb, var(--jt-warn) 35%, white);
  }
