/* ==========================================================================
   🎨 LIFEWHEEL DESIGN TOKENS — THE SINGLE VISUAL SOURCE OF TRUTH
   ==========================================================================

   Extracted VERBATIM from app.css in Phase 2 of the Design System 2.0 work.
   Not one value was changed, renamed, added or removed in the move.

   --------------------------------------------------------------------------
   Why this file exists
   --------------------------------------------------------------------------
   The auth pages (login / register / password-help) sit outside the app
   cascade on purpose — they load `login.css` and never `app.css`. That left
   their palette hand-copied, with a comment in login.css instructing whoever
   changes a colour here to remember to change it there too. Nobody remembers
   forever. Now both cascades load THIS file, and login.css aliases its local
   names onto these tokens instead of restating their values.

   --------------------------------------------------------------------------
   ⚠️ LOAD ORDER MATTERS
   --------------------------------------------------------------------------
   This must be linked BEFORE app.css / login.css / marketing.css, because
   those stylesheets consume the tokens it defines. It defines tokens only —
   no selectors, no rules — so it can never override anything downstream.

   --------------------------------------------------------------------------
   ⚠️ THESE NAMES ARE A CONTRACT
   --------------------------------------------------------------------------
   ~15,000 lines of CSS and 45,000 lines of views resolve against them, and
   the Tailwind v4 `@theme inline` bridge in resources/css/app.entry.css maps
   onto these exact names. Add tokens freely; do not rename or remove one.

   Light IS `:root` — there is no `body.light-mode` override block. Dark
   redefines a subset. `html.pre-dark` stays in app.css with the other <html>
   rules, next to the pre-paint script that sets it.
   ========================================================================== */

/* ==========================================================================
   2. Design tokens
   ========================================================================== */
:root {
    /* -- Brand --------------------------------------------------------
       ONE accent. The product used to carry three — indigo `--primary`, a
       violet `--secondary` and a light-blue `--accent` — plus a glow token,
       and the result was that no two panels agreed on what "the brand
       colour" meant. A single accent, used sparingly, is what makes an
       interface read as one product rather than a collection of screens.

       #3341c9 is deliberately darker and less saturated than the indigo it
       replaces (#6366f1). On the off-white ground it measures 7.41:1 as
       text and 7.66:1 under a white label — it is legible as a FILL without
       needing to be darkened first, which the old accent was not.

       `--secondary` and `--accent` are kept as aliases, not as colours.
       Five stylesheets still reference them; pointing them at the one
       accent retires the second and third hues without a rename pass. */
    --primary: #3341c9;
    --primary-strong: #262fa3;
    --primary-soft: rgba(51, 65, 201, 0.08);
    /* Was a 0.38-alpha glow behind buttons and cards. §9 of the brief rules
       out glowing backgrounds, and a glow is what made the old dashboard
       read as generated rather than designed. Kept as a token because six
       rules reference it; it is now a hairline ring. */
    --primary-glow: rgba(51, 65, 201, 0.18);
    --secondary: var(--primary);
    --accent: var(--primary);

    /* -- Derived from --primary, for CONTRAST -------------------------
       ♿ --primary is whatever the user picked in الإعدادات ← لون التمييز,
       and a chosen accent is not guaranteed to carry a white label. The
       split is unchanged: --primary keeps the chosen colour and goes on
       borders, icons, focus rings and soft backgrounds; --primary-ink is
       the same hue darkened until a white label clears AA, and it is the
       ONLY thing allowed under `color: var(--text-on-primary)`.

       These color-mix values are the pre-paint fallback. ui.js recomputes
       both properly — it measures the real luminance of the chosen accent
       and darkens by exactly as much as that hue needs, which a fixed
       percentage cannot do. The default accent already passes, so the mix
       is a near no-op for it and only does real work for a custom colour. */
    --primary-ink: color-mix(in srgb, var(--primary) 94%, #000);
    --secondary-ink: var(--primary-ink);

    /* The accent used as TEXT on the page rather than as a fill. On the
       light ground the accent is already dark enough to be body text, so
       this is the accent itself; the dark theme overrides it. */
    --primary-text: var(--primary);

    /* ♿ The keyboard focus indicator. ONE definition, consumed by every
       `:focus-visible` rule as `outline: var(--focus-ring)` and by input
       focus borders as `border-color: var(--focus)`.
       On light it IS the accent (7.41:1 on the page). On dark the accent
       fill measures 2.53:1 against the page and 2.03:1 on --surface-3 —
       below the 3:1 a focus ring must clear — so the dark theme points
       this at --primary-text instead (see below). The shape never changes
       here: width and offset stay with the rule that draws it. (Phase 11) */
    --focus: var(--primary);
    --focus-ring: 2px solid var(--focus);

    /* -- Semantic -----------------------------------------------------
       ♿ Measured against the off-white ground AND against --surface-3, the
       tinted layer chips and list rows sit on. All four clear 4.5:1 as text
       and under a white label. */
    --success: #05704f;
    --success-soft: rgba(5, 112, 79, 0.09);
    --warning: #8a5300;
    --warning-soft: rgba(138, 83, 0, 0.10);
    --danger: #c02434;
    --danger-soft: rgba(192, 36, 52, 0.09);
    --info: #1d4ed8;
    --info-soft: rgba(29, 78, 216, 0.09);

    /* Money semantics — used everywhere an amount is shown. */
    --money-in: #05704f;
    --money-out: #b8213a;

    /* -- Surfaces (LIGHT is the default look now) ---------------------
       The stylesheet used to define dark in :root and light in an override
       class, which meant every unclassed surface — the 404 page, a print
       sheet, anything rendered before the boot script runs — was dark. The
       palettes are swapped: :root is the product's real ground, and
       `body.dark-mode` is the override.

       Off-white rather than pure white: #ffffff panels need something to
       sit ON, and a page that is also #ffffff gives a card no edge except
       its border. One step down is enough. */
    --bg-color: #fbfbfc;
    /* No radial glow. The value is `none` rather than deleted because one
       rule paints it; the token stays so that rule keeps resolving. */
    --bg-gradient: none;
    --surface: #ffffff;
    --surface-strong: #ffffff;
    --surface-2: #f4f5f7;
    --surface-3: #eceef1;
    /* "Glass" is a misnomer now and is kept only as a name. §9 rules out
       glassmorphism; these resolve to ordinary opaque panels. */
    --glass-bg: #ffffff;
    --glass-border: #e3e5e9;
    --glass-highlight: #f4f5f7;
    --border: #e3e5e9;
    --border-strong: #cfd2d9;
    --overlay: rgba(14, 15, 19, 0.42);

    /* -- Text ---------------------------------------------------------
       Near-black, not black: #000 on off-white is harsher than any printed
       page and is the single most common tell of an unconsidered palette. */
    --text-main: #0e0f13;
    --text-muted: #5b6270;
    /* ♿ --text-faint has to clear 4.5:1 on the DARKEST of the three grounds
       it lands on (--surface-3, #eceef1), not just on the page background.
       #6e7482 measured 4.53 on the page but only 4.03 on surface-3;
       #656b78 clears all three (4.60 / 4.90 / 5.17). */
    --text-faint: #656b78;
    /* `--text-soft` is the name three older stylesheets (habit-detail,
       goal-detail, notifications) reach for. It was never defined, so all
       22 uses fell to their `#94a3b8` fallback — 2.48:1 on the light page.
       It is an alias, not a fourth grey: it follows --text-faint in both
       themes. (Phase 11) */
    --text-soft: var(--text-faint);
    --text-on-primary: #ffffff;

    /* -- Radii --------------------------------------------------------
       Tightened across the board. §9 rules out excessive rounding, and the
       old scale (up to 26px) rounded a panel corner hard enough that the
       panel read as a bubble. Buttons and inputs share 8px so a button
       beside a field is one shape, not two. */
    --radius-xs: 6px;
    --radius-sm: 8px;
    --radius-md: 10px;
    --radius-lg: 14px;
    --radius-xl: 18px;
    --radius-pill: 999px;

    /* -- Elevation ----------------------------------------------------
       ♿/§9 Shadows carry SEPARATION, not depth. The old scale went to
       `0 24px 60px rgba(0,0,0,.34)` — a drop shadow that large is a glow by
       another name. On a light ground a hairline border does most of the
       work and the shadow only has to lift the element off the page, so
       every value here is shorter, tighter and far more transparent. */
    --shadow-xs: 0 1px 1px rgba(14, 15, 19, 0.04);
    --shadow-sm: 0 1px 2px rgba(14, 15, 19, 0.06), 0 1px 3px rgba(14, 15, 19, 0.04);
    --shadow-md: 0 4px 10px rgba(14, 15, 19, 0.06), 0 1px 2px rgba(14, 15, 19, 0.05);
    --shadow-lg: 0 12px 28px rgba(14, 15, 19, 0.10), 0 2px 6px rgba(14, 15, 19, 0.05);

    /* -- Spacing scale ------------------------------------------------ */
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: clamp(14px, 1.4vw, 18px);
    --space-5: clamp(18px, 2vw, 26px);
    --space-6: clamp(24px, 3vw, 38px);
    --space-7: clamp(34px, 4.4vw, 56px);

    /* -- Type scale ---------------------------------------------------
       ⚠️ The ceilings came DOWN. §9 rules out giant meaningless typography,
       and --text-2xl topped out at 2.4rem — a page heading larger than the
       content it labelled. A dense product reads better when the largest
       thing on a working screen is around 1.9rem; the marketing site, which
       genuinely does need display sizes, sets its own scale in
       marketing.css rather than inflating this one. */
    --text-xs: clamp(0.70rem, 0.68rem + 0.10vw, 0.76rem);
    --text-sm: clamp(0.79rem, 0.77rem + 0.12vw, 0.86rem);
    --text-base: clamp(0.88rem, 0.86rem + 0.14vw, 0.95rem);
    --text-md: clamp(0.97rem, 0.94rem + 0.18vw, 1.06rem);
    --text-lg: clamp(1.08rem, 1.02rem + 0.32vw, 1.26rem);
    --text-xl: clamp(1.25rem, 1.12rem + 0.62vw, 1.55rem);
    --text-2xl: clamp(1.5rem, 1.28rem + 1.0vw, 1.95rem);
    --text-num: clamp(1.3rem, 1.08rem + 1.0vw, 1.75rem);

    /* -- Motion -------------------------------------------------------
       §35 asks for subtle and meaningful. 220ms with a spring overshoot on
       interface chrome reads as slow AND bouncy; 150ms on a standard ease
       reads as fast. --ease-spring is kept for the two places a bounce is
       intentional (toast entry, wheel). */
    --transition: 150ms cubic-bezier(0.2, 0, 0.13, 1);
    --ease-spring: cubic-bezier(0.2, 0.9, 0.3, 1.15);

    /* -- Layout metrics ----------------------------------------------- */
    --sidebar-w: 258px;
    --sidebar-rail-w: 78px;
    --topbar-h: 62px;
    --tabbar-h: 62px;
    --content-max: 1560px;
    --tap: 44px; /* minimum comfortable touch target */

    /* ==================================================================
       🎛️ V2 DESIGN FOUNDATION  —  Platform V2, Phase 1
       ------------------------------------------------------------------
       ⚠️ ADDITIVE. Nothing above this block was replaced, renamed or
       re-valued. The 105 tokens already here — colour, surface, text,
       border, space, radius, shadow, the fluid type scale — were audited
       and RETAINED; this block fills the groups that were missing, so
       there is one token system rather than two.

       Every value below is a value the stylesheet was ALREADY using as a
       literal. Naming them is a no-op on screen and the point is exactly
       that: the drift was that nobody could tell which of five weights or
       five durations was "the" one.

       ⚠️ Deliberately colour-free. Colour tokens need a dark-mode twin;
       weights, durations and sizes do not, so this block is theme-neutral
       and adds nothing to the dark override below.
       ================================================================== */

    /* -- Weight ---------------------------------------------------------
       Measured across app.css before naming: 700×28, 600×15, 800×14,
       900×4, 500×3. Five weights with no scale is how a heading ends up
       heavier than the page title next to it. */
    --weight-medium: 500;
    --weight-semibold: 600;
    --weight-bold: 700;
    --weight-heavy: 800;
    --weight-black: 900;

    /* -- Line height ----------------------------------------------------
       ⚠️ Arabic needs MORE leading than Latin at the same size: the script
       carries diacritics above and descenders below the baseline, and
       `IBM Plex Sans Arabic` renders them at a size where 1.2 clips. These
       are chosen so the Arabic UI is comfortable and the English follows,
       not the other way round. */
    --leading-tight: 1.25;    /* display numbers, big figures */
    --leading-snug: 1.4;      /* headings */
    --leading-normal: 1.6;    /* body, and the default for Arabic */
    --leading-relaxed: 1.75;  /* long prose, hints */

    /* -- Tracking -------------------------------------------------------
       ⚠️ Positive tracking on Arabic BREAKS the script — it separates
       letters that must join. `--tracking-wide` is for Latin caps only
       (nav section labels, badges) and must never be applied to a run of
       Arabic text. */
    --tracking-tight: -0.01em;
    --tracking-normal: 0;
    --tracking-wide: 0.06em;

    /* -- Control heights ------------------------------------------------
       Anchored on `--tap`, not parallel to it: `md` IS the touch floor, so
       the accessible size is the default and the small one is the
       exception that has to be justified. */
    --control-sm: 36px;             /* dense, non-primary, desktop only */
    --control-md: var(--tap);       /* the default — 44px */
    --control-lg: 52px;             /* primary actions, one-handed reach */

    /* -- Layout ---------------------------------------------------------
       `--content-max` above stays the app frame; these are for measure —
       how wide a column of TEXT is allowed to get before it stops being
       readable. */
    --container-narrow: 46ch;
    --container-base: 68ch;
    --container-wide: 1120px;
    --gutter: var(--space-4);

    /* -- Motion ---------------------------------------------------------
       The three durations already in the file (150 / 220 / 420ms), named.
       `--ease-spring` above is kept and unchanged. */
    --dur-fast: 150ms;
    --dur-base: 220ms;
    --dur-slow: 420ms;
    --ease-standard: cubic-bezier(0.2, 0, 0, 1);
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

    /* -- Stacking -------------------------------------------------------
       Named so a new overlay does not get a hand-picked 9999. */
    --z-base: 1;
    --z-sticky: 20;
    --z-nav: 40;
    --z-overlay: 60;
    --z-dialog: 80;
    --z-toast: 100;

    /* -- Type roles -----------------------------------------------------
       ⚠️ ROLES, not sizes. The fluid scale above answers «how big»; these
       answer «what is this». A page title is `--type-page` wherever it
       appears, so the same thing is the same size on every V2 surface
       instead of being re-picked per screen. */
    --type-page: var(--text-2xl);
    --type-section: var(--text-lg);
    --type-body: var(--text-base);
    --type-secondary: var(--text-sm);
    --type-label: var(--text-sm);
    --type-meta: var(--text-xs);
    --type-control: var(--text-base);
    --type-nav: var(--text-base);
    --type-figure: var(--text-num);

    /* -- System-bar insets --------------------------------------------
       📱 ZERO on purpose, and overridden in exactly one place below.

       The app used to ship `viewport-fit=cover`, which asks the phone to
       draw the page UNDER the status bar and the home indicator. Six rules
       then pushed their own content back out with
       `max(x, env(safe-area-inset-*))`. Nothing was hidden — but the app was
       painting its own chrome in the strip that belongs to the clock, the
       battery and the signal, and two unrelated interfaces sharing 47px of
       screen is a collision, not a layout.

       `cover` is gone from the viewport meta, so the browser insets the
       viewport itself and the page simply starts below the status bar.

       ⚠️ Which makes reading env() directly a hazard rather than a safety
       net. Per spec the insets resolve to 0px without `cover`, and on a real
       iPhone and a real Android they do — but that gate is exactly the kind
       of thing a browser gets wrong, and if any device reports 47px here the
       old rules would add 47px of padding INSIDE an already-inset viewport:
       a dead band at the top of every page, on the one device that misreads
       it, with nothing in the code pointing at why.

       So the insets are a constant the app controls. They are only wired up
       to env() under `display-mode: fullscreen` — the one mode that really
       does overlay the system bars — and that block is the only place in the
       stylesheet allowed to mention safe-area-inset. */
    --safe-top: 0px;
    --safe-bottom: 0px;

    /* -- Direction sign ----------------------------------------------
       ↔️ CSS transforms have no logical equivalent: `translateX(-28px)` means
       "left" in Arabic exactly as it does in English, so every slide-in
       animation in the app travelled the same way in both languages and was
       therefore wrong in one of them. This token carries the sign, and any
       transform that should move toward the inline-START edge writes
       `translateX(calc(28px * var(--dir)))` instead of a bare offset.
       Set on <html>, so it inherits everywhere. */
    --dir: 1;

    /* -- Typeface -----------------------------------------------------
       §5. Cairo is a good Arabic face and a poor bilingual one: its Latin
       companion is not the same design, so an English screen and an Arabic
       screen did not look like the same product — which is the exact failure
       the brief calls out.

       IBM Plex Sans Arabic and IBM Plex Sans are one superfamily, drawn to
       share a skeleton, a stroke contrast and a vertical rhythm across both
       scripts. Arabic first in the stack: an Arabic glyph should never fall
       through to the Latin face, whereas Latin falling through to the Arabic
       face is the intended behaviour for the mixed content §32 describes —
       «Project: Nike Campaign» in an Arabic sentence is then set in one
       family, at one weight, on one baseline.

       --font-num is the same family with tabular figures enabled at the
       usage site, not a monospace: proportional-vs-mono is a much larger
       visual break beside Arabic text than it is beside Latin. */
    --font-sans: 'IBM Plex Sans Arabic', 'IBM Plex Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-num: 'IBM Plex Sans Arabic', 'IBM Plex Sans', system-ui, -apple-system, sans-serif;

    color-scheme: light;
}

/* -- Dark theme -------------------------------------------------------
   Applied by ui.js as `body.dark-mode`, and pre-painted from
   `html.pre-dark` in header.php so the page never flashes light first.

   This is a NEUTRAL dark, not the old #0b1220 navy: near-black with a grey
   ramp, no gradient, no glow. The accent lightens here rather than darkens
   — #3341c9 on a near-black ground measures 2.6:1 and is unreadable as
   text — while `--primary` itself stays put so that borders, focus rings
   and soft fills keep the brand hue.

   ⚠️ `body.light-mode` is still emitted by ui.js alongside this, because
   settings_reports.css carries seven `.light-mode` rules. Light needs no
   token overrides any more (it IS :root), so there is no matching block
   here — the class survives purely so those rules keep matching.
   --------------------------------------------------------------------- */
body.dark-mode {
    --bg-color: #0c0d11;
    --bg-gradient: none;
    --surface: #141519;
    --surface-strong: #17181d;
    --surface-2: #1a1c21;
    --surface-3: #212429;
    --glass-bg: #141519;
    --glass-border: #262930;
    --glass-highlight: #212429;
    --border: #24272e;
    --border-strong: #363a43;
    --overlay: rgba(6, 7, 9, 0.66);

    --text-main: #f2f3f6;
    --text-muted: #a1a6b2;
    /* ♿ 4.87:1 on --surface-3, the darkest ground faint text lands on. */
    --text-faint: #8b909c;

    /* On a near-black ground the accent has to go LIGHTER to be readable.
       #9aa4f5 measures 7.82:1 on a panel and 8.33:1 on the page. */
    --primary-text: color-mix(in srgb, var(--primary) 34%, #f2f3f6);
    /* ♿ Focus follows the accent-as-ink, not the accent-as-fill: 7.9:1 on
       --surface-3 and 9.9:1 on the page, and — being a color-mix of
       --primary — it tracks a custom accent exactly as --primary-text does. */
    --focus: var(--primary-text);
    /* ⚠️ Re-declared here on purpose. A custom property that references
       another one is resolved on the element that DEFINES it, so the :root
       copies of --focus-ring and --text-soft would keep the LIGHT values
       of --focus / --text-faint even under body.dark-mode. Redeclaring the
       two aliases inside this block makes them resolve against the dark
       tokens above. (Measured: without this the dark ring computed to
       #3341c9.) */
    --focus-ring: 2px solid var(--focus);
    --text-soft: var(--text-faint);

    /* The semantic colours in :root are tuned for a white ground and are
       far too dark here — #05704f on #141519 measures 1.9:1. These are the
       same hues lifted until they clear AA as text on a panel. */
    --success: #4ade9f;
    --success-soft: rgba(74, 222, 159, 0.11);
    --warning: #f0b849;
    --warning-soft: rgba(240, 184, 73, 0.11);
    --danger: #ff8095;
    --danger-soft: rgba(255, 128, 149, 0.11);
    --info: #7aa2ff;
    --info-soft: rgba(122, 162, 255, 0.11);
    --money-in: #4ade9f;
    --money-out: #ff8095;

    /* ⚠️ --primary-ink carries WHITE text, so on the dark theme it must not
       follow --primary-text upward: a pale fill under a white label is the
       same failure in reverse. It stays a saturated mid-tone (5.88:1 under
       white) and ui.js recomputes it for a custom accent exactly as it does
       on light. */
    --primary-ink: #4653e0;
    --secondary-ink: var(--primary-ink);

    /* Shadows do almost nothing on a near-black ground — a black shadow on
       a black page is invisible — so separation comes from --border here
       and the elevation scale is reduced to a faint contact shadow. */
    --shadow-xs: 0 1px 1px rgba(0, 0, 0, 0.30);
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.36);
    --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.42);
    --shadow-lg: 0 14px 34px rgba(0, 0, 0, 0.50);

    color-scheme: dark;
}

/* ==========================================================================
   📱 Phone type floor  (Phase 11)
   --------------------------------------------------------------------------
   The fluid scale above bottoms out at 11.2px (--text-xs) and 12.6px
   (--text-sm) on a 360px phone — the two sizes that carry most of the
   product's metadata, chips, small buttons and list copy. Below 768px, the
   mobile layout's own breakpoint, the two smallest steps are pinned to the
   12px / 14px floor. Nothing else on the scale moves, desktop is untouched
   (the override is width-scoped, so print never sees it either), and the
   `--type-*` aliases inherit the floor because they resolve through these.
   ⚠️ At 360px --text-sm (14px) now sits 0.26px under --text-base (14.26px):
   the sm/base step is carried by weight and colour on phones, as it
   already effectively was at 1.5px.
   ========================================================================== */
@media (max-width: 767px) {
    :root {
        --text-xs: 0.75rem;   /* 12px */
        --text-sm: 0.875rem;  /* 14px */
    }
}
