        /* ===== CSS VARIABLES ===== */
        :root {
            /* [T-378] One shared offset for everything that sticks under the header: --header-h is the header's height and --banner-h the height of the
               one banner (backup reminder, ignored-data notice, failed save, other-tab notice) that is sticky under it; JS (_syncStickyOffsets) keeps both
               live. --sticky-top is where a sticky bar of a page (finance filter tabs, backlog bulk bar, search) must stop. Defaults = the old fixed 70px. */
            --header-h:70px; --banner-h:0px; --sticky-top:calc(var(--header-h) + var(--banner-h));
            --bg:#f5f8f8; --bg2:#fff; --bg2:#fff; --bg3:#f0f5f5;
            --text1:#1a1a2e; --text2:#4a6b6b; --text3:#5f5f5f;
            --accent:#0D6E6E; --accent-dark:#0A4A4A; --accent-rgb:13,110,110;
            --gold:#B8860B; --gold-light:#ffd966;
            --border:rgba(var(--accent-rgb),0.12);
            --radius:12px; --radius-sm:8px;
            /* Global Layout Consistency — عرض موحد لكل المودالز، المرجع
               القياسي هو مودال "إضافة مهمة". أي مودال جديد يستخدم نفس القيمة. */
            --modal-max-width:430px;
            /* Z-Index Scale (2026-09-09) — audited from every real z-index
               value in use across masari.css/masari.html/assets/js at design
               time (see docs/07_DECISIONS_ACTIVE.md → "Inline-Style Cleanup
               Z-Index Scale"). Scoped to the 4 tiers the inline style=""
               cleanup's Part C sites actually need — the base .modal-overlay
               (100), full-screen focus overlays (200), and the handful of
               small-numbered (1-30) purely-local sibling-stacking values are
               untouched, out of scope for this token (they were never inline
               literals needing conversion, or have no cross-component
               meaning a shared token would express). */
            --z-modal:150; --z-popover:9100; --z-modal-top:9200; --z-overlay-top:9999;
            --orange:#c85a00; --orange-light:rgba(200,90,0,0.08);
            --red:#c0392b;
            --success:#2d7a4a;
            /* Semantic tokens (Sprint 13 — Theme Customization). Canonical
               names going forward; --red/--orange kept as-is (existing var()
               sites unaffected). Declared as literals, NOT var(--red)/
               var(--orange) aliases — verified live that a custom property
               defined only in :root as var(--other-token) does not reliably
               re-resolve when --other-token is later overridden in body.dark
               or a body.palette-* block (measured: --danger stayed pinned to
               :root's value even though --red correctly changed per mode on
               the same element). Each mode/palette override block below
               sets these explicitly instead of relying on chained var(). */
            --danger:#c0392b; --warning:#c85a00; --info:#0A4A4A;
            --danger-rgb:192,57,43; --warning-rgb:200,90,0;
            --toast-info-bg:#e6f4f4; --toast-ok-bg:#e8f5ee; --toast-warn-bg:#fff0e6; --toast-err-bg:#fdecea;
            /* Semantic Content-Type Colors (2026-08-07) — distinct from the
               --danger/--warning/--success/--info severity tokens above:
               these encode WHAT KIND of thing a .btn-primary action acts on
               (a transaction type, a file format), not how important the
               click is. Exact literal values carried over unchanged from the
               10 .btn-primary inline overrides deferred by the Button System
               sprint (docs/07_DECISIONS_ACTIVE.md → ".btn-primary Inline
               Color Overrides Excluded from Button System Sprint"). --color-
               prefix used deliberately (unlike --accent/--danger/--bg) to
               keep this content-type category visually distinct from the
               base UI-severity palette. Same value in light+dark (none of
               these 10 sites had a dark-mode override to preserve). */
            --color-income:var(--success);
            --color-transfer:#5a3e8a;
            --color-json:linear-gradient(135deg,#1a7a6a,var(--accent));
            --color-csv-export:var(--success);
            --color-excel-end:#6a5a9a;
            --color-excel:linear-gradient(135deg,#5a4a8a,var(--color-excel-end));
            --color-csv-import-end:#2a8a50;
            --color-csv-import:linear-gradient(135deg,var(--success),var(--color-csv-import-end));
            --color-pdf:#4a5568;
            --color-master-structure:#0D6E4A;
            --color-bills:#8E44AD;
            /* Inline-style cleanup Part C (2026-09-09) — Finance's "bills due
               soon" alert banner used a raw rgba(230,126,22,...) distinct
               from --warning (#c85a00, 200,90,0) despite the banner's own
               text using var(--warning) right next to it. Not force-matched
               to --warning: #E67E22 (amber) reads as a deliberately
               different, milder tier than the app's red-orange --warning
               (matches the base .fin-alert-banner's own precedent of a raw
               background literal paired with a token-based text color).
               New token, not reused from an unrelated existing #E67E22
               sighting (--sys-accent-1, the Systems Marketplace accent
               palette) per this file's own rule against merging tokens on
               coincidental hex match alone. */
            --color-bill-urgent:#E67E22; --color-bill-urgent-rgb:230,126,22;
            /* SI3-3 fix (Sprint 14 Third Re-Audit remediation, 2026-09-02) —
               2 previously-unbridged raw hex gradients (Monthly Archive
               folder-header, resetBacklogDistribution() button), each a
               unique static 2-stop gradient with no prior token. */
            --color-archive-folder:#534AB7;
            --color-backlog-reset:#7a5c2e;
            --fin-accent-dark:#0a4f6e;
            --fin-hero-teal-end:#0e7a7a;
            --fin-hero-dark-start:#1a2a3a;
            --fin-hero-dark-end:#2d3e52;
            --fin-hero-purple-start:#5b2d8a;
            --fin-hero-purple-end:#7c4db8;
            --fin-hero-green-start:#1a6b3a;
            --fin-hero-green-end:#2d9a5a;
            --fin-hero-amber-start:#8a5b00;
            --fin-hero-amber-end:#c4850a;
            --kt-concept:#6366f1;
            --kt-framework:#0ea5e9;
            --kt-book-summary:#22c55e;
            --kt-article-summary:#84cc16;
            --kt-quote:#f59e0b;
            --kt-insight:#ec4899;
            --kt-reference-note:#8b5cf6;
            --kt-checklist:#14b8a6;
            --kt-sop:#f97316;
            --kt-note:#94a3b8;
            --color-urgent:#d33;
            --color-eliminate-muted:#999;
            --color-backlog-option:#516091;
            --color-energy-low:#1a5f8f;
            --color-achievement-text:#3d2b00;
            /* Habit Frequency Icon Distinction (2026-08-29) — daily/weekly
               reuse existing tokens (--gold/--success) directly, matching
               values already established elsewhere: --gold is the
               pre-existing .tl-kind-habit badge color, kept unchanged for
               the daily tier (no reason to move existing daily habits off
               their established color); --success is CHOICE_PILL_COLORS[1],
               the exact color the habit-creation modal's own "أسبوعي"
               frequency pill already shows (masari.html ~29963/31620).
               monthly/yearly have no existing token to reuse — minted here,
               but the VALUES are not invented: they're
               CHOICE_PILL_COLORS[2]/[3], the same "شهري"/"سنوي" pill colors
               from that same modal, so a habit's badge matches the color
               the user already saw when picking that frequency.
               (Religious/Prayer 'daily now matches Prayer' rationale
               removed 2026-08-29 — item.type:'religious' and its
               .tl-kind-prayer badge were dead code, confirmed no producer
               anywhere and no real stored data, and have been deleted
               entirely; see archive/decisions-history/10_CHANGELOG_LIVE_PRE_RESTRUCTURE.md.) */
            --color-freq-monthly:#e67e22;
            --color-freq-yearly:#5a3e8a;
            /* Timeline activity-category badge colors (2026-09-04) — a SECOND,
               narrower axis than the frequency tiers directly above. Those five
               say what KIND of record this is (task / habit-at-frequency-N /
               bill); these four say what the item IS ABOUT, and they win over
               the tier color when — and only when — TL_NAME_ICON_KEYWORDS'
               keyword match fires and that group carries a category. No match,
               or a group with no category, keeps the tier color exactly as
               before: same one-tier-fallback structure the icon inference
               already uses, not a replacement for it.
               Four, not one-per-group: ~24 groups × a unique hue each would be
               a color system nobody can read, so only the categories that are
               both frequent in real habit lists AND semantically far apart get
               their own. Values were picked to clear BOTH the six tier colors
               (accent #0D6E6E, --gold #B8860B, --success #2d7a4a,
               --color-freq-monthly #e67e22, --color-freq-yearly #5a3e8a /
               --color-bills #8E44AD) and each other, and every one clears 4:1
               against the white glyph on top (--text-on-accent), measured, not
               eyeballed: water 4.5, worship 5.4, exercise 5.8, care 4.1.
               Minted rather than aliased for the same reason --color-bills and
               the --color-cat-* family are separate tokens that happen to share
               #8e44ad — a distinct semantic gets a distinct name even where a
               near-value already exists; the nearest existing candidates were
               all on unrelated axes (--color-palette-ocean is a user-selectable
               THEME accent, --success is a state, --color-freq-monthly is a
               frequency), and reusing one would have tied this badge's color to
               a variable that changes for reasons that have nothing to do with
               what the item is about. Same value in light and dark, matching
               every other --color-* token here. */
            --color-act-water:#1F7AC4;
            --color-act-worship:#0E7A46;
            --color-act-exercise:#C2185B;
            --color-act-care:#1789A6;
            --color-dp-day-other:#ccc;
            --color-workspace-bounds:#ff2222;
            --color-import-neutral:#666;
            --color-import-strong:#333;
            --color-undo-create:#2a8;
            --color-undo-edit:#e8a23d;
            --color-undo-moved:#0B72B9;
            --color-undo-restored:#8e44ad;
            --color-cat-habit:#8e44ad;
            --color-cat-project:#16a085;
            --color-cat-account:#2980b9;
            --color-cat-idea:#1f6f5c;
            --color-cat-knowledge:#6b4fae;
            --color-cat-system:#7d3c98;
            --color-ambition-draft:#95a5a6;
            --color-ambition-active:#3498db;
            --color-ambition-abandoned:#7f8c8d;
            --color-priority-medium:#e8a23d;
            --color-rarity-rare:#3b82f6;
            --color-rarity-epic:#a855f7;
            --color-rarity-legendary:#f59e0b;
            --color-palette-ocean:#0B72B9;
            --color-palette-forest:#2E7D32;
            --color-idea-raw:#95a5a6;
            --color-idea-exploring:#3498db;
            --color-idea-converted:#8e44ad;
            --color-idea-archived:#7f8c8d;
            --color-relation-extends:#2c7be5;
            --color-relation-related:#3498db;
            --color-relation-similar:#16a085;
            --color-relation-conflicts:#8e44ad;
            --color-import-info:#1565C0;
            --text-on-accent:#fff;
            /* Unified Heatmap Semantic Scale (2026-07-22 refinement) — ONE
               color language shared by every heatmap in the app (Habits/
               Focus/Completion/Behavior, and reusable later by Progress
               Bars/Score cards/Executive views per the design decision).
               Colors mean execution quality, never data type — replaces the
               old per-heatmap color families (habits=green/focus=blue/
               achieve=purple/behavior=orange), which made the same % look
               like 4 different things depending which heatmap you were on.
               No-Data reuses --bg3 directly (already theme-aware per mode,
               not aliased — see --danger's comment below for why literals
               beat var() chaining here). */
            --heat-scale-poor:#c0392b; --heat-scale-low:#c85a00; --heat-scale-avg:#c9971c;
            --heat-scale-verygood:#1e88e5; --heat-scale-excellent:#2d7a4a;
            --heat-text-on:#fff; --heat-text-off:#333;
            /* Timeline shared spacing — مصدر واحد. أي تعديل هنا بينعكس تلقائياً
               على الـ Timeline وقسم "مهام بدون وقت محدد" مع بعض. */
            /* Icon-on-spine redesign (2026-09-04) — the gutter went 46px→72px
               because it now has to hold TWO things side by side, not one:
                 [ hour column (4em ≈ 44px, 50.6px at font-lg) ][ the outward
                 half of the kind badge (--tl-badge-size / 2 = 18px) ]
               …with ~2px of air between them. 44+2+18 = 64 at normal size,
               50.6+2+18 = 70.6 at font-lg — 72px covered both with a little
               slack (superseded below: the badge's outward half is no longer a
               fixed 18px, so this arithmetic is re-run at the new max and the
               gutter is 78px now — the method is unchanged, the inputs are not),
               and --tl-edge-pad is a raw literal (it does NOT scale
               under body.font-sm or body.font-lg the way the space and fs
               tokens do), so the
               font-lg case is the one that has to fit.
               --tl-edge-pad is ALSO the spine's own x-position now: the spine
               (.timeline::before), the period-divider dot and the kind badge
               all sit centered on .timeline's CONTENT-box edge, which is
               exactly --tl-edge-pad in from its padding-box edge. That
               deliberately collapses the old 46-vs-42 mismatch (the spine used
               to sit 4px outside the content edge, which every positioned
               child then had to re-derive with its own calc — the source of
               two rounds of off-by-4 geometry bugs). One number now: everything
               on the spine is `calc(var(--tl-spine-x) - var(--tl-edge-pad))`
               plus its own half-width.
               Duration-scaled badge (2026-09-04, 4th refinement pass) — the
               badge diameter is no longer one number: _tlBadgeSizePx(durMins)
               scales it 28px→44px with the item's duration (the same "the card
               already grows with duration, the node should too" idea as
               _tlChipHeightPx), and the renderer writes the result as an
               INLINE --tl-badge-size on that item's own .tl-item-row.
               Every piece of gutter geometry that has to stay CONSTANT down the
               column — the hour label's x, the card's inset — therefore keys off
               --tl-badge-size-MAX, never off --tl-badge-size: keying them off the
               varying value would give every row a different card edge and a
               different hour x, i.e. a ragged column, which is the opposite of
               what this redesign is for. Only the circle itself varies.
               (This also side-steps a CSS custom-property subtlety that would
               have made the "just override --tl-badge-size on the row" shortcut
               silently wrong: --tl-card-inset's own var() is substituted at
               computed-value time HERE, on :root, so an override further down
               the tree can never reach it. Naming the max explicitly makes that
               a stated intent instead of an accident.)
               The gutter grew 72px→78px with it, by the same arithmetic as
               above but at the new max: [hour 4em][2px][max badge's outward
               half] = 44+2+22 = 68 at normal, 50.6+2+22 = 74.6 at font-lg —
               78px covers the font-lg case (the binding one, since
               --tl-edge-pad is a raw literal and does not scale) with slack. */
            --tl-edge-pad:78px;   /* padding-inline-start لحاوية الـ Timeline (#timelineEl) — بيحجز مساحة عمود الساعة + النص الخارجي من دايرة الأيقونة */
            --tl-spine-x:78px;    /* بُعد خط الـ Timeline (.timeline::before) عن حافة .timeline الداخلية — مساوي لـ --tl-edge-pad عمداً (الخط بالظبط عند حافة المحتوى) */
            --tl-badge-size:36px; /* قطر .tl-kind-badge الافتراضي — الدايرة متمركزة على الخط، نصها برّه ونصها جوّه. صفوف الـ Timeline بتكتب قيمة خاصة بيها inline حسب مدة العنصر */
            --tl-badge-size-max:44px; /* أكبر قطر ممكن (_tlBadgeSizePx ceiling) — كل حسابات الجَتَر الثابتة بتتحسب عليه هو مش على المتغيّر */
            /* --tl-badge-height (2026-09-15, circle-to-capsule) عمداً مش متعرّفة هنا —
               مفيش قيمة افتراضية مفيدة على مستوى :root، كل صف بيكتبها inline
               زي --tl-badge-size بالظبط (_tlBadgeHeightPx في ui-timeline.js).
               .tl-kind-badge نفسها بتقرأها بـ var(--tl-badge-height, var(--tl-badge-size))
               فلو صف قديم/سياق تاني ماكتبهاش أبدًا، بترجع دايرة زي قبل التغيير ده تمامًا. */
            --tl-badge-gap:6px;   /* المسافة بين الحافة الداخلية للدايرة وأول الكارت */
            --tl-card-inset:calc(var(--tl-badge-size-max) / 2 + var(--tl-badge-gap)); /* = 28px — إزاحة الكارت عن حافة المحتوى عشان ميتغطّاش بالدايرة حتى عند أكبر قطر */
            --tl-row-inset:0px;   /* margin-right لكل صف ساعة (.tl-hour) — كان 50px قبل كده وده كان بيعمل مساحة فاضية زيادة (مكرّرة فوق tl-edge-pad) بتضيّق عرض كروت التايم لاين عن باقي عناصر الصفحة زي مورننج كارد بدون أي فايدة بصرية */
            /* ===== MOTION & ELEVATION TOKENS (Sprint 11) =====
               dur-fast/base/slow مأخوذة من أكتر 3 قيم transition متكررة فعليًا
               في الملف (0.15s / 0.22s / 0.38s) — مش قيم مخترعة. ease-standard
               كانت بتتستخدم بس في أنيميشن جديد وقت ما الملاحظة دي اتكتبت
               (Sprint 11) — Sprint 8 Phase 2 Batch 3 (2026-08-28) رجّع كل
               الـ transition/animation القديمة اللي كانت بتستخدم 0.15s/0.22s/
               0.38s ease حرفيًا لنفس التوكنز + var(--ease-standard)، فبقت
               القيمة الافتراضية مش استثناء للعناصر الجديدة بس.
               --dur-instant (0.12s) اتضاف في نفس الباتش دي: مش تقريب لـ
               dur-fast، دي درجة رابعة حقيقية — كانت مستخدمة باستمرار
               (9+ مواقع) في كل مواضع "ضغطة الكارت" (.fin-tx-card,
               .fin-quick-btn, .task-menu-btn, .task-menu-item, .dp-day)
               واللي محتاجة إحساس فوري/لمسي أسرع من dur-fast العادية. */
            --dur-fast:0.15s; --dur-base:0.22s; --dur-slow:0.38s; --dur-instant:0.12s;
            --ease-standard:cubic-bezier(.4,0,.2,1);
            --radius-xs:4px; --radius-md:10px; --radius-lg:14px; --radius-xl:20px;
            --radius-pill:999px; --radius-full:50%;
            --shadow-card:0 1px 4px rgba(var(--accent-rgb),0.08);
            --shadow-card-hover:0 2px 8px rgba(var(--accent-rgb),0.1);
            --shadow-overlay:0 4px 24px rgba(0,0,0,0.18);
            --shadow-modal:0 8px 32px rgba(0,0,0,0.25);
            /* Border-width scale (Design Tokenization sprint, 2026-08-06) -
               taken from the 4 distinct border-width values actually used
               file-wide, not invented. */
            --border-hairline:1px; --border-thin:2px; --border-medium:3px; --border-thick:4px;
            /* Promoted from 2 exact-duplicate one-off box-shadow values found
               during the same sprint (were composed inline in 4 places using
               the same rgba(var(--accent-rgb),X) idiom --shadow-card itself
               uses - promoted because they repeat, not because the idiom
               itself needed changing). */
            --shadow-ring-active:0 0 0 3px rgba(var(--accent-rgb),0.22);
            --shadow-ring-pulse:0 0 0 4px rgba(var(--accent-rgb),0.18);
            /* Font-size scale (Design Tokenization sprint, 2026-08-06) -
               organizational only: the 21 distinct px values actually in use
               file-wide, named by value, not remapped to a semantic
               hierarchy. A true semantic scale (display/heading/body/label
               per docs/DESIGN_SYSTEM.md) is a separate, larger design
               decision - it would mean choosing which of these 21 values
               consolidate into fewer tiers, changing rendered sizes on some
               elements, which this pass deliberately does not do. Values
               are NOT rem-based - the "Zoom Strategy" question (docs/
               07_DECISIONS_ACTIVE.md) is reopened and resolved this batch
               (Sprint 8 Phase 2 Batch 4, 2026-08-28): body.font-sm/font-lg
               below redeclare this whole token block scaled by 0.9/1.15,
               replacing the non-standard CSS `zoom` property previously
               used for this. Each override must restate every token as a
               self-contained calc(base * factor) - a shared inherited
               "--font-scale" multiplier variable was tried first and does
               NOT work here: a custom property's computed value is
               resolved (var() substituted) once at its OWN declaring
               element and that resolved value is what inherits, so a
               descendant's un-redeclared --font-size-14 stays frozen at
               :root's factor (1) no matter what a body class overrides
               further down - confirmed live via getComputedStyle before
               settling on this direct-duplication approach instead. */
            --font-size-7:0.4375rem; --font-size-8:0.5rem; --font-size-9:0.5625rem;
            --font-size-10:0.625rem; --font-size-11:0.6875rem; --font-size-12:0.75rem;
            --font-size-13:0.8125rem; --font-size-14:0.875rem; --font-size-15:0.9375rem;
            --font-size-16:1rem; --font-size-17:1.0625rem; --font-size-18:1.125rem;
            --font-size-19:1.1875rem; --font-size-20:1.25rem; --font-size-22:1.375rem;
            --font-size-24:1.5rem; --font-size-26:1.625rem; --font-size-28:1.75rem;
            --font-size-32:2rem; --font-size-52:3.25rem; --font-size-60:3.75rem;
            /* Semantic typography hierarchy (Sprint 8 Phase 2, 2026-08-29) -
               named roles aliasing 8 of the 21 --font-size-* values above,
               closing the "organizational only, not a semantic hierarchy"
               gap this file's own comment used to note. Each --fs-* below
               is a self-contained literal here (NOT var(--font-size-N)) and
               is redeclared the same way under body.font-sm/font-lg, for
               the identical re-resolution reason the comment above this
               block already explains for --font-size-* itself - an alias
               chain would freeze at :root's value under font-sm/font-lg
               instead of picking up their scaled figure. The remaining 13
               --font-size-* values (12,15,16,17,19,20,22,26,28,52,60) stay
               unaliased: 16 is deliberately kept literal (input-font-size-
               floor, a coincidental overlap with body text, not a real
               semantic relationship - see input-font-size-floor skill);
               the rest didn't have enough independent, consistent usage to
               justify a named role distinct from a neighbor. */
            --fs-micro:0.5625rem; --fs-caption:0.625rem; --fs-label:0.6875rem; --fs-body:0.8125rem;
            --fs-heading-sm:0.875rem; --fs-heading-md:1.125rem; --fs-stat:1.5rem; --fs-display-lg:2rem;
            /* Icon-size tokens (icon-container sizing convergence,
               2026-08-30) - two families, matching two different CSS
               mechanisms already in use for icon sizing file-wide (see
               docs/07_DECISIONS_ACTIVE.md's convergence decision entry
               for the full per-site inventory and why these weren't
               forced onto one shared value). --icon-glyph-* aliases the
               existing --font-size-N values already used for bare icon
               glyphs sized via font-size, so it re-resolves under
               font-sm/font-lg exactly like --fs-* does above, same
               reason. --icon-box-* are flat, non-scaling width/height
               dimensions for icon CONTAINERS (a circle/rounded-square
               background behind an icon) - these never scaled with
               font-sm/font-lg before this pass and still don't, by
               design. Zero value changes at any existing site renamed
               onto these tokens. */
            --icon-glyph-16:16px; --icon-glyph-20:20px; --icon-glyph-22:22px;
            --icon-box-16:16px; --icon-box-20:20px; --icon-box-22:22px; --icon-box-24:24px;
            /* Spacing scale (Design Tokenization sprint, 2026-08-06) -
               organizational only, named by value: the 24 distinct px
               values actually used in padding/margin/gap file-wide. Same
               "not invented, not remapped" precedent as --font-size-*
               above - a coarser XS/SM/MD/LG/XL scale would mean merging
               some of these 24 values together, changing real spacing on
               some elements, which this pass deliberately does not do.
               Also redeclared under body.font-sm/font-lg (see comment
               above) so spacing rescales along with text, matching the
               visual proportions the old `zoom` approach produced. */
            --space-1:1px; --space-2:2px; --space-3:3px; --space-4:4px;
            --space-5:5px; --space-6:6px; --space-7:7px; --space-8:8px;
            --space-9:9px; --space-10:10px; --space-11:11px; --space-12:12px;
            --space-14:14px; --space-16:16px; --space-18:18px; --space-20:20px;
            --space-22:22px; --space-24:24px; --space-26:26px; --space-30:30px;
            --space-34:34px; --space-64:64px; --space-220:220px; --space-230:230px;
        }
        body.dark {
            --bg:#0e1414; --bg2:#152020; --bg3:#1a2828;
            --text1:#e8f4f4; --text2:#7ab5b5; --text3:#9e9e9e;
            --border:rgba(var(--accent-rgb),0.2);
            --red:#e74c3c; --danger:#e74c3c; --danger-rgb:231,76,60;
            /* Unified Heatmap Semantic Scale — brightened for legibility on
               a near-black background, same 5 meanings as :root. */
            --heat-scale-poor:#e74c3c; --heat-scale-low:#ff9800; --heat-scale-avg:#ffd966;
            --heat-scale-verygood:#64b5f6; --heat-scale-excellent:#43a047;
            --heat-text-off:#0e1414;
        }
        /* ===== THEME CENTER — Sprint 4 =====
           AMOLED و High Contrast طبقات إضافية فوق body.dark، مش أوضاع مستقلة.
           بيغطوا كل حاجة بتقرا من CSS vars (الأغلبية الساحقة من الملف).
           فيه عدد محدود من الألوان الـ hardcoded جوه body.dark.xxx (header/tabs/modal)
           بتتغطى هنا صراحة لأنها أكتر عناصر بصريًا واضحة. باقي الألوان الـ
           hardcoded القليلة المتبقية (لو فيه) هتفضل بشكل dark العادي —
           ده scope محدود معروف مش باگ، مش متتبَّع في أي قائمة منفصلة. */
        body.dark.amoled { --bg:#000000; --bg2:#050505; --bg3:#0a0a0a; --border:rgba(var(--accent-rgb),0.28);
            --heat-scale-poor:#ff5252; --heat-scale-low:#ffa726; --heat-scale-avg:#ffeb3b;
            --heat-scale-verygood:#448aff; --heat-scale-excellent:#4caf50; }
        body.dark.amoled .header { background:#000; }
        body.dark.amoled .nav-bottom { background:#000; }
        body.dark.amoled .nav-sidebar { background:#000; }
        body.dark.amoled .modal { background:#050505; border-color:rgba(var(--accent-rgb),0.3); }

        body.high-contrast { --border:rgba(var(--accent-rgb),0.65);
            --heat-scale-poor:#b71c1c; --heat-scale-low:#e65100; --heat-scale-avg:#f57f17;
            --heat-scale-verygood:#0d47a1; --heat-scale-excellent:#1b5e20; --heat-text-off:#000; --heat-text-on:#fff; }
        body.dark.high-contrast { --text1:#ffffff; --text2:#d0eaea; --border:rgba(122,181,181,0.75);
            --heat-scale-poor:#ff8a80; --heat-scale-low:#ffab40; --heat-scale-avg:#ffe57f;
            --heat-scale-verygood:#82b1ff; --heat-scale-excellent:#b9f6ca; --heat-text-off:#000; }
        body.high-contrast button, body.high-contrast input, body.high-contrast select, body.high-contrast .modal, body.high-contrast .task-item, body.high-contrast .backlog-item { border-width:var(--border-thin); }

        /* ===== PALETTE LAYER — Sprint 13 (Theme Customization) =====
           محور مستقل عن Mode (auto/light/dark/amoled/highContrast) اللي فوق.
           Palette بس بيبدّل --accent/--accent-dark/--accent-rgb، وبيتطبّق
           فوق أي Mode (زي ما amoled/high-contrast بيتطبّقوا فوق dark).
           classic هو الافتراضي الحالي (var(--accent)) — مفيش class ليه، هو الأصل
           في :root. الـ 5 الباقيين بيستخدموا نفس الميكانيزم. */
        /* --shadow-card/--shadow-card-hover redeclared per palette below —
           same reason as the Semantic Token Correction (Phase 2): a custom
           property whose only declaration embeds var(--accent-rgb) does not
           reliably re-resolve when --accent-rgb changes in a more specific
           selector, verified live (measured getComputedStyle + actual
           box-shadow render both stayed pinned to Classic's rgb under
           Ocean). Explicit per-block redeclaration is the only pattern
           confirmed to work. */
        body.palette-ocean        { --accent:#0B72B9; --accent-dark:#075186; --accent-rgb:11,114,185; --info:#075186; --shadow-card:0 1px 4px rgba(11,114,185,0.08); --shadow-card-hover:0 2px 8px rgba(11,114,185,0.1); }
        body.palette-forest       { --accent:#2E7D32; --accent-dark:#1B5E20; --accent-rgb:46,125,50; --info:#1B5E20; --shadow-card:0 1px 4px rgba(46,125,50,0.08); --shadow-card-hover:0 2px 8px rgba(46,125,50,0.1); }
        body.palette-warm         { --accent:#C85A00; --accent-dark:#954300; --accent-rgb:200,90,0; --info:#954300; --shadow-card:0 1px 4px rgba(200,90,0,0.08); --shadow-card-hover:0 2px 8px rgba(200,90,0,0.1); }
        body.palette-gold         { --accent:#B8860B; --accent-dark:#8A6508; --accent-rgb:184,134,11; --info:#8A6508; --shadow-card:0 1px 4px rgba(184,134,11,0.08); --shadow-card-hover:0 2px 8px rgba(184,134,11,0.1); }

        /* ===== CARD STYLE — Sprint 13 (Theme Customization) =====
           بيستخدم tokens الـ radius الموجودة من Sprint 11 — صفر قيم جديدة
           hardcoded. square بيصفّر كل الـ radius tokens المستخدمة فعليًا
           على الكروت/الأزرار/المودالات. */
        body.square-cards { --radius:2px; --radius-sm:2px; --radius-md:2px; --radius-lg:2px; --radius-xl:2px; }

        /* ===== ACCESSIBILITY — Sprint 11, revised Sprint 8 Phase 2 Batch 4 (2026-08-28) =====
           حجم الخط: كان بيستخدم CSS zoom (خاصية غير قياسية) لأن وقتها معظم
           عناصر التطبيق كانت بتحدد font-size بتاعها مباشر (px) مش وارثة من
           body. بعد Design Tokenization sprint (2026-08-06)، 98% من
           font-size/spacing بقوا بيمروا عبر --font-size-N و --space-N
           tokens المُعرّفة فوق في :root — فبقى تغييرهم هنا (بضرب كل قيمة في
           0.9 أو 1.15) كافي يوصل لكل حاجة، من غير zoom. لازم كل token
           يتعاد تعريفه صراحة هنا (مش عن طريق متغيّر واحد مشترك زي
           --font-scale)، لأن قيمة custom property بتتحسب مرة واحدة عند أول
           عنصر بيعرّفها وبتورّث كده لأي عنصر تاني من غير ما تتحسب تاني —
           جُرِّب متغيّر مشترك الأول وثبت إنه مبيوصلش. راجع "Zoom Strategy"
           في docs/07_DECISIONS_ACTIVE.md.
           كثافة العرض: task-item/backlog-item/dash-card/menu-item/modal/
           filter-btn/tag-pill — 7 عناصر تغطي الأغلبية الساحقة من المساحة
           المتكررة بصريًا. عناصر متخصصة قليلة (زي كروت التقارير المنفصلة
           و icon SVG المُحدّدة بالبكسل مباشر) لسه برّه التغطية — معروفة
           كـ scope محدود، مش متتبَّعة في أي قائمة منفصلة. */
        body.font-sm {
            --font-size-7:calc(0.4375rem * 0.9); --font-size-8:calc(0.5rem * 0.9); --font-size-9:calc(0.5625rem * 0.9);
            --font-size-10:calc(0.625rem * 0.9); --font-size-11:calc(0.6875rem * 0.9); --font-size-12:calc(0.75rem * 0.9);
            --font-size-13:calc(0.8125rem * 0.9); --font-size-14:calc(0.875rem * 0.9); --font-size-15:calc(0.9375rem * 0.9);
            --font-size-16:calc(1rem * 0.9); --font-size-17:calc(1.0625rem * 0.9); --font-size-18:calc(1.125rem * 0.9);
            --font-size-19:calc(1.1875rem * 0.9); --font-size-20:calc(1.25rem * 0.9); --font-size-22:calc(1.375rem * 0.9);
            --font-size-24:calc(1.5rem * 0.9); --font-size-26:calc(1.625rem * 0.9); --font-size-28:calc(1.75rem * 0.9);
            --font-size-32:calc(2rem * 0.9); --font-size-52:calc(3.25rem * 0.9); --font-size-60:calc(3.75rem * 0.9);
            --fs-micro:calc(0.5625rem * 0.9); --fs-caption:calc(0.625rem * 0.9); --fs-label:calc(0.6875rem * 0.9); --fs-body:calc(0.8125rem * 0.9);
            --fs-heading-sm:calc(0.875rem * 0.9); --fs-heading-md:calc(1.125rem * 0.9); --fs-stat:calc(1.5rem * 0.9); --fs-display-lg:calc(2rem * 0.9);
            --icon-glyph-16:calc(16px * 0.9); --icon-glyph-20:calc(20px * 0.9); --icon-glyph-22:calc(22px * 0.9);
            --space-1:calc(1px * 0.9); --space-2:calc(2px * 0.9); --space-3:calc(3px * 0.9); --space-4:calc(4px * 0.9);
            --space-5:calc(5px * 0.9); --space-6:calc(6px * 0.9); --space-7:calc(7px * 0.9); --space-8:calc(8px * 0.9);
            --space-9:calc(9px * 0.9); --space-10:calc(10px * 0.9); --space-11:calc(11px * 0.9); --space-12:calc(12px * 0.9);
            --space-14:calc(14px * 0.9); --space-16:calc(16px * 0.9); --space-18:calc(18px * 0.9); --space-20:calc(20px * 0.9);
            --space-22:calc(22px * 0.9); --space-24:calc(24px * 0.9); --space-26:calc(26px * 0.9); --space-30:calc(30px * 0.9);
            --space-34:calc(34px * 0.9); --space-64:calc(64px * 0.9); --space-220:calc(220px * 0.9); --space-230:calc(230px * 0.9);
        }
        body.font-lg {
            --font-size-7:calc(0.4375rem * 1.15); --font-size-8:calc(0.5rem * 1.15); --font-size-9:calc(0.5625rem * 1.15);
            --font-size-10:calc(0.625rem * 1.15); --font-size-11:calc(0.6875rem * 1.15); --font-size-12:calc(0.75rem * 1.15);
            --font-size-13:calc(0.8125rem * 1.15); --font-size-14:calc(0.875rem * 1.15); --font-size-15:calc(0.9375rem * 1.15);
            --font-size-16:calc(1rem * 1.15); --font-size-17:calc(1.0625rem * 1.15); --font-size-18:calc(1.125rem * 1.15);
            --font-size-19:calc(1.1875rem * 1.15); --font-size-20:calc(1.25rem * 1.15); --font-size-22:calc(1.375rem * 1.15);
            --font-size-24:calc(1.5rem * 1.15); --font-size-26:calc(1.625rem * 1.15); --font-size-28:calc(1.75rem * 1.15);
            --font-size-32:calc(2rem * 1.15); --font-size-52:calc(3.25rem * 1.15); --font-size-60:calc(3.75rem * 1.15);
            --fs-micro:calc(0.5625rem * 1.15); --fs-caption:calc(0.625rem * 1.15); --fs-label:calc(0.6875rem * 1.15); --fs-body:calc(0.8125rem * 1.15);
            --fs-heading-sm:calc(0.875rem * 1.15); --fs-heading-md:calc(1.125rem * 1.15); --fs-stat:calc(1.5rem * 1.15); --fs-display-lg:calc(2rem * 1.15);
            --icon-glyph-16:calc(16px * 1.15); --icon-glyph-20:calc(20px * 1.15); --icon-glyph-22:calc(22px * 1.15);
            --space-1:calc(1px * 1.15); --space-2:calc(2px * 1.15); --space-3:calc(3px * 1.15); --space-4:calc(4px * 1.15);
            --space-5:calc(5px * 1.15); --space-6:calc(6px * 1.15); --space-7:calc(7px * 1.15); --space-8:calc(8px * 1.15);
            --space-9:calc(9px * 1.15); --space-10:calc(10px * 1.15); --space-11:calc(11px * 1.15); --space-12:calc(12px * 1.15);
            --space-14:calc(14px * 1.15); --space-16:calc(16px * 1.15); --space-18:calc(18px * 1.15); --space-20:calc(20px * 1.15);
            --space-22:calc(22px * 1.15); --space-24:calc(24px * 1.15); --space-26:calc(26px * 1.15); --space-30:calc(30px * 1.15);
            --space-34:calc(34px * 1.15); --space-64:calc(64px * 1.15); --space-220:calc(220px * 1.15); --space-230:calc(230px * 1.15);
        }
        body.compact .task-item, body.compact .backlog-item { padding:var(--space-6) 9px; margin-bottom:var(--space-3); }
        body.compact .dash-card { padding:var(--space-9); margin-bottom:var(--space-8); }
        body.compact .menu-item { padding:var(--space-6) 9px; margin-bottom:var(--space-3); }
        body.compact .modal { padding:var(--space-10); }
        body.compact .filter-btn { padding:var(--space-3) 9px; }
        body.compact .tag-pill { padding:var(--space-1) 6px; }

        /* ===== RESET & BASE ===== */
        * { margin:0; padding:0; box-sizing:border-box; }
        body { font-family:'Segoe UI',Tahoma,Geneva,Verdana,sans-serif; background:var(--bg); color:var(--text1); direction:rtl; padding-bottom:var(--space-220); max-width:430px; margin:0 auto; transition:background var(--dur-slow) var(--ease-standard),color var(--dur-slow) var(--ease-standard); }
        /* RTL CSS Keystone Fix (2026-08-26) — body{direction:rtl} above is unconditional
           and overrides the [dir] attribute DirectionEngine.apply() sets on <html>. This
           override restores the .lang-ltr class it toggles on <body> as the real switch. */
        body.lang-ltr { direction:ltr; }
        /* App-wide iOS focus auto-zoom floor (App-Wide Mobile Input &
           Control Defects sprint, Batch 2, 2026-08-14) — iOS Safari zooms
           the viewport on focus for ANY input/textarea/select rendering
           below 16px. Bare element selectors carry the lowest specificity,
           so this is a FLOOR and not an override: every class-based rule
           and every inline style still wins over it. Its job is to catch
           form controls with no font-size source at all (#sleepHoursInput
           rendered at the 13.333px UA default before this) and to stop new
           fields being introduced below 16px. Do not add a sub-16px
           font-size to a form control. */
        input, textarea, select { font-size:var(--font-size-16); }
        body.dark { background:var(--bg); color:var(--text1); }
        body.dark .nav-item { background:var(--bg2); border-color:var(--border); color:var(--text1); }
        body.dark .header { background:#061212; }
        body.dark .morning-card { background:#061a1a; }
        body.dark .btn-cancel { background:transparent; color:var(--text2); }
        body.dark .btn-cancel:hover { color:var(--text1); }
        body.dark .btn-primary { background:var(--accent); color:var(--text-on-accent); }
        body.dark .month-nav { background:var(--bg2); color:var(--text2); }
        body.dark .streak-track-row { background:var(--bg3); }
        body.dark .task-label { color:var(--text1); }
        /* ===== HEADER ===== */
        .header { background:var(--accent-dark); padding:var(--space-14) 16px 12px; display:flex; align-items:center; gap:var(--space-8); position:sticky; top:0; z-index:10; transition:background var(--dur-slow) var(--ease-standard); }
        /* weight 700 + letter-spacing:-0.2px (2026-09-15) — matches
           .morning-title, the app's other --fs-heading-md/
           var(--text-on-accent) "prominent hero heading on an accent
           background" treatment, instead of inventing a separate style
           for the same role. Was font-weight:600, no letter-spacing. */
        .header-name { font-size:var(--fs-heading-md); font-weight:700; letter-spacing:-0.2px; color:var(--text-on-accent); flex-shrink:0; }
        /* Sprint 2 — نفس نتيجة justify-content:space-between القديمة بالضبط،
           بس بأسماء مناطق واضحة بدل 3 flex children مباشرة على .header.
           header-zone-middle فاضي من حيث المحتوى الإضافي دلوقتي (نفس أزرار
           header-right القديمة) فـ flex:1 عليه بيدي نفس المسافة اللي كانت
           بتتحسب تلقائيًا من space-between.
           .header نفسه دلوقتي عليه gap ثابت (var(--space-8)) بين الـ 3 مناطق
           (UI/UX fixes batch, 2026-09-12, Part A) — قبل كده مفيش أي فاصل
           مضمون بين header-zone-start (العنوان) وheader-zone-middle، فلما
           المنطقة النص تزدحم (تاريخ طويل + كذا زرار) العنوان كان بيتلزق
           في التاريخ/الأيقونة اللي جنبه مباشرة. الـ gap ده هو الحد الأدنى
           المضمون بغض النظر عن الزحمة جوه المنطقة النص. */
        .header-zone-start { display:flex; align-items:center; flex-shrink:0; }
        /* overflow-x:auto + scrollbar-width:none (نفس idiom .subnav/.fin-filter-tabs
           الموجود بالفعل في الملف ده) بدل ما نضغط الـ gap بين الأيقونات لحد
           2px على الموبايل (كان بيخلي الدوائر 44px تلزق في بعض بصريًا -
           Part A #1). دلوقتي header-date بيقصر لحد ما يخلص min-width:0 بتاعه
           الأول (ellipsis)، وبعد كده لو لسه فيه أيقونات مش لاقيه مكان، المنطقة
           دي بتعمل scroll أفقي بدل ما تكسر الـ gap أو تخلي حاجة تتقص/تتلزق -
           وده بيحافظ على الـ 44px tap target لكل زرار زي ما التعليق القديم
           كان بيأكد عليه. */
        .header-zone-middle { display:flex; align-items:center; gap:var(--space-8); flex:1; justify-content:center; min-width:0; overflow-x:auto; scrollbar-width:none; }
        .header-zone-middle::-webkit-scrollbar { display:none; }
        .header-zone-end { display:flex; align-items:center; flex-shrink:0; }
        /* Relocated into Intelligence/Overview 2026-07-22 (was a global-shell
           strip under the header). Styled to match .xp-bar-row directly above
           it in the same card stack (solid --accent-dark, same radius/margin)
           instead of the old edge-to-edge gradient header strip. Only 3 chips
           remain (Focus Score/Done Today/Morning Energy, down from 10) —
           Execution Load was later promoted out to the Intelligence Overview
           Hero card (2026-08-07, `ed5c510`) and is no longer one of the bar's
           chips — wider gaps/padding so it reads as spacious, not crowded.
           No longer clickable (hover tooltip replaces the old per-chip
           modal), so cursor is default, not pointer. */
        .exec-status-bar { background:var(--accent-dark); margin:0 0 12px; padding:var(--space-10) 16px; display:flex; align-items:center; flex-wrap:wrap; gap:var(--space-10); border-radius:var(--radius); }
        .esb-chip { display:flex; align-items:center; gap:var(--space-5); background:rgba(255,255,255,0.15); border:var(--border-hairline) solid rgba(255,255,255,0.25); border-radius:20px; padding:var(--space-5) 12px; cursor:default; flex-shrink:0; color:var(--text-on-accent); }
        .esb-ic { font-size:var(--fs-label); }
        .esb-val { font-size:var(--fs-label); color:var(--text-on-accent); font-weight:600; }
        /* min-width:44px (2026-09-16, was 0) — .header-date was the only
           flex child in .header-zone-middle without flex-shrink:0 (every
           icon button has it), so it absorbed 100% of any width deficit
           and collapsed to literally 0px at narrow widths (confirmed live
           at 320-360px), independent of icon count. 44px is a floor, not
           a token value — matches one .dark-toggle button-width's worth
           of room, enough for a few Arabic characters + the existing
           text-overflow:ellipsis. See docs/07_DECISIONS_ACTIVE.md →
           "Header Date Min-Width Floor". min-width stays on this parent
           element on purpose — refreshHeaderOverflowMenu()'s fit
           computation (assets/js/ui-modal-dialog.js) reads
           getComputedStyle(#headerDate).minWidth by id and doesn't care
           about the element's internal structure. */
        /* 2 lines (weekday / day+month) since 2026-09-15 — confirmed by
           live measurement that .header's 44px content-box height (set by
           the 44px icon buttons, not by this element) already had ~29px
           of unused vertical space around the old single-line text, and
           the 2-line block (~30px at normal line-height) fits inside it
           with zero height change to .header or any row below it — see
           docs/07_DECISIONS_ACTIVE.md → "Header Date Two-Line Wrap".
           display:flex column instead of the old single text node so each
           line gets its own overflow:hidden/ellipsis — a wrapped 2-line
           text node can't ellipsis per-line, only as one clamped block. */
        .header-date { display:flex; flex-direction:column; align-items:center; gap:var(--space-1); min-width:44px; overflow:hidden; }
        .header-date-weekday, .header-date-full { font-size:var(--fs-label); max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
        .header-date-weekday { color:rgba(255,255,255,0.5); }
        .header-date-full { color:rgba(255,255,255,0.75); font-weight:600; }
        .dark-toggle { width:44px; height:44px; flex-shrink:0; border-radius:var(--radius-full); border:var(--border-hairline) solid rgba(255,255,255,0.2); background:rgba(255,255,255,0.1); color:var(--text-on-accent); cursor:pointer; display:flex; align-items:center; justify-content:center; font-size:var(--fs-heading-sm); }
        /* Header popup — shared small dropdown pattern for Music/White Noise/
           Quick Tools (2026-07-22): anchored under its trigger button via a
           position:relative wrapper, not a full modal — matches the "small
           lightweight popup" spec instead of reusing the Notification
           Center's full-modal pattern. */
        .header-popup-wrap { position:relative; display:flex; }
        .header-popup { position:absolute; top:40px; left:0; min-width:190px; background:var(--bg2,#152020); border:var(--border-hairline) solid var(--border,rgba(255,255,255,0.12)); border-radius:var(--radius); box-shadow:0 8px 24px rgba(0,0,0,0.3); padding:var(--space-8); z-index:150; display:none; }
        .header-popup.show { display:block; }
        .header-popup-item { display:flex; align-items:center; gap:var(--space-8); padding:var(--space-8) 10px; border-radius:var(--radius-sm); cursor:pointer; font-size:var(--fs-body); color:var(--text1,#fff); }
        .header-popup-item:hover { background:rgba(255,255,255,0.06); }
        .header-popup-item.active { background:var(--accent); color:var(--text-on-accent); }
        .header-popup-divider { height:1px; background:var(--border,rgba(255,255,255,0.12)); margin:var(--space-6) 2px; }
        .header-popup-empty { display:flex; align-items:flex-start; gap:var(--space-8); padding:var(--space-8) 10px; font-size:var(--fs-body); color:var(--text2,rgba(255,255,255,0.7)); line-height:1.6; }
        .header-popup-volume { padding:var(--space-6) 10px 2px; }
        .header-popup-volume input[type="range"] { width:100%; }
        /* Music/White Noise have no header button of their own (Quick
           Tools only) — both open in the same fixed spot near the top of
           the screen (under the header), not anchored under any specific
           trigger button. */
        .header-popup.floating { position:fixed; top:54px; bottom:auto; left:50%; transform:translateX(-50%); }
        /* XP BAR — 2026-07-16: moved from the global header (shown on every
           tab) into the Dashboard tab only, as its first card, per user
           request. Styled as a rounded card (border-radius/margin) to match
           .dash-card spacing instead of the old edge-to-edge header strip. */
        .xp-bar-row { background:var(--accent-dark); padding:var(--space-10) 16px; display:flex; align-items:center; gap:var(--space-8); cursor:pointer; border-radius:var(--radius); margin-bottom:var(--space-12); }
        .xp-level-label { font-size:var(--fs-label); font-weight:600; color:var(--gold-light); white-space:nowrap; }
        .xp-bar-track { flex:1; height:5px; background:rgba(255,255,255,0.12); border-radius:var(--radius-full); overflow:hidden; }
        .xp-bar-fill { height:100%; border-radius:var(--radius-full); background:linear-gradient(90deg,var(--gold),var(--gold-light)); transition:width var(--dur-slow) var(--ease-standard); }
        .xp-num { font-size:var(--fs-caption); color:rgba(255,255,255,0.5); white-space:nowrap; }
        /* ===== NAVIGATION SYSTEM — Sidebar (Desktop) / Bottom Nav (Mobile) =====
           مصدر واحد: NAVIGATION_REGISTRY + NavigationEngine (JS). الرندرر بس بيختلف
           حسب المقاس — breakpoint عند 900px. تحت 900px: Bottom Nav ثابت تحت + Drawer
           (menuPanelModal نفسه، متغذي من نفس الـ Registry). فوق 900px: Sidebar ثابت
           على اليمين فى العربي (RTL) وعلى الشمال فى الإنجليزي (LTR) — نفس نمط
           body.lang-ltr المستخدم فى RTL CSS Keystone Fix (2026-08-26)؛ التعليق
           القديم هنا كان يقول "على الشمال حتى مع RTL" وده كان غلط، متعارض مع
           الكود الفعلي (right:0) — اتصحح هنا، مش الكود. */
        .nav-sidebar { display:none; }
        .nav-bottom { display:flex; position:fixed; bottom:0; right:0; left:0; max-width:430px; margin:0 auto; height:58px; background:var(--bg2); border-top:var(--border-hairline) solid rgba(var(--accent-rgb),0.12); z-index:9; }
        body.dark .nav-bottom { background:var(--bg2); }
        .nav-bottom-item { flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:var(--space-2); background:none; border:none; color:var(--text3); font-family:inherit; font-size:var(--fs-caption); cursor:pointer; padding:0; }
        .nav-bottom-icon { font-size:var(--font-size-17); line-height:1; position:relative; display:inline-block; }
        .nav-bottom-item.active { color:var(--accent); font-weight:600; }
        .nav-badge { position:absolute; top:-6px; left:-8px; min-width:14px; height:14px; padding:0 3px; border-radius:var(--radius-full); background:var(--danger); color:var(--text-on-accent); font-size:var(--fs-micro); font-weight:700; line-height:14px; text-align:center; }
        /* FOCUS NAVIGATION — Group 3 (Sprint 7). أثناء جلسة تركيز نشطة (currentFocusSession)
           بيتخفوا كل عناصر التنقل غير الضرورية، ويفضل بس "اليوم" — الجلسة/الإيقاف
           أصلاً ظاهرين جوه #focusTimer، والعودة بتحصل تلقائي لما الجلسة تقفل. */
        body.focus-nav-active .nav-bottom-item:not([data-nav-id="today"]) { display:none; }
        body.focus-nav-active .nav-sidebar-top { display:none; }
        @media (min-width:900px) {
            .nav-bottom { display:none; }
            body.focus-nav-active .nav-item:not([data-nav-id="today"]) { display:none; }
            /* #toastStack had the same viewport-edge-relative right:279px bug
               #mainFab/#focusTimer were already fixed for (see #mainFab's
               comment below) — it only lined up with the app's content
               column at one specific desktop width, overflowing toward the
               screen edge at any other width instead of staying anchored to
               the column's real center. Same fix: anchor via 100vw minus the
               reserved sidebar width, same as #mainFab. No transform reset
               needed here — the base rule's transform:translateX(-50%)
               (line ~1270) is already plain, unlike #focusTimer's +145px
               offset.
               `body #toastStack` (not plain `#toastStack`) — same trap
               #focusTimer's own comment below already flags: the
               unconditional base #toastStack{} rule (line ~1280) sits later
               in the file at equal (bare-ID) specificity, so a plain
               #toastStack here would lose the cascade tie by source order
               and silently do nothing at any width ≥900px. Confirmed live
               (getComputedStyle) before adding this prefix — the bare-ID
               version measured as having no effect at all. */
            body #toastStack { left:calc((100vw - 64px) / 2); right:auto; bottom:32px; }
            /* RTL CSS Keystone Fix (2026-08-26) — sidebar mirrors to the left in LTR (see body.lang-ltr near line 216); mirror its reserved-space offsets too. */
            body.lang-ltr #toastStack { left:calc((100vw + 64px) / 2); }
            /* #mainFab keeps the mobile left:50%+transform:translateX(-50%)
               centering (not right:Npx) so it stays anchored to the
               center of the app's own content column at any desktop
               width, instead of a viewport-edge-relative offset that
               only lined up with the old (buggy) right-hugging body
               layout. ID selector (not .fab) because this @media block
               sits earlier in the file than the base .fab{} rule — equal
               specificity would let the later, unconditional base rule
               win the cascade regardless of the media condition. */
            #mainFab { left:calc((100vw - 64px) / 2); right:auto; bottom:32px; }
            /* RTL CSS Keystone Fix (2026-08-26) — sidebar reserves 64px on the left in LTR instead of the right; re-center within the remaining space accordingly. */
            body.lang-ltr #mainFab { left:calc((100vw + 64px) / 2); }
            /* #focusTimer (Focus Session counter card) had the same
               viewport-edge-relative right:279px bug #mainFab was already
               fixed for — only lined up with the timeline/header column at
               one specific desktop width, drifting off to the side (fully
               outside the header/timeline area) at any other width. Same
               fix: anchor to the content column's real center via 100vw
               minus the reserved sidebar width. Also resets the base
               rule's translateX(-50% + 145px) back to plain translateX(-50%)
               — that +145px existed to clear #mainFab on the narrow mobile
               column, but body.focus-nav-active already hides .fab
               whenever #focusTimer is showing (same condition, mutually
               exclusive), so on desktop the offset only pushed the (wider,
               min-width:210px) card past the header's own right edge —
               exactly the reported bug. Dead-center keeps it inside the
               header's width at any desktop size. `body #focusTimer` (not
               plain `#focusTimer`) — the unconditional base #focusTimer{}
               rule sits later in the file (same ID specificity), so it
               would otherwise win this cascade tie by source order and
               silently undo this override at any width ≥900px, same trap
               #mainFab's comment above already flags. */
            body #focusTimer { left:calc((100vw - 64px) / 2); right:auto; bottom:32px; transform:translateX(-50%); }
            /* RTL CSS Keystone Fix (2026-08-26) — see body.lang-ltr #mainFab above; same reasoning. */
            body.lang-ltr #focusTimer { left:calc((100vw + 64px) / 2); }
            /* Center the mobile-width column in the space left of the
               64px nav-sidebar, instead of hugging its right edge with
               margin-right:var(--space-64) (which, combined with the unchanged
               max-width:430px from the base rule, over-constrained the
               box and pushed all the leftover width to the left as dead
               space). */
            body { margin-left:calc((100vw - 494px) / 2); margin-right:calc(64px + (100vw - 494px) / 2); padding-bottom:var(--space-24); }
            body.nav-sidebar-pinned { margin-left:calc((100vw - 650px) / 2); margin-right:calc(220px + (100vw - 650px) / 2); }
            body.nav-sidebar-pinned #toastStack { left:calc((100vw - 220px) / 2); right:auto; }
            body.nav-sidebar-pinned #focusTimer { left:calc((100vw - 220px) / 2); right:auto; }
            body.nav-sidebar-pinned #mainFab { left:calc((100vw - 220px) / 2); right:auto; }
            /* RTL CSS Keystone Fix (2026-08-26) — sidebar reserves space on the left in
               LTR instead of the right; swap body's margin-left/margin-right (and the
               pinned-width variant) so the content column re-centers on the correct side,
               and mirror the pinned toastStack/focusTimer/mainFab offsets the same way
               as their unpinned counterparts above. */
            body.lang-ltr { margin-left:calc(64px + (100vw - 494px) / 2); margin-right:calc((100vw - 494px) / 2); }
            body.lang-ltr.nav-sidebar-pinned { margin-left:calc(220px + (100vw - 650px) / 2); margin-right:calc((100vw - 650px) / 2); }
            body.lang-ltr.nav-sidebar-pinned #toastStack { left:calc((100vw + 220px) / 2); }
            body.lang-ltr.nav-sidebar-pinned #focusTimer { left:calc((100vw + 220px) / 2); }
            body.lang-ltr.nav-sidebar-pinned #mainFab { left:calc((100vw + 220px) / 2); }
            /* .modal-overlay is position:fixed;inset:0 (full viewport, for the
               dimming backdrop) so its own centering ignores body's shifted
               column above — modals rendered dead-center of the viewport
               instead of centered under the header. Mirror the same reserved
               sidebar width as padding so justify-content:center centers the
               modal box within the same column as body/header. */
            .modal-overlay { padding-right:var(--space-64); }
            body.nav-sidebar-pinned .modal-overlay { padding-right:var(--space-220); }
            /* RTL CSS Keystone Fix (2026-08-26) — mirror the reserved-column padding to the left in LTR. */
            body.lang-ltr .modal-overlay { padding-right:0; padding-left:var(--space-64); }
            body.lang-ltr.nav-sidebar-pinned .modal-overlay { padding-left:var(--space-220); }
            .nav-sidebar { display:flex; flex-direction:column; position:fixed; top:0; right:0; bottom:0; width:64px; background:var(--bg2); border-right:var(--border-hairline) solid rgba(var(--accent-rgb),0.12); z-index:30; transition:width var(--dur-fast) var(--ease-standard); overflow:hidden; }
            body.dark .nav-sidebar { background:var(--bg2); }
            .nav-sidebar:hover, .nav-sidebar.pinned { width:220px; box-shadow:-2px 0 16px rgba(0,0,0,0.12); }
            /* RTL CSS Keystone Fix (2026-08-26) — sidebar moves to the left edge in LTR;
               swap its fixed-edge and accent-border sides, and the hover/pinned shadow's
               cast direction (was toward the content on its left, now toward the content
               on its right). */
            body.lang-ltr .nav-sidebar { right:auto; left:0; border-right:none; border-left:var(--border-hairline) solid rgba(var(--accent-rgb),0.12); }
            body.lang-ltr .nav-sidebar:hover, body.lang-ltr .nav-sidebar.pinned { box-shadow:2px 0 16px rgba(0,0,0,0.12); }
            .nav-sidebar-top { display:flex; justify-content:flex-end; padding:var(--space-10) 8px; }
            .nav-sidebar-pin { background:none; border:none; color:var(--text3); font-size:var(--fs-heading-sm); cursor:pointer; padding:var(--space-4); border-radius:var(--radius-sm); opacity:0.5; transition:transform var(--dur-fast) var(--ease-standard),color var(--dur-fast) var(--ease-standard),opacity var(--dur-fast) var(--ease-standard); display:inline-block; }
            .nav-sidebar:hover .nav-sidebar-pin, .nav-sidebar.pinned .nav-sidebar-pin { opacity:1; }
            .nav-sidebar-pin.active { color:var(--accent); opacity:1; transform:rotate(45deg); }
            .nav-sidebar-modules { display:flex; flex-direction:column; gap:var(--space-2); padding:var(--space-4); flex:1; overflow-y:auto; }
            .nav-item { display:flex; align-items:center; gap:var(--space-12); padding:var(--space-10) 12px; border-radius:var(--radius-sm); background:none; border:none; color:var(--text3); cursor:pointer; font-family:inherit; font-size:var(--fs-body); white-space:nowrap; width:100%; text-align:right; }
            /* RTL CSS Keystone Fix (2026-08-26) — see body.lang-ltr near line 216. */
            body.lang-ltr .nav-item { text-align:left; }
            .nav-item:hover { background:rgba(var(--accent-rgb),0.08); }
            .nav-item.active { color:var(--accent); background:rgba(var(--accent-rgb),0.1); font-weight:600; }
            .nav-item-icon { font-size:var(--fs-heading-md); width:var(--icon-box-24); text-align:center; flex-shrink:0; position:relative; display:inline-block; }
            .nav-item-label { display:none; }
            .nav-sidebar:hover .nav-item-label, .nav-sidebar.pinned .nav-item-label { display:inline; }
        }
        /* Thinking Space Canvas — Desktop Viewport Widening (Phase 1,
           2026-08-30). #tsViewport declares no width of its own (see
           masari.html:56540) — it fills its parent #thinkCanvasCard,
           which inherits body's max-width:430px minus .tab-content's and
           .fin-module's 16px×2 horizontal padding each (430-32-32=366px),
           on EVERY screen size, since neither of those two shared rules
           (masari.html:391,605,1935) has ever set its own width. The old
           desktop @media block above only recenters that same 430px body
           column in the leftover space beside the nav-sidebar — it never
           widens it (see body's own comment at masari.html:552).
           This widens ONLY #thinkCanvasCard on desktop — no other
           selector here touches body/.tab-content/.fin-module, so every
           other tab/sub-tab sharing those 3 rules (confirmed via grep:
           nothing else overrides width/max-width on them) is completely
           unaffected, on desktop or mobile.
           --ts-canvas-w is capped via min() so the widened box can never
           reach the reserved nav-sidebar (64px, 220px pinned) or the
           screen edge at ANY width the 900px breakpoint allows — worst
           case exactly at 900px viewport: min(1000, 900-64-48)=788px,
           still >2x the 366px baseline. margin-left/right use % (not a
           literal 366) so they resolve against #thinkCanvasCard's own
           containing block (#tsSection-spaces, which has no padding of
           its own) and stay correct if that 366px baseline ever shifts
           upstream. No LTR/RTL-specific mirror rule is needed here
           (unlike #mainFab/#toastStack/#focusTimer above) — symmetric
           left/right margins re-center on whichever side body's own
           already-mirrored center sits, without this rule needing to
           know which physical side the sidebar reserves.
           The camera/viewport math (_tsViewportDims/_tsClampPan/
           _tsFitScale/_tsWorkspaceBounds) needs no code change to pick
           up the new size — _tsViewportDims() (masari.html:56819) always
           reads #tsViewport's live clientWidth/clientHeight from the DOM
           at call time; nothing in that math hardcodes the old ~366px
           figure. */
        @media (min-width:900px) {
            #thinkCanvasCard {
                --ts-canvas-w: min(1000px, calc(100vw - 64px - 48px));
                width: var(--ts-canvas-w);
                margin-left: calc((100% - var(--ts-canvas-w)) / 2);
                margin-right: calc((100% - var(--ts-canvas-w)) / 2);
            }
            body.nav-sidebar-pinned #thinkCanvasCard {
                --ts-canvas-w: min(1000px, calc(100vw - 220px - 48px));
            }
        }
        /* TAB CONTENT */
        .tab-content { display:none; padding:var(--space-14) 16px; }
        .tab-content.active { display:block; }
        /* [T-367 d] inactive tabs keep their laid-out subtree (content-visibility:hidden skips rendering and, like display:none, hides it from find, focus and the a11y tree); padding 0 and the zero intrinsic block size keep the box at 0 height so nothing shifts; printTab() shows a non-active tab by an inline display:block, which must stay printable, so that case is excluded */
        .tab-content:not(.active):not([style*="display: block"]) { display:block; content-visibility:hidden; contain-intrinsic-size:auto 0; padding:0; }
        .subview:not(.active) { display:block; content-visibility:hidden; contain-intrinsic-size:auto 0; }
        /* SUBNAV */
        .subnav { display:flex; gap:var(--space-6); overflow-x:auto; margin-bottom:var(--space-12); scrollbar-width:none; }
        .subnav::-webkit-scrollbar { display:none; }
        .subview { display:none; }
        .subview.active { display:block; }
        /* Planner subviews need padding since parent tab has padding:0 for fin-subnav */
        #tab-planner .subview.active { padding:var(--space-14) 16px; }
        /* CARDS */
        .dash-card { background:var(--bg2); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.12); border-radius:var(--radius); padding:var(--space-14); margin-bottom:var(--space-12); box-shadow:var(--shadow-card); }
        body.dark .dash-card { background:var(--bg2); border-color:rgba(var(--accent-rgb),0.2); }
        .dash-card.is-selected { border-color:var(--accent); }
        /* Systems Library card — per-system accent gradient (--sys-accent set
           inline per card) layered on top of .dash-card, plus a stronger tint
           + accent border once installed so installed/not-installed read as
           two distinct states, not just the small badge/button-row swap. */
        .sys-mkt-card { background:linear-gradient(135deg, color-mix(in srgb, var(--sys-accent) 9%, var(--bg2)) 0%, var(--bg2) 100%); }
        body.dark .sys-mkt-card { background:linear-gradient(135deg, color-mix(in srgb, var(--sys-accent) 16%, var(--bg2)) 0%, var(--bg2) 100%); }
        .sys-mkt-card.is-installed { background:linear-gradient(135deg, color-mix(in srgb, var(--sys-accent) 24%, var(--bg2)) 0%, color-mix(in srgb, var(--sys-accent) 6%, var(--bg2)) 100%); border-color:color-mix(in srgb, var(--sys-accent) 55%, transparent); }
        body.dark .sys-mkt-card.is-installed { background:linear-gradient(135deg, color-mix(in srgb, var(--sys-accent) 32%, var(--bg2)) 0%, color-mix(in srgb, var(--sys-accent) 10%, var(--bg2)) 100%); border-color:color-mix(in srgb, var(--sys-accent) 55%, transparent); }
        /* Unified Time Picker — one shared 3-column wheel popover
           (Hour|Minute|AM-PM) replacing every native input[type=time]
           app-wide. The native input stays in the DOM at each call site
           (time-wheel-input-hidden) as the real value/event source — the
           chip is purely a presentation swap, so no downstream onchange/
           .value-reading code needed to change. */
        .time-wheel-input-hidden { display:none; }
        .time-chip { display:inline-flex; align-items:center; gap:var(--space-5); padding:var(--space-5) 10px; border-radius:var(--radius-sm); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.25); background:var(--bg3); color:var(--text1); font-size:var(--fs-body); font-family:inherit; cursor:pointer; direction:ltr; }
        .time-chip:hover { border-color:var(--accent); }
        /* «مسح الوقت» next to a .time-chip (task window). Ghost variant, sized like the chip it sits beside
           so the tap target is never smaller than its neighbour. */
        .btn-inline.time-clear-btn { display:inline-flex; align-items:center; gap:var(--space-5); padding:var(--space-5) 10px; font-size:var(--fs-body); margin-inline-start:var(--space-6); vertical-align:middle; align-self:stretch; }
        .time-wheel-popover { position:fixed; z-index:6000; background:var(--bg2); border:var(--border-hairline) solid var(--border); border-radius:var(--radius); box-shadow:var(--shadow-card); display:none; padding:var(--space-6); direction:ltr; }
        .time-wheel-popover.open { display:flex; }
        .time-wheel-col { width:52px; max-height:190px; overflow-y:auto; text-align:center; scrollbar-width:thin; }
        .time-wheel-col > div { padding:var(--space-6) 0; font-size:var(--fs-body); cursor:pointer; border-radius:var(--radius-sm); color:var(--text2); }
        .time-wheel-col > div:hover { background:rgba(var(--accent-rgb),0.12); }
        .time-wheel-col > div.selected { background:var(--accent); color:var(--text-on-accent); font-weight:600; }
        .time-wheel-divider { width:1px; background:var(--border); margin:var(--space-4) 3px; }
        .dash-card-title { font-size:var(--font-size-12); font-weight:600; color:var(--text3); letter-spacing:0.4px; margin-bottom:var(--space-8); display:flex; align-items:center; justify-content:space-between; gap:var(--space-8); }
        .dash-card-title > span:first-child { display:flex; align-items:center; flex:1; min-width:0; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }
        .dash-stat-row { display:flex; justify-content:space-between; align-items:center; padding:var(--space-7) 0; border-bottom:var(--border-hairline) solid rgba(var(--accent-rgb),0.12); font-size:var(--fs-body); }
        /* Project Detail's Execution task row (icon-container sizing
           convergence, 2026-08-30) — .dash-stat-row itself has no gap, so
           its drag-handle/text/checkbox/menu-button sat flush against each
           other (0px between them, confirmed by measurement) — scoped here
           rather than adding gap to the shared .dash-stat-row base rule,
           which has ~90 other consumers with different content shapes. */
        .pd-task-row { gap:var(--space-6); padding:var(--space-4) 8px; }
        .intel-severity-badge { font-size:var(--fs-caption); padding:var(--space-2) 6px; border-radius:var(--radius-sm); flex-shrink:0; background:color-mix(in srgb, var(--text3) 13%, transparent); color:var(--text3); }
        .intel-severity-badge.intel-severity-high { background:color-mix(in srgb, var(--danger) 13%, transparent); color:var(--danger); }
        .intel-severity-badge.intel-severity-medium { background:color-mix(in srgb, var(--warning) 13%, transparent); color:var(--warning); }
        .intel-severity-badge.intel-severity-low { background:color-mix(in srgb, var(--success) 13%, transparent); color:var(--success); }
        .dash-stat-row.severity-danger, .dash-stat-row.severity-warning, .dash-stat-row.severity-muted { border-inline-start:var(--border-medium) solid; padding-inline-start:8px; }
        .dash-stat-row.severity-danger { border-inline-start-color:var(--danger); }
        .dash-stat-row.severity-warning { border-inline-start-color:var(--warning); }
        .dash-stat-row.severity-muted { border-inline-start-color:var(--text3); }
        .eis-quadrant { min-height:32px; border-radius:var(--radius-sm); transition:background var(--dur-fast) var(--ease-standard); }
        .eis-quadrant.eis-drop-over { background:rgba(var(--accent-rgb),0.08); outline:2px dashed var(--accent); outline-offset:-2px; }
        .dash-stat-row.pd-task-dragging { opacity:0.35; }
        .dash-stat-row.pd-drop-over { outline:2px dashed var(--accent); outline-offset:-2px; }
        .pm-card.pd-task-dragging, .pm-row.pd-task-dragging { opacity:0.35; }
        .pm-card.pd-drop-over, .pm-row.pd-drop-over { outline:2px dashed var(--accent); outline-offset:-2px; }
        .menu-item.pd-task-dragging { opacity:0.35; }
        .menu-item.pd-drop-over { outline:2px dashed var(--accent); outline-offset:-2px; }
        .backlog-item.pd-task-dragging { opacity:0.35; }
        .backlog-item.pd-drop-over { outline:2px dashed var(--accent); outline-offset:-2px; }
        .dash-stat-row:last-child { border-bottom:none; }
        .dash-stat-num { font-weight:600; color:var(--accent); font-size:var(--fs-body); }
        /* Flagged-row/card convention (Visual & UX Completion Audit Batch 1,
           Sub-batch 2) — ONE shared visual treatment for any row/card that
           carries a real engine-computed importance signal (habit
           streak-risk via _habitIsAtRisk(), knowledge connectivity health
           via KnowledgeEngine.getHealthSignals()), applied at each surface's
           own render function rather than reinvented per surface. Compound
           selectors (not a bare .flagged-item rule) so this wins on
           specificity over each base class's own border, regardless of
           source order. Eisenhower cards deliberately do NOT get this
           treatment — their border-right slot already carries real
           pillar/track color-coding (getTaskColor()), and "due-date
           proximity" has no existing engine signal to reuse without
           inventing new computation, both out of this sub-batch's scope. */
        .dash-stat-row.flagged-item, .knowledge-card.flagged-item { border-right:var(--border-thick) solid var(--accent); font-weight:600; }
        .dash-stat-row.flagged-item { padding-right:var(--space-8); }
        .dash-empty { font-size:var(--font-size-12); color:var(--text3); text-align:center; padding:var(--space-10) 0; }
        .dash-empty.spacious { padding:var(--space-16) 8px; }
        .dash-empty.compact { padding:var(--space-8) 8px; }
        .dash-empty-icon { font-size:var(--icon-glyph-22); margin-bottom:var(--space-6); }
        .dash-empty.compact .dash-empty-icon { margin-bottom:var(--space-4); }
        .dash-empty-title { margin-bottom:var(--space-8); }
        .dash-empty.compact .dash-empty-title { margin-bottom:var(--space-4); }
        .dash-empty-hint { font-size:var(--fs-label); color:var(--text3); margin-bottom:var(--space-8); }
        .dash-empty.compact .dash-empty-hint { margin-bottom:var(--space-4); }
        /* Executive Dashboard Evolution (2026-07-16) — visual-weight tiers.
           Critical (alert cards, only shown when there's real data — see
           renderDashboard()) get a strong right accent + tinted background
           (right, not left — this is an RTL app; corrected 2026-08-25,
           Visual & UX Completion Audit Batch 3, comment-only, no rule
           change: the live rule was already border-right, confirmed via
           computed-style ground truth);
           Informational (achievements/activity) get a quieter, subdued
           look so the eye naturally lands on Critical first. */
        .dash-exec-summary-text { font-size:var(--fs-heading-sm); line-height:1.7; color:var(--text1); margin:0; }
        .dash-card-quiet { box-shadow:none; opacity:0.85; }
        .dash-card-quiet .dash-card-title { color:var(--text3); }
        /* Intelligence Refinement Pass (2026-07-19) — typography/spacing
           emphasis only, explicitly NOT a new card-tier system (descoped
           per the design spec, Section 5/7: deciding Hero/Secondary/
           Supporting needs a full-app review, not a call made here).
           Applied only to Productivity's headline KPI rows. */
        .dash-stat-row-headline { font-weight:600; font-size:var(--fs-heading-sm); }
        .dash-stat-row-headline .dash-stat-num { font-size:var(--font-size-15); }
        /* Daily Summary hierarchy (2026-07-24) — main mood line bolder than
           the base .dash-exec-summary-text size, streak/focus meta quieter,
           and a colored flag line replacing the old flat sentence list so
           "needs attention" vs "all clear" reads at a glance. */
        .dash-exec-summary-main { font-weight:700; }
        .dash-exec-summary-meta { font-size:var(--font-size-12); color:var(--text3); margin:var(--space-2) 0 0; }
        .dash-exec-summary-flag { font-size:var(--fs-body); font-weight:600; margin:var(--space-6) 0 0; }
        .dash-exec-summary-flag-warn { color:var(--warning); }
        .dash-exec-summary-flag-ok { color:var(--accent); }
        /* Activity Feed time grouping (2026-07-24) — small muted section
           label ("اليوم"/"أمس"/older date), not a full card header. */
        .dash-activity-group-title { font-size:var(--fs-caption); font-weight:600; color:var(--text3); text-transform:uppercase; letter-spacing:0.04em; margin:var(--space-8) 0 2px; }
        .dash-activity-group-title:first-child { margin-top:0; }
        /* Executive Summary emphasis (2026-07-23) — single-card typography/
           spacing override ONLY, requested because it read as equal-weight
           to Activity/Achievements. NOT a reusable tier class and NOT a
           reopening of deferred item #23 in docs/12_NEXT_TASK.md (a general
           Hero/Medium/Supporting card-tier system, rejected twice as
           premature) — scoped to #dashTodayStatusCard alone, same
           single-card-exception precedent as .dash-stat-row-headline above. */
        #dashTodayStatusCard .dash-exec-summary-text { font-size:var(--font-size-16); line-height:1.75; font-weight:500; margin:var(--space-2) 0; }
        /* أداء جوانب حياتك (2026-07-23) — compact per-pillar status card,
           replaces the old table-like .dash-stat-row list. */
        .pillar-status-card { background:var(--bg2); border-radius:var(--radius-sm); padding:var(--space-8) 10px; }
        .pillar-status-card.pillar-health-success, .pillar-status-card.pillar-health-danger, .pillar-status-card.pillar-health-warning, .pillar-status-card.pillar-health-muted { border-right:var(--border-medium) solid; }
        .pillar-status-card.pillar-health-success { border-right-color:var(--success); }
        .pillar-status-card.pillar-health-danger { border-right-color:var(--danger); }
        .pillar-status-card.pillar-health-warning { border-right-color:var(--warning); }
        .pillar-status-card.pillar-health-muted { border-right-color:var(--text3); }
        .achievement-tile { background:var(--bg2); border-style:solid; border-width:var(--border-hairline); border-color:var(--accent); border-radius:var(--radius-md); padding:var(--space-10) 8px; text-align:center; opacity:1; }
        .achievement-tile.is-locked { background:var(--bg3); border-color:var(--border); opacity:0.4; }
        .achievement-tile.rarity-epic, .achievement-tile.rarity-legendary { border-width:var(--border-thin); }
        .achievement-tile.rarity-epic { box-shadow:0 0 0 2px var(--color-rarity-epic); transform:scale(1.03); }
        .achievement-tile.rarity-legendary { box-shadow:0 0 0 2px var(--color-rarity-legendary), 0 0 14px color-mix(in srgb, var(--color-rarity-legendary) 50%, transparent); transform:scale(1.03); }
        .u-text-rarity-rare { color:var(--color-rarity-rare); }
        .u-text-rarity-epic { color:var(--color-rarity-epic); }
        .u-text-rarity-legendary { color:var(--color-rarity-legendary); }
        #dashTodayStatusCard .dash-card-title { font-size:var(--fs-heading-sm); font-weight:600; }
        /* Habits "ملخص العادات" Hero (Premium UI Sprint, Hero Cards phase,
           2026-07-31) — was 3 equal-weight text lines; now one big number
           answers the single most important question first (at-risk > best
           streak > fastest improving), the rest as smaller supporting chips.
           Single-card exception, same precedent as #dashTodayStatusCard
           above — NOT a reusable Hero-tier class, no reopening of the
           rejected general Hero/Secondary/Supporting system. */
        #habitsBestWorstCard { padding:var(--space-16) 14px; }
        #habitsBestWorstCard .habit-hero-primary { display:flex; align-items:center; gap:var(--space-12); }
        #habitsBestWorstCard .habit-hero-icon { width:44px; height:44px; border-radius:var(--radius-full); display:flex; align-items:center; justify-content:center; flex-shrink:0; }
        #habitsBestWorstCard .habit-hero-icon.habit-hero-risk { background:rgba(200,90,0,0.14); color:var(--warning); }
        #habitsBestWorstCard .habit-hero-icon.habit-hero-best { background:rgba(184,134,11,0.14); color:var(--gold); }
        #habitsBestWorstCard .habit-hero-icon.habit-hero-improving { background:rgba(45,122,74,0.14); color:var(--success); }
        #habitsBestWorstCard .habit-hero-num { font-size:var(--fs-stat); font-weight:800; line-height:1.1; color:var(--text1); }
        #habitsBestWorstCard .habit-hero-label { font-size:var(--font-size-12); color:var(--text3); margin-top:var(--space-1); }
        #habitsBestWorstCard .habit-hero-sub { font-size:var(--fs-body); font-weight:600; color:var(--text1); margin-top:var(--space-2); }
        #habitsBestWorstCard .habit-hero-secondary { display:flex; gap:var(--space-12); flex-wrap:wrap; margin-top:var(--space-12); padding-top:var(--space-10); border-top:var(--border-hairline) solid var(--border); font-size:var(--font-size-12); color:var(--text3); }
        /* Premium Details pass (2026-07-31) — the card only became genuinely
           clickable (→ Intelligence/Performance) when it started leading
           with a real Hero number; .is-clickable is toggled by the same JS
           that already sets cursor:pointer, scoped so a non-clickable
           (empty) card never shows misleading hover/press feedback. */
        #habitsBestWorstCard.is-clickable { transition:box-shadow var(--dur-fast) var(--ease-standard),transform var(--dur-fast) var(--ease-standard); }
        #habitsBestWorstCard.is-clickable:hover { box-shadow:var(--shadow-card-hover); transform:translateY(-1px); }
        #habitsBestWorstCard.is-clickable:active { transform:scale(0.98); }
        /* Manager stat-strip Hero shared shell (Premium UI Sprint, Hero Cards
           phase, 2026-07-31) — Projects/Pillar/Stages Managers all had the
           exact same "N equal-weight text spans" shape (unlike Habits/
           Ambitions/Knowledge below, which each need their own icon/color
           logic), so ONE small shared shell is reused for these three
           instead of copy-pasting the same rules 3x — still not the
           app-wide Hero/Secondary/Supporting tier system (rejected), just a
           genuinely identical structure DRY'd once, same "one component" rule
           .gpill/.menu-item already follow. */
        .mgr-stat-hero { display:flex; align-items:center; gap:var(--space-10); margin-bottom:var(--space-8); }
        .mgr-stat-hero-icon { width:38px; height:38px; border-radius:var(--radius-full); background:rgba(var(--accent-rgb),0.14); color:var(--accent); display:flex; align-items:center; justify-content:center; flex-shrink:0; }
        .mgr-stat-hero-num { font-size:var(--fs-stat); font-weight:800; line-height:1.1; color:var(--text1); }
        .mgr-stat-hero-label { font-size:var(--font-size-12); color:var(--text3); margin-top:var(--space-1); }
        .mgr-stat-hero-secondary { display:flex; gap:var(--space-10); flex-wrap:wrap; font-size:var(--fs-label); color:var(--text3); }
        /* Intelligence sub-tab presentation variety (2026-07-19, Intelligence
           Refinement Pass, Section 8 of the design spec) — Discoveries gets
           a highlight treatment (raw observations deserve visual weight
           distinct from Analysis/Decisions' plainer stat rows); Memory gets
           a vertical-steps timeline (docs/DESIGN_SYSTEM.md's "Timeline
           Blocks", documented as intended, never built until now — reused
           here for its first real consumer). Both scoped to this one
           sub-tab, not a general system. */
        .ih-highlight-block { border-right:var(--border-medium) solid var(--accent); background:rgba(var(--accent-rgb),0.06); border-radius:var(--radius-sm); padding:var(--space-4) 10px; margin-bottom:var(--space-4); }
        body.dark .ih-highlight-block { background:rgba(var(--accent-rgb),0.1); }
        .ih-timeline { position:relative; padding-right:var(--space-22); }
        .ih-timeline-item { position:relative; padding-bottom:var(--space-14); }
        .ih-timeline-item:last-child { padding-bottom:0; }
        .ih-timeline-item::before { content:''; position:absolute; right:-18px; top:4px; width:8px; height:8px; border-radius:50%; background:var(--accent); }
        .ih-timeline-item::after { content:''; position:absolute; right:-15px; top:14px; bottom:0; width:2px; background:rgba(var(--accent-rgb),0.2); }
        .ih-timeline-item:last-child::after { display:none; }
        /* Executive Brief (2026-07-27, Intelligence Center rebuild as an
           Executive Briefing System) — replaces the old .ih-hero-section
           card-with-emoji-title treatment. This is a canvas, not a card:
           headline/support/CTA, composed differently per arc
           (see ExecutiveBriefComposer()), never a fixed template. Arc
           modifiers below only change accent — markup/anatomy stays
           identical across arcs, per "one system, different moods". */
        .ih-brief { border-radius:var(--radius-lg); padding:var(--space-16) 18px; margin-bottom:var(--space-14); background:linear-gradient(135deg,rgba(var(--accent-rgb),0.14),rgba(var(--accent-rgb),0.03)); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.28); }
        .ih-brief-headline { font-size:var(--font-size-16); font-weight:800; line-height:1.5; color:var(--accent-dark); margin-bottom:var(--space-6); }
        body.dark .ih-brief-headline { color:var(--accent); }
        .ih-brief-support { font-size:var(--fs-body); color:var(--text2); line-height:1.6; margin-bottom:var(--space-10); }
        .ih-brief-cta { display:block; width:100%; }
        .ih-brief-crisis { background:linear-gradient(135deg,rgba(var(--danger-rgb),0.16),rgba(var(--danger-rgb),0.04)); border-color:rgba(var(--danger-rgb),0.35); }
        .ih-brief-crisis .ih-brief-headline { color:var(--danger); }
        .ih-brief-crisis .ih-brief-cta { background:var(--danger) !important; }
        .ih-brief-opportunity { background:linear-gradient(135deg,rgba(184,134,11,0.16),rgba(184,134,11,0.04)); border-color:rgba(184,134,11,0.35); }
        .ih-brief-opportunity .ih-brief-headline { color:var(--gold); }
        .ih-brief-opportunity .ih-brief-cta { background:var(--gold) !important; }
        .ih-brief-learning { background:linear-gradient(135deg,rgba(var(--accent-rgb),0.1),rgba(var(--accent-rgb),0.02)); border-color:rgba(var(--accent-rgb),0.2); }
        .ih-brief-learning .ih-brief-headline { font-weight:700; font-style:italic; }
        .ih-brief-quiet { background:var(--bg2); border-color:rgba(var(--accent-rgb),0.12); }
        .ih-brief-quiet .ih-brief-headline { font-size:var(--fs-heading-sm); font-weight:600; color:var(--text2); }
        /* Executive section peer headers (القرار/الفهم/الفرص/التعلم) —
           bolder than the old 11px muted sub-labels since these are named,
           institutional sections of a briefing, not throwaway captions. */
        .ih-sec-title { font-size:var(--fs-heading-sm); font-weight:700; color:var(--accent); margin:var(--space-16) 0 8px; display:flex; align-items:center; gap:var(--space-6); }
        .ih-sec-title:first-child { margin-top:0; }
        /* Project Workspace — Executive Hero (Project Workspace Redesign,
           same "canvas, one card, state-driven variant" pattern as
           .ih-brief above, re-themed for a single project's own state
           instead of a daily narrative arc). */
        .ph-hero { border-radius:var(--radius-lg); padding:var(--space-16) 18px; margin-bottom:var(--space-12); background:linear-gradient(135deg,rgba(var(--accent-rgb),0.14),rgba(var(--accent-rgb),0.03)); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.28); }
        .ph-hero-name { font-size:var(--fs-heading-md); font-weight:800; color:var(--accent-dark); }
        body.dark .ph-hero-name { color:var(--accent); }
        .ph-hero-objective { font-size:var(--fs-body); color:var(--text2); line-height:1.6; margin:var(--space-4) 0 12px; }
        .ph-hero-stats { display:flex; flex-wrap:wrap; gap:var(--space-16); margin-bottom:var(--space-10); }
        .ph-hero-stat-val { font-size:var(--font-size-17); font-weight:700; color:var(--text1); }
        .ph-hero-stat-val.ph-warn { color:var(--danger); }
        .ph-hero-stat-label { font-size:var(--fs-caption); color:var(--text3); }
        .ph-hero-next { font-size:var(--font-size-12); background:var(--bg2); border-radius:var(--radius-sm); padding:var(--space-8) 10px; margin-top:var(--space-4); }
        .ph-hero-celebrate { background:linear-gradient(135deg,rgba(184,134,11,0.16),rgba(184,134,11,0.04)); border-color:rgba(184,134,11,0.35); }
        .ph-hero-celebrate .ph-hero-name { color:var(--gold); }
        .ph-hero-prompt { background:linear-gradient(135deg,rgba(184,134,11,0.12),rgba(184,134,11,0.03)); border-color:rgba(184,134,11,0.3); }
        /* milestone Timeline done/pending modifiers on the shared
           .ih-timeline-item dot/line (default is always "accent/active" —
           these override it per-milestone). */
        .ih-timeline-item.pt-pending::before { background:var(--border); }
        .ih-timeline-item.pt-pending::after { background:var(--border); opacity:0.4; }
        .ih-timeline-item.pt-pending { opacity:0.55; }
        /* Project Wizard step indicator (Project Creation UX Redesign) —
           no prior multi-step modal pattern existed in the app to reuse. */
        .pw-steps { display:flex; gap:var(--space-6); margin-bottom:var(--space-14); }
        .pw-step-dot { flex:1; height:4px; border-radius:var(--radius-full); background:var(--border); }
        .pw-step-dot.active { background:var(--accent); }
        .pw-step-dot.done { background:rgba(var(--accent-rgb),0.5); }
        /* TASK ITEMS */
        .task-item { display:flex; align-items:center; gap:var(--space-10); padding:var(--space-10) 12px; background:var(--bg2); border-radius:var(--radius-sm); margin-bottom:var(--space-5); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.12); box-shadow:var(--shadow-card); transition:all var(--dur-fast) var(--ease-standard); }
        body.dark .task-item { background:var(--bg2); border-color:rgba(var(--accent-rgb),0.2); }
        .task-item.done { opacity:0.45; }
        .task-item.done .task-label { text-decoration:line-through; }
        .task-item.pillar-accent { border-right:var(--border-medium) solid var(--group-color); display:flex; align-items:center; }
        .task-item.pillar-accent:hover, body.dark .task-item.pillar-accent { border-right-color:var(--group-color); }
        /* Same body.dark specificity trap as .task-item.pillar-accent above —
           border-right:var(--color-bills) was inline before this cleanup, so
           it always beat body.dark .task-item's border-color reset. */
        .task-item.cal-day-bill-item { border-right:var(--border-medium) solid var(--color-bills); }
        body.dark .task-item.cal-day-bill-item { border-right-color:var(--color-bills); }
        .filter-btn.dep-task-btn { font-size:var(--fs-label); padding:var(--space-3) 8px; text-align:right; width:100%; display:flex; justify-content:space-between; align-items:center; border-right:var(--border-medium) solid var(--task-color); }
        .filter-btn.dep-task-btn:hover, body.dark .filter-btn.dep-task-btn { border-right-color:var(--task-color); }
        .dash-stat-row.eis-task-row { border-right:var(--border-thin) solid var(--task-color); padding-right:var(--space-8); cursor:grab; }
        body.dark .dash-stat-row.eis-task-row { border-right-color:var(--task-color); }
        .cal-day-group-header { display:flex; align-items:center; gap:var(--space-6); padding:var(--space-5) 8px; background:linear-gradient(135deg,color-mix(in srgb, var(--group-color) 13%, transparent),color-mix(in srgb, var(--group-color) 3%, transparent)); border-right:var(--border-medium) solid var(--group-color); border-radius:var(--radius-sm); margin-top:var(--space-8); margin-bottom:var(--space-3); }
        .cal-day-group-pillar { font-size:var(--font-size-12); font-weight:600; color:var(--group-color); }
        .cal-day-group-track { font-size:var(--fs-label); color:color-mix(in srgb, var(--group-color) 67%, transparent); }
        .hier-group-header { display:flex; align-items:center; gap:var(--space-8); padding:var(--space-7) 10px; background:linear-gradient(135deg,color-mix(in srgb, var(--group-color) 13%, transparent),color-mix(in srgb, var(--group-color) 3%, transparent)); border-right:var(--border-thick) solid var(--group-color); border-radius:var(--radius-sm); margin-bottom:var(--space-8); }
        .hier-group-pillar { font-size:var(--fs-body); font-weight:700; color:var(--group-color); }
        .hier-group-track { font-size:var(--font-size-12); color:var(--group-color); padding-right:var(--space-10); }
        /* The track's own color as a small dot before the label (the label text stays as it was: pillar color) */
        .hier-group-track::before, .cal-day-group-track::before { content:''; display:inline-block; width:8px; height:8px; border-radius:var(--radius-full); background:var(--track-color, var(--group-color)); margin-inline-end:var(--space-6); vertical-align:middle; }
        .hier-crumb-pillar { cursor:pointer; color:var(--crumb-color); font-weight:600; }
        .pillar-tag { font-size:var(--fs-label); color:var(--pillar-color, var(--accent)); }
        .pillar-dot { width:8px; height:8px; border-radius:50%; background:var(--pillar-color, var(--accent)); display:inline-block; flex-shrink:0; }
        /* Unified status-dot icon (mobile-FAB-overlap + color-dot batch,
           2026-08-28) — replaces 3 raw colored-dot emoji call sites
           (_pmgrProjectHealth, renderInsights() ranking markers,
           Ambitions review cards) with a real icon, consistent with
           .pillar-dot's own shape/size just above (8px filled circle) —
           parameterized by semantic status color via statusDot() below
           instead of a per-pillar bridge color. -status-neutral is a
           hollow ring, not a 5th solid color — ⚪ already reads as
           "empty/outline" in most emoji fonts, and staying shape-
           distinct (not just color-distinct) from -status-inactive
           keeps the two apart without relying on color alone. */
        .status-dot { width:8px; height:8px; border-radius:50%; display:inline-block; flex-shrink:0; vertical-align:middle; }
        .status-dot-success { background:var(--success); }
        .status-dot-warning { background:var(--warning); }
        .status-dot-danger { background:var(--danger); }
        .status-dot-inactive { background:var(--text3); }
        .status-dot-neutral { background:transparent; border:var(--border-thin) solid var(--text3); }
        .streak-track-dot { color:var(--pillar-color, var(--accent)); margin-left:var(--space-6); }
        /* Unified checkbox geometry (icon-container sizing convergence,
           2026-08-29) — .task-check (Calendar/Backlog/Project Detail/
           Projects Manager/Tag Manager) and .tl-task-chip .tl-check
           (Timeline) share one drawn size across all 9 sites. Event wiring
           stays separate (Timeline's tlToggle() vs. toggleTask()/bulk-select
           handlers elsewhere) — only the visual/geometry layer is shared.
           RB-12 (Sprint 14 audit, 2026-08-31) re-adds a 44x44 invisible
           ::before hit-area to .tl-task-chip .tl-check ONLY — .task-check's
           other 8 sites are untouched, and the drawn box everywhere (incl.
           Timeline) stays 24px, so the 2026-08-30 visual-consistency
           decision (`docs/07_DECISIONS_ACTIVE.md` → "Icon-Container Sizing
           Convergence") holds; only the invisible tap area is restored, per
           user decision on this exact re-flagged conflict. */
        .task-check, .tl-task-chip .tl-check { width:var(--icon-box-24); height:var(--icon-box-24); border-radius:var(--radius-sm); border:1.5px solid rgba(var(--accent-rgb),0.22); background:none; cursor:pointer; flex-shrink:0; display:flex; align-items:center; justify-content:center; font-size:var(--font-size-12); transition:all var(--dur-fast) var(--ease-standard); color:transparent; }
        .task-check.checked, .tl-task-chip .tl-check.checked { background:var(--accent); border-color:var(--accent); color:var(--text-on-accent); }
        .tl-task-chip .tl-check { position:relative; z-index:2; }
        .tl-task-chip .tl-check::before { content:''; position:absolute; top:calc(-1 * var(--tl-hit-v-inset, 11px)); right:-11px; bottom:calc(-1 * var(--tl-hit-v-inset, 11px)); left:-11px; }
        .task-info { flex:1; min-width:0; }
        .task-label { font-size:var(--fs-body); color:var(--text1); }
        body.dark .task-label { color:#e8f4f4; }
        /* 44px tap target (Tap Targets Under 44px sprint, Batch 3) — was
           26x26. Same min-width/min-height + flex-centring idiom as
           .task-menu-btn. The ~41 real usage sites were fully enumerated
           this batch (prior batches left this deliberately scoped/untouched
           pending that enumeration — see docs/07_DECISIONS_ACTIVE.md): every
           site is either beside a flex:1/min-width:0 sibling that absorbs
           the growth, inside a flex-wrap:wrap row, inside a horizontally-
           scrollable table, or was live-measured with the real 44x44 rule
           injected and found collision-free. Zero collisions found anywhere.
           The former `.knowledge-md-toolbar .task-icon-btn` scoped override
           is retired here — the base rule now does what it did. */
        .task-icon-btn { min-width:44px; min-height:44px; border-radius:var(--radius-sm); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.12); background:var(--bg); color:var(--text2); cursor:pointer; display:flex; align-items:center; justify-content:center; font-size:var(--fs-body); line-height:1; transition:all var(--dur-fast) var(--ease-standard); font-family:inherit; flex-shrink:0; }
        body.dark .task-icon-btn { background:var(--bg); color:var(--text2); border-color:rgba(var(--accent-rgb),0.2); }
        .task-icon-btn:hover { border-color:rgba(var(--accent-rgb),0.22); color:var(--text1); background:var(--bg2); }
        .task-icon-btn.del:hover { background:#fdecea; border-color:rgba(192,57,43,0.3); color:var(--danger); }
        /* Companion rule cancelling the global [data-icon] 4px trailing
           margin — same dependency already documented for .modal-close and
           .refl-star-btn (line ~4293's own comment). Selector is [data-icon]
           itself, NOT .icon: some .task-icon-btn markup (tsSelectModeBtn,
           the 3 tsBulk* buttons) never puts class="icon" on the span that
           carries data-icon, only on the SVG hydrateIcons() injects into it
           — a .icon-based override would silently match the wrong element
           there, exactly the bug found in .refl-star-btn's own override
           this same session (see docs/07_DECISIONS_ACTIVE.md). [data-icon]
           matches the actual margin-bearing element regardless of whether
           class="icon" happens to be present too. */
        .task-icon-btn [data-icon] { margin-inline-end:0; }
        /* زرار أكشن بنص + أيقونة على الكروت (موازنات/أهداف/فواتير) — كان النص
           بيتحشر جوه .task-icon-btn المربعة 26px فيتداخل فوق الأيقونة. */
        .card-action-btn { display:inline-flex; align-items:center; gap:var(--space-5); height:26px; padding:0 10px; border-radius:var(--radius-sm); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.12); background:var(--bg); color:var(--text2); cursor:pointer; font-size:var(--font-size-12); font-weight:600; line-height:1; transition:all var(--dur-fast) var(--ease-standard); font-family:inherit; flex-shrink:0; white-space:nowrap; }
        body.dark .card-action-btn { background:var(--bg); color:var(--text2); border-color:rgba(var(--accent-rgb),0.2); }
        .card-action-btn:hover { border-color:rgba(var(--accent-rgb),0.22); background:var(--bg2); }
        body.dark .card-action-btn:hover { background:var(--bg2); }
        /* was inline style="color:var(--success)" at its one call site
           (Button System sprint, Batch 4) — same .success modifier idiom
           as .btn-inline.success. */
        .card-action-btn.success { color:var(--success); }
        /* TIMELINE */
        /* The transparent border-top is a permanent placeholder, not
           decoration (final-review Important #3, 2026-09-04) — .tl-drop-target
           is toggled onto EVERY row the instant a drag starts, so declaring
           the border there as a shorthand grew every row by 1px at once
           (N px of cumulative downward shift on an N-item day, moving the
           intended drop row out from under the cursor mid-gesture).
           Reserving the 1px here makes that modifier color-only again,
           the way the deleted .tl-slot.tl-drop-target worked. */
        /* display:flow-root is load-bearing, not cosmetic (2026-09-04 fix
           round to the 4th refinement pass). The pass below moved the
           8px/3px row-spacing margin OFF the in-flow chip and ONTO
           .tl-item-row, which is this wrapper's LAST in-flow child. This
           wrapper had nothing establishing a block-formatting context — the
           border-top above blocks the FIRST child's top margin from
           collapsing through, and does nothing at all for the last child's
           bottom margin — so that 8px collapsed straight OUT of
           .tl-item-wrap instead of staying inside it. Four things broke at
           once, all of them silently:
             1. the drop targets (ondragover/ondrop are on THIS element) got
                an 8px dead band between consecutive wraps belonging to no
                target — the highlight dropped out and a release there was
                lost;
             2. .tl-now-line's style="top:N%" resolves against this box, and
                the box was 8px short, so the line drifted;
             3. the escaped margin became adjoining to .tl-period-divider's
                own margin-block-start and collapsed WITH it (16px) instead
                of adding to it, losing 8px of the intended 24px lead-in
                before every divider;
             4. the last wrap's margin escaped .timeline itself, which has no
                bottom padding/border either, shortening its box by 8px.
           flow-root (not overflow:hidden — that would clip the badge and
           hour column, which live in .timeline's gutter OUTSIDE this box)
           establishes the BFC that keeps the margin in. Wrap height is
           chipH + 8 again, byte-identical to before the margin move. */
        .tl-item-wrap { position:relative; display:flow-root; border-top:var(--border-hairline) solid transparent; }
        .tl-show-more-row { display:flex; justify-content:center; padding:var(--space-3) 0; }
        .tl-show-more { min-height:44px; padding:0 var(--space-4); }
        /* Icon-on-spine redesign (2026-09-04) — .tl-item-row is the new
           per-item row emitted by _renderTimelineChipHTML(): the hour column
           and the kind badge are SIBLINGS of .tl-task-chip now, not children
           of it, so the badge can sit ON the connecting spine (outside the
           card) the way the Structured reference does, instead of being one
           more flex child inside the card's own border.
           It is emitted by the chip renderer itself rather than added to
           .tl-item-wrap, because .tl-item-wrap only exists on the main
           Timeline — renderAnytimeToday()/renderUnscheduledRecurring() append
           the same chip HTML straight into their own section, and an
           absolutely-positioned badge with no row of its own there would
           resolve against an unrelated ancestor. One wrapper, three consumers,
           same as the chip itself.
           position:relative makes it the containing block for the two
           absolutely-positioned children below; flex handles the fallback
           (non-Timeline) case where the badge is still in normal flow. */
        /* align-items:center, not flex-start (2026-09-04, 4th refinement pass)
           — on the Timeline both leading elements are absolutely positioned so
           this changes nothing there, but on the other two consumers the badge
           is a real flex item and was sitting at the top of the card. Centering
           it makes all three consumers agree with the Timeline's own new
           centering below, and with .tl-task-chip's long-standing
           align-items:center for the checkbox. */
        .tl-item-row { display:flex; align-items:center; gap:var(--tl-badge-gap); position:relative; }
        .tl-item-row > .tl-swipe-wrap, .tl-item-row > .tl-task-chip { flex:1 1 auto; min-width:0; }
        /* Row-spacing margin moved OFF the in-flow child and onto the row
           (2026-09-04, 4th refinement pass) — required for the vertical
           centering below to be exact rather than approximately right.
           .tl-item-row is a flex container, so its content height is the flex
           line's cross size, which is the child's MARGIN box, not its border
           box. With the gap still on the child, the row was 8px (plain chip) or
           3px (swipeable, .tl-swipe-wrap's own margin) taller than the card it
           contains, and anything centered against the row therefore sat 4px /
           1.5px BELOW the card's true center — small, but this exact chip has
           had its geometry silently wrong twice, so it is fixed at the source
           instead of compensated for at two separate call sites.
           Moving the identical value from child to parent shrinks the
           containing block the two absolute children resolve against to
           exactly the card, which is the point. It does NOT on its own keep
           the row's outer contribution the same: as a margin rather than
           part of the row's content height it is collapsible, and
           .tl-item-wrap had no block-formatting context, so it escaped the
           wrapper entirely (drop-target dead band, drifted now-line,
           swallowed period-divider spacing — the full account is in
           .tl-item-wrap's own comment above). What makes the outer height,
           every segment height and every drop-target box byte-identical to
           before is that margin move TOGETHER WITH .tl-item-wrap's
           display:flow-root; neither half is sufficient alone.
           A bottom margin (unlike the inline padding/margin the note below
           warns about) cannot move the row's padding-box origin, so the
           badge's x/y anchor is untouched. The two values stay distinct — the swipeable
           rows really are tighter — via the class the renderer already has the
           information to emit.
           Scoped to .tl-item-row, NOT to .tl-item-wrap .tl-item-row: measured
           live, the two spine-less consumers had the identical defect in their
           own terms — align-items:center centered their in-flow badge on the
           chip's margin box, leaving it 4px (plain) / 1.5px (swipeable) below
           the card's real center. Same cause, same fix, so the rule is written
           once for all three consumers instead of leaving two of them
           almost-right. The child selector keeps it off any .tl-task-chip that
           is ever rendered outside a row. */
        .tl-item-row { margin-bottom:var(--space-8); }
        .tl-item-row.tl-row-swipeable { margin-bottom:var(--space-3); }
        .tl-item-row.tl-row-swipeable.tl-row-gap8 { margin-bottom:var(--space-8); }
        .tl-item-row > .tl-task-chip,
        .tl-item-row > .tl-swipe-wrap { margin-bottom:0; }
        /* On the Timeline only, both leading elements leave normal flow (they
           live in .timeline's own gutter, outside the row's content box) and
           the card is pushed clear of the badge's inner half. This INLINE
           inset goes on the in-flow child, never on .tl-item-row itself —
           inline padding/margin on the row would move its padding box and
           drag the absolutely positioned badge along with it, which is
           exactly the class of containing-block mistake this redesign is
           undoing. (The row-spacing margin-BOTTOM above is the deliberate
           exception and is safe for the opposite reason: a bottom margin
           cannot move a box's own origin. It needs .tl-item-wrap's
           display:flow-root to stay contained — see there.) */
        .tl-item-wrap > .tl-item-row > .tl-swipe-wrap,
        .tl-item-wrap > .tl-item-row > .tl-task-chip { margin-inline-start:var(--tl-card-inset); }
        /* Every chip-level background below is deliberately the background-COLOR
           longhand, never the `background` shorthand: the shorthand also resets
           background-image to none, which silently wiped the .tl-chip-nizol
           stripe (a background-image layer, see below) from any chip that also
           carried a type/bill/tint/overdue/conflict class — invisibly, and at
           higher specificity in dark mode. Keep these as longhands. */
        .tl-task-chip { display:flex; align-items:center; gap:var(--space-6); padding:var(--space-5) 8px; border-radius:var(--radius-xl); margin-bottom:var(--space-8); background-color:var(--bg2); border:var(--border-hairline) solid rgba(var(--accent-rgb),var(--tl-border-a,0.12)); box-shadow:var(--tl-bar-inset,0 0 transparent),var(--tl-shadow,var(--shadow-card)); cursor:pointer; transition:all var(--dur-fast) var(--ease-standard); position:relative; overflow:hidden;
            /* Visual weight tiers (see .tl-tier-N below): the side bar color is --tl-bar (set per type), faded/darkened by tier into --tl-bar-final. */
            --tl-bar-contrast:#000; --tl-bar-final:color-mix(in srgb, color-mix(in srgb, var(--tl-bar,var(--border)) var(--tl-bar-keep,100%), var(--tl-bar-contrast)) var(--tl-bar-strength,100%), transparent); }
        body.dark .tl-task-chip { background-color:var(--bg2); border-color:rgba(var(--accent-rgb),var(--tl-border-a-d,0.2)); --tl-bar-contrast:#fff; }
        .tl-task-chip.done { opacity:0.55; }
        /* ...and the row's own leading elements dim WITH it (2026-09-04 fix
           round). The hour column and the kind badge used to be children of
           .tl-task-chip, so the rule directly above reached them; as siblings
           it no longer does, and a completed item's solid-fill badge stayed at
           100% next to a 55% card. _renderTimelineChipHTML mirrors the chip's
           done/tl-archived classes onto .tl-item-row for exactly these rules.
           Same numbers as the chip's, deliberately — the row must fade as one
           object, not in two tones. */
        .tl-item-row.done > .tl-kind-badge,
        .tl-item-row.done > .tl-item-hour-col { opacity:0.55; }
        /* Name/details column top-aligned (2026-09-04 icon-on-spine redesign)
           — the chip keeps align-items:center for every OTHER child (the
           checkbox, the effort dot, the menu button; the checkbox's 44x44
           ::before hit-area inset in _renderTimelineChipHTML is derived from
           that centering, so it is deliberately left alone). Only the text
           column moves to the top, because a duration-height card centered its
           title in the middle of a 3-hour block — which is what made the hour
           label impossible to keep "level with the task's own text" at both
           chip extremes. With this, the name's first line is at a constant
           offset from the card's top, and the hour column and the kind badge
           can both anchor to that same constant. */
        .tl-task-chip > .u-flex-1 { align-self:flex-start; }
        /* .tl-check's own box/checked-state geometry now lives at the
           shared .task-check rule above (icon-container sizing
           convergence, 2026-08-29) — see that rule's comment. */
        /* Kind badge — Premium UI Sprint (Timeline Phase 2, 2026-07-31).
           Small leading icon-circle, same colored-icon-on-tint language as
           the Hero cards' icon badges, scaled down for a compact chip row. */
        /* SF3-6 fix (Sprint 14 Third Re-Audit remediation, 2026-09-02) —
           this badge has no click handler of its own (purely a kind
           indicator icon), but real clicks on its overlap with the
           adjacent .tl-check::before hit-area extension (see that rule's
           own -11px right-extension above) were resolving to this badge
           instead — either a dead end or an unintended bubble to the
           chip's own onclick. pointer-events:none lets every such click
           pass straight through to whatever is actually meant to receive
           it (the checkbox's extended hit-area), regardless of the exact
           stacking-order cause. */
        /* Spine alignment (Task 6, 2026-09-04) — real-click measurement
           found ~13px of unintended whitespace between the chip's leading
           element and .timeline::before's spine line (the chip's own 8px
           padding-right plus the spine's small gutter inset), reading as
           a gap rather than that element sitting right against the
           connecting line. Pulled flush with the existing --space-8
           token rather than shrinking the chip's own padding (which
           would also move the checkbox/name/time columns).
           The rule that does this now lives on .tl-item-hour-col, not
           here — the 2026-09-04 chip refinement made the hour column the
           chip's leading element, ahead of this badge; see that rule
           below for the (unchanged) reasoning and .tl-item-wrap scoping. */
        /* Chip Visual Refinement (2026-09-04) — 26px→36px with a SOLID
           saturated fill and a light glyph on top (was a 14%-alpha tint of
           the same hue as the icon, subtle to the point of being easy to
           miss on a busy day). Icon scaled 14px→18px to keep the same
           glyph-to-circle ratio. The color still comes from the kind /
           habit-frequency tier below — only the fill/glyph roles swapped,
           no new color variants. */
        /* Circle-to-capsule (2026-09-15) — height now reads --tl-badge-height
           (falls back to --tl-badge-size, i.e. a circle, whenever a caller
           doesn't set it), and border-radius moved from --radius-full (50%)
           to --radius-pill (999px): on a square box (height===width, the
           .tl-badge-capsule-less case) 999px still clips to a full circle
           exactly like 50% did, but once height>width (.tl-badge-capsule)
           50% would draw an ELLIPSE — a fixed radius far larger than either
           dimension is what keeps both ends true semicircles at any aspect
           ratio, i.e. an actual stadium/pill shape, not an ellipse. */
        .tl-kind-badge { width:var(--tl-badge-size); height:var(--tl-badge-height, var(--tl-badge-size)); border-radius:var(--radius-pill); display:flex; align-items:center; justify-content:center; flex-shrink:0; z-index:1; pointer-events:none; }
        /* Badge ON the spine (2026-09-04 icon-on-spine redesign) — the whole
           point of this pass. Scoped to .tl-item-wrap, i.e. the main Timeline,
           because that is the only one of the three chip consumers that HAS a
           spine; in the other two the badge stays an ordinary in-flow flex
           child of .tl-item-row exactly as before.
           The x formula is the same one .tl-period-divider::before uses (that
           dot is the ground-truth "correctly on the spine" element and this
           was cross-checked against it by getBoundingClientRect): walk from
           this containing block's own inline-start edge out to the spine
           (--tl-spine-x minus --tl-edge-pad, = 0 now that the spine sits
           exactly at .timeline's content edge), then back by half the badge so
           the badge is CENTERED on that x rather than starting at it.
           The x formula stays keyed to --tl-badge-size, the per-row VARYING
           value, and that is the point: half of whatever this row's badge is
           lands on either side of the spine, so the circle is centered on the
           line at 28px exactly as it is at 44px. Nothing else in the gutter may
           key off it (see --tl-badge-size-max in :root).
           top: y was a fixed offset from the card's top until 2026-09-04's 4th
           refinement pass, chosen so the badge sat on the task/habit NAME's own
           line at any card height. Corrected to a true centering on the user's
           instruction: on a 2-hour chip that fixed offset left the badge pinned
           near the top of a 128px card while the card's own checkbox — centered
           by .tl-task-chip's align-items:center — sat 46px lower, so the row
           read as two different alignments at once. 50% + translateY(-50%)
           resolves against .tl-item-row, whose height is now exactly the card's
           (see the margin move above), so this is the card's real center, not
           the card's center plus a stray margin. */
        .tl-item-wrap .tl-kind-badge { position:absolute; z-index:3;
            inset-inline-start:calc(var(--tl-spine-x) - var(--tl-edge-pad) - var(--tl-badge-size) / 2);
            top:50%; transform:translateY(-50%); }
        /* svg.icon, not bare svg (2026-09-04) — icon() stamps class="icon"
           and the shared `svg.icon { width:1em; height:1em }` rule has the
           SAME (0,1,1) specificity as a bare `.tl-kind-badge svg`, so
           whichever comes later in the sheet wins. svg.icon is later, which
           means the pre-existing 14px here had never actually applied
           either — measured live, the glyph was rendering at the inherited
           1em (16px) the whole time. Two classes puts this rule
           unconditionally above it, independent of source order. */
        /* Half the circle's diameter, not a px literal (2026-09-04, 4th
           refinement pass) — 18/36 is the glyph-to-circle ratio the previous
           pass settled on by eye, and now that the diameter varies per row the
           glyph has to hold that ratio or a 44px badge would read as a small
           icon lost in a big disc. 14px at the 28px floor, 22px at the 44px
           ceiling. */
        .tl-kind-badge svg.icon { width:calc(var(--tl-badge-size) * 0.5); height:calc(var(--tl-badge-size) * 0.5); }
        /* Per-item start time (Timeline Phase 3, 2026-07-31; promoted out of
           .tl-task-name into its own leading column 2026-09-04) — it used to
           be an inline <span> prefix INSIDE the name, so the hour and the
           task title ran together as one text run. It is now the chip's own
           first flex child, ahead of the kind-badge, giving the hours a
           single column of their own down the timeline's spine edge (the
           Structured-app reference's arrangement).
           This is NOT the former per-hour-bucket .tl-hour-label (removed in
           the proportional-axis redesign) — that labelled an hour GROUP;
           this labels one ITEM and lives inside its chip.
           The -space-8 leading nudge moved here from .tl-kind-badge with the
           reorder — it exists to pull the chip's leading column flush with
           .timeline::before's spine, and after the reorder the hour column,
           not the badge, is that leading column. Same .tl-item-wrap scoping
           and same reason (final-review Important #2, 2026-09-04): only the
           main Timeline's rows have the spine this nudge was measured
           against; the other two consumers (renderUnscheduledRecurring,
           renderAnytimeToday) render untimed items and would just lose an
           inset for nothing.
           align-self:center (was flex-start + a small padding-block-start,
           changed 2026-09-04 in the same pass and for the same reason as the
           badge's top above): the hour is now centered on the card's own
           height, not optically seated on the name's first line. This rule is
           the non-Timeline consumers' copy of that decision — there the column
           is :empty and collapsed, so it is written for consistency with the
           .tl-item-wrap override below rather than for a visible effect.
           :empty collapses the column on untimed items — all three consumers
           are homogeneous (the Timeline renders timed items, the other two
           render only untimed ones), so a render never mixes a populated and
           a collapsed column in one list. */
        /* Width is 4em, NOT a px literal, and white-space:nowrap is load-bearing
           — both fix a measured clipping defect (2026-09-04 fix round). The
           original 34px was sized against "12:45م" but the real widest string
           fmtHour() produces is a two-digit hour + 4 glyphs ("10:15ص"), which
           needs 43px at --fs-label's 11px: 9px of overflow that .tl-task-chip's
           own overflow:hidden was silently shaving off the leading digit. Under
           body.font-lg (--fs-label = 11px * 1.15) EVERY string overflowed, the
           widest by 15px, painting past the chip edge and into the badge. em
           resolves against this element's own font-size (set on this same rule),
           so the column now scales 1:1 with the font-size accessibility setting
           instead of staying fixed while its contents grow. Measured fit at 375px:
           44px box / 43px widest text at normal, 50.6px / 49px at font-lg. */
        .tl-item-hour-col { flex-shrink:0; width:4em; font-size:var(--fs-label); font-weight:700; color:var(--text3); line-height:1.2; align-self:center; text-align:center; white-space:nowrap; }
        .tl-item-hour-col:empty { display:none; }
        /* Hour column in the gutter, OUTSIDE the spine (2026-09-04) — it used
           to be the chip's first flex child with a -8px nudge, which put it
           straddling the spine; the badge now owns that x, so the hour moves
           one step further out and the reading order becomes the reference's
           [hour] [icon on the line] [card].
           Anchored by inset-inline-END, not inline-start: `100%` of an
           absolutely positioned box's containing block puts its trailing edge
           at the row's own inline-start edge, and the extra
           (badge/2 + 2px) pushes it just clear of the badge's outer edge. The
           box then grows OUTWARD from there, so a wider string (font-lg makes
           4em 50.6px) eats into the gutter's slack instead of sliding into the
           badge.
           --tl-badge-size-MAX, not --tl-badge-size (2026-09-04, 4th refinement
           pass): the badge diameter now varies per row with the item's
           duration, and clearing "this row's badge" would slide the hour label
           left and right down the column with it. Clearing the LARGEST possible
           badge keeps the hours in one straight column — which is the whole
           reason the column exists — and guarantees no row can ever have its
           badge grow into the label. Measured fit at font-lg: 24 + 50.6 = 74.6
           of the 78px gutter.
           top matches the badge's rationale exactly — a true centering on the
           card's own height (the fixed name-line offset it replaced, and why,
           are documented at the badge rule above). */
        .tl-item-wrap .tl-item-hour-col { position:absolute;
            inset-inline-end:calc(100% + var(--tl-badge-size-max) / 2 + 2px);
            top:50%; transform:translateY(-50%); }
        .tl-kind-badge.tl-kind-task { background:var(--accent); color:var(--text-on-accent); }
        /* Habit Frequency Icon Distinction (2026-08-29) — replaces the
           single .tl-kind-habit rule (was: every habit, any frequency,
           identical gold badge) with one rule per frequency tier. Same
           'repeat' icon shape at every tier by default (JS-side,
           _renderTimelineChipHTML — a name-keyword match can now substitute a
           more specific glyph, see _tlInferIconFromName) — only this badge
           fill color varies per tier. (.tl-kind-prayer previously
           sat here as a separate but identically-colored rule — removed
           2026-08-29 along with the rest of the dead item.type:'religious'
           machinery; see archive/decisions-history/10_CHANGELOG_LIVE_PRE_RESTRUCTURE.md.) */
        .tl-kind-badge.tl-kind-habit-daily { background:var(--gold); color:var(--text-on-accent); }
        .tl-kind-badge.tl-kind-habit-weekly { background:var(--success); color:var(--text-on-accent); }
        .tl-kind-badge.tl-kind-habit-monthly { background:var(--color-freq-monthly); color:var(--text-on-accent); }
        .tl-kind-badge.tl-kind-habit-yearly { background:var(--color-freq-yearly); color:var(--text-on-accent); }
        .tl-kind-badge.tl-kind-bill { background:var(--color-bills); color:var(--text-on-accent); }
        /* Activity-category override (2026-09-04) — declared AFTER the five
           .tl-kind-* rules on purpose. Both tiers are (0,2,0) specificity, so
           source order alone decides, and this is the tier that must win: when
           the name told us what the item actually IS, that beats what kind of
           record it happens to be stored as. An item with no keyword match
           never gets one of these classes at all and keeps its tier color
           untouched — the fallback is structural, not a color computation.
           Token rationale and the contrast measurements are at the
           --color-act-* declarations in :root. */
        .tl-kind-badge.tl-cat-water    { background:var(--color-act-water); color:var(--text-on-accent); }
        .tl-kind-badge.tl-cat-worship  { background:var(--color-act-worship); color:var(--text-on-accent); }
        .tl-kind-badge.tl-cat-exercise { background:var(--color-act-exercise); color:var(--text-on-accent); }
        .tl-kind-badge.tl-cat-care     { background:var(--color-act-care); color:var(--text-on-accent); }
        .tl-task-chip.bill-chip { --tl-bar:var(--color-bills); border-right:var(--border-medium) solid var(--tl-bar-final); background-color:rgba(142,68,173,0.05); }
        body.dark .tl-task-chip.bill-chip { background-color:rgba(142,68,173,0.1); border-right-color:var(--tl-bar-final); }
        /* Timeline Visual Differentiation — the 4-group marker system (archive/44: habit/recurring=--gold,
           bills=--color-bills, project=--accent, one-off=neutral) is now only the FALLBACK side-bar color
           (--tl-bar) for chips with no hue. A chip with a pillar/track/subtrack gets that hue instead (see
           .has-pillar-tint { --tl-bar } below); bills keep --color-bills. The type itself is shown by the
           kind badge on the spine. */
        .tl-task-chip.tl-type-habit  { --tl-bar:var(--gold); border-right:var(--border-medium) solid var(--tl-bar-final); background-color:rgba(184,134,11,0.05); }
        .tl-task-chip.tl-type-habit::before  { content:''; position:absolute; inset:0; border-radius:var(--radius-xl); background:repeating-linear-gradient(135deg,transparent,transparent 6px,rgba(184,134,11,0.04) 6px,rgba(184,134,11,0.04) 7px); pointer-events:none; }
        .tl-task-chip.tl-type-recurring { --tl-bar:var(--gold); border-right:var(--border-medium) solid var(--tl-bar-final); background-color:rgba(184,134,11,0.05); }
        .tl-task-chip.tl-type-backlog   { --tl-bar:color-mix(in srgb, var(--text3) 55%, transparent); border-right:var(--border-medium) solid var(--tl-bar-final); border-right-style:dashed; }
        .tl-task-chip.tl-type-project   { --tl-bar:var(--accent); border-right:var(--border-medium) solid var(--tl-bar-final); background-color:rgba(var(--accent-rgb),0.05); }
        .tl-task-chip.tl-type-user      { --tl-bar:color-mix(in srgb, var(--text3) 55%, transparent); border-right:var(--border-medium) solid var(--tl-bar-final); }
        body.dark .tl-task-chip.tl-type-habit     { background-color:rgba(184,134,11,0.08); border-right-color:var(--tl-bar-final); }
        body.dark .tl-task-chip.tl-type-recurring { background-color:rgba(184,134,11,0.08); border-right-color:var(--tl-bar-final); }
        body.dark .tl-task-chip.tl-type-project   { background-color:rgba(var(--accent-rgb),0.08); border-right-color:var(--tl-bar-final); }
        body.dark .tl-task-chip.tl-type-backlog   { border-right-color:var(--tl-bar-final); }
        body.dark .tl-task-chip.tl-type-user      { border-right-color:var(--tl-bar-final); }
        /* Pillar tint (bridged from JS-computed rgba() — the dark/light split
           now lives in CSS instead of a JS isDark branch). Placed after every
           type/bill background rule above so it wins the same way the old
           inline style unconditionally did, at equal .tl-task-chip.X specificity. */
        .tl-task-chip.has-pillar-tint { background-color:color-mix(in srgb, var(--pillar-tint-color) var(--tl-tint-l,var(--tl-t2-l)), transparent); }
        body.dark .tl-task-chip.has-pillar-tint { background-color:color-mix(in srgb, var(--pillar-tint-color) var(--tl-tint-d,var(--tl-t2-d)), transparent); }
        /* Visual weight tiers (timeline hierarchy sprint) — by how rare the item is: 1 daily routine (calm),
           2 periodic (weekly, every 2-6 days: the pre-existing look, no overrides), 3 rare/unique (one-time,
           monthly+, bills). Weight only: they set variables the base chip rules read (tint strength, border
           alpha, shadow, side-bar fade/darken + a 2px inset stripe, title color). No size, padding, height or
           layout property is touched, and every state rule (done, conflict, overdue, next-up, dragging, hover)
           still sets its own property later in the file and wins. Hue is NOT set here: it comes from
           _tlHueColor(). */
        .tl-task-chip.tl-tier-1 { --tl-tint-l:var(--tl-t1-l); --tl-tint-d:var(--tl-t1-d); --tl-border-a:0.07; --tl-border-a-d:0.13; --tl-shadow:0 0 transparent; --tl-bar-strength:45%; --tl-title:color-mix(in srgb, var(--text1) 78%, var(--bg2)); }
        .tl-task-chip.tl-tier-3 { --tl-tint-l:var(--tl-t3-l); --tl-tint-d:var(--tl-t3-d); --tl-border-a:0.3; --tl-border-a-d:0.38; --tl-shadow:0 2px 8px rgba(var(--accent-rgb),0.22); --tl-bar-keep:80%; --tl-bar-inset:inset -2px 0 0 0 var(--tl-bar-final); --tl-title:color-mix(in srgb, var(--text1) 88%, var(--tl-bar-contrast)); }
        /* Timeline tint strength per tier (hue from _tlHueColor): light-theme / dark-theme share of the hue mixed into the chip. One place to retune. */
        /* Chosen by the owner (variant D, 2026-10-01): light 18/23/28%, dark 28/33/38% for tiers 1/2/3. */
        :root { --tl-t1-l:18%; --tl-t2-l:23%; --tl-t3-l:28%; --tl-t1-d:28%; --tl-t2-d:33%; --tl-t3-d:38%; }
        /* Side bar uses the same hue source as the tint (--pillar-tint-color, from _tlHueColor: subtrack, then track,
           then pillar). Declared after every .tl-type-* rule so it replaces their type colors (the gold/accent/neutral
           type encoding of the bar is retired; the kind badge on the spine still shows the type). Items with no hue
           (no pillar/track) and bills keep their own bar color. */
        .tl-task-chip.has-pillar-tint { --tl-bar:var(--pillar-tint-color); }
        .tl-task-chip.tl-archived { opacity:0.35; filter:grayscale(0.6); }
        /* Sibling counterpart of the rule above — see the .tl-item-row.done
           note next to .tl-task-chip.done for why this exists. */
        .tl-item-row.tl-archived > .tl-kind-badge,
        .tl-item-row.tl-archived > .tl-item-hour-col { opacity:0.35; filter:grayscale(0.6); }
        /* Expand/collapse (archive/44 Part B1) — reuses .morning-card's own
           max-height show/hide idiom, with the project's real duration/easing
           tokens instead of that precedent's hardcoded 0.38s ease. */
        .tl-chip-details { max-height:0; overflow:hidden; transition:max-height var(--dur-slow) var(--ease-standard); }
        .tl-task-chip.expanded .tl-chip-details { max-height:320px; overflow-y:auto; }
        /* Overdue tasks (Sprint 13 Phase 2) — reuses the existing isOverdue
           definition (fixed-time, not done, scheduled time passed by >15min)
           already established for Insights recommendations. Deliberately
           NOT a copy of .tl-bill-overdue: keeps the task's own type-color
           border intact, adds a subtle danger-tinted wash + bold danger
           time text instead of overriding the border/background outright. */
        .tl-task-chip.tl-overdue { background-color:rgba(var(--danger-rgb),0.06); }
        body.dark .tl-task-chip.tl-overdue { background-color:rgba(var(--danger-rgb),0.12); }
        .tl-task-track.tl-overdue-time { color:var(--danger); font-weight:600; }
        /* Chip Visual Refinement (2026-09-04) — --fs-body/normal →
           --fs-heading-sm/600 so the title reads as the card's primary text
           rather than sitting at the same weight as the metadata under it.
           Deliberately 600, not 700: .tl-next-up .tl-task-name below already
           uses 700 as its own "this is the next thing up" emphasis, and
           raising the base to 700 would have silently erased that. */
        .tl-task-name { font-size:var(--fs-heading-sm); font-weight:600; flex:1; color:var(--tl-title,var(--text1)); }
        /* time/duration line: 20% toward the title color so it keeps AA (4.5:1) on the stronger tier tints */
        .tl-task-track { font-size:var(--fs-label); color:color-mix(in srgb, var(--text3) 80%, var(--text1)); }
        /* FILTERS */
        .filter-btn { padding:var(--space-5) 12px; border-radius:20px; border:var(--border-hairline) solid rgba(var(--accent-rgb),0.22); background:var(--bg2); color:var(--text2); font-family:inherit; font-size:var(--fs-label); cursor:pointer; transition:all var(--dur-fast) var(--ease-standard); }
        body.dark .filter-btn { background:var(--bg2); color:var(--text2); border-color:rgba(var(--accent-rgb),0.35); }
        .filter-btn:hover { background:rgba(var(--accent-rgb),0.08); border-color:rgba(var(--accent-rgb),0.35); color:var(--accent); }
        body.dark .filter-btn:hover { background:rgba(var(--accent-rgb),0.15); border-color:rgba(var(--accent-rgb),0.5); color:var(--text2); }
        .filter-btn:active { transform:scale(0.95); }
        .filter-btn.active { background:var(--accent); border-color:var(--accent); color:var(--text-on-accent); }
        .filter-btn.active:hover { background:#0a5555; }
        /* Finance Modals — Visual Polish Pass (2026-07-30). Scoped to the
           5 Finance modal containers only. */
        /* 1. Active Selection Clarity — Budget Scope (.filter-btn) */
        #budgetModal .filter-btn.active { font-weight:700; padding:var(--space-6) 13px; box-shadow:0 1px 3px rgba(0,0,0,0.18); }
        /* 3. Section Dividers — quieter, more premium in Finance modals only */
        #finTxModal .modal-sep, #accountModal .modal-sep, #billModal .modal-sep,
        #budgetModal .modal-sep, #goalModal .modal-sep { height:1px; background:rgba(var(--accent-rgb),0.18); margin:var(--space-14) 0; }
        /* Gradient Pills — filter system (Timeline/Projects/Calendar/Backlog/
           Archive hierarchy filters + every modal Choice Pill group —
           accounts/pillars/priority/difficulty/duration/repeat/schedule/tags —
           all render through this one gradientPill()/choicePills() primitive).
           Premium UI Sprint, Chips Phase (2026-07-31) — the bold+padding+
           shadow selected-state treatment used to be scoped to just 2 grids
           (#goalModalProgressModeGrid, #habitFreqGrid, both since removed as
           now-redundant) — generalized here to every chip app-wide, plus a
           real hover state (previously only had :active) and token-based
           transitions. Same shared component, no new class, no new markup. */
        .gpill-wrap { display:inline-flex; flex-direction:column; align-items:center; gap:var(--space-3); flex-shrink:0; }
        .gpill { display:inline-flex; align-items:center; gap:var(--space-6); padding:var(--space-7) 14px 7px 10px; border-radius:var(--radius-pill); font-size:var(--font-size-12); font-weight:500; color:var(--text2); background:var(--bg3); cursor:pointer; border:none; font-family:inherit; white-space:nowrap; transition:filter var(--dur-fast) var(--ease-standard),transform var(--dur-fast) var(--ease-standard),box-shadow var(--dur-fast) var(--ease-standard),padding var(--dur-fast) var(--ease-standard),background var(--dur-fast) var(--ease-standard),color var(--dur-fast) var(--ease-standard); user-select:none; }
        .gpill.gpill-active { background:linear-gradient(135deg,var(--pill-start, color-mix(in srgb, var(--pill-color) 80%, transparent)),var(--pill-color)); color:var(--pill-fg, var(--text-on-accent)); }
        body:not(.dark) .gpill.gpill-active.gpill-neutral { background:var(--pill-color); } /* [T-301] the neutral pill (var(--accent)) is a flat fill in the light theme: white on its 80% gradient start read 3.99:1, on the solid accent it is 6.05:1 (the same fallback pillForeground uses for hex pills); dark, amoled and high contrast keep the gradient (6.2+) */
        body.palette-warm .gpill.gpill-active.gpill-neutral, body.palette-gold .gpill.gpill-active.gpill-neutral { background:var(--accent-dark); } /* [T-306] white on the flat --accent is below AA on these two palettes (warm #C85A00 4.27, gold #B8860B 3.25; dark themes 4.5 and 3.4); the neutral pill takes the palette's own --accent-dark instead, same white label, same flat fill as the T-301 light rule (warm 6.8, gold 5.3); every theme, classic/ocean/forest stay as they are (5.09+) */
        .gpill:hover { filter:brightness(1.1); }
        .gpill.gpill-active:hover { filter:none; } /* [T-301] an active pill's label color is chosen for AA on the undimmed fill (pillForeground); brightening it on hover read 4.26:1 for white on #1b7f4c. The dark themes already have this (body.dark .gpill.gpill-active below) */
        .gpill:active { transform:scale(0.94); }
        .gpill .gpill-count { background:rgba(var(--accent-rgb),0.15); color:var(--text2); border-radius:var(--radius-pill); padding:var(--space-1) 7px; font-size:var(--fs-caption); margin-right:var(--space-2); }
        .gpill.gpill-active .gpill-count { background:transparent; box-shadow:inset 0 0 0 1px currentColor; color:var(--pill-fg, var(--text-on-accent)); }
        .gpill-underline { background:var(--pill-color); width:22px; height:3px; border-radius:var(--radius-full); opacity:0; transition:opacity var(--dur-fast) var(--ease-standard),width var(--dur-fast) var(--ease-standard); }
        .gpill-underline.on { opacity:1; width:28px; }
        .gpill-wrap:has(.gpill-underline.on) .gpill { font-weight:700; padding:var(--space-7) 16px 7px 12px; box-shadow:0 2px 6px rgba(0,0,0,0.16); }
        .filter-row::-webkit-scrollbar { display:none; }
        body.dark .gpill { filter:brightness(0.85); }
        body.dark .gpill:hover { filter:brightness(0.98); }
        body.dark .gpill.gpill-active { filter:none; } /* the label color is chosen for AA on the undimmed fill (pillForeground) */
        /* Hierarchy Visual Separation — v66 (A18): فواصل جريدنت ملونة رقيقة بدل الخط العادي */
        .sub-filter-row {
            border-right:var(--border-medium) solid rgba(var(--accent-rgb),0.22); margin-right:var(--space-10); padding-right:var(--space-10);
            padding-top:var(--space-9); margin-top:var(--space-6); margin-bottom:var(--space-6);
            border-top:var(--border-thin) solid transparent;
            border-image: linear-gradient(90deg, transparent, rgba(var(--accent-rgb),0.45), rgba(var(--accent-rgb),0.15) 60%, transparent) 1;
        }
        .sub-filter-row.layer2 {
            border-right-color:rgba(var(--accent-rgb),0.14); margin-right:var(--space-22); padding-right:var(--space-10);
            border-image: linear-gradient(90deg, transparent, rgba(74,144,217,0.4), rgba(74,144,217,0.12) 60%, transparent) 1;
        }
        .sub-filter-row.layer3 {
            border-right-color:rgba(var(--accent-rgb),0.08); margin-right:var(--space-34); padding-right:var(--space-10);
            border-image: linear-gradient(90deg, transparent, rgba(22,160,133,0.4), rgba(22,160,133,0.12) 60%, transparent) 1;
        }
        .filter-row { display:flex; flex-wrap:wrap; gap:var(--space-5); margin-bottom:var(--space-12); align-items:flex-start; }
        .hier-sep { border-top:var(--border-thin) solid transparent; border-image: linear-gradient(90deg, transparent, rgba(var(--accent-rgb),0.35), transparent) 1; }
        /* تمييز بصري بين مستويات فلتر العمود/التراك/الصب تراك (سبيك
           2026-07-17) — label فوق كل مستوى، بيختفي تلقائيًا لو المستوى ده
           مقفول (الصف بعده فاضي، مفيش تراكات/صب تراكات للعمود المختار)
           بدل ما نحتاج نلمس JS في كل Call Site. */
        .hier-track-label, .hier-subtrack-label { display:block; }
        .hier-track-label:has(+ .filter-row:empty) { display:none; }
        .hier-subtrack-label:has(+ .filter-row:empty) { display:none; }
        /* First-run fixes (2026-10-05): a picker with nothing to pick (no pillars / no accounts yet) shows no bare label. */
        .modal-label:has(+ .filter-row:empty), .modal-label:has(+ input[type="hidden"] + .pill-group:empty) { display:none; }
        body.dark .sub-filter-row { border-image-source: linear-gradient(90deg, transparent, rgba(122,181,181,0.4), transparent); }
        body.dark .hier-sep { border-image-source: linear-gradient(90deg, transparent, rgba(122,181,181,0.35), transparent); }
        /* KEYBOARD-FIRST LIST NAVIGATION — Sprint 10 (Professional Workflow).
           Applied to .task-item/.backlog-item rows by _kbdNavSetFocus() when
           the user navigates the active tab's list with ArrowUp/ArrowDown. */
        .kbd-focused { outline:2px solid var(--accent); outline-offset:1px; }
        /* BACKLOG */
        .backlog-item { padding:var(--space-11) 13px; background:var(--bg2); border-radius:var(--radius-sm); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.12); margin-bottom:var(--space-6); box-shadow:var(--shadow-card); transition:box-shadow var(--dur-fast) var(--ease-standard),border-color var(--dur-fast) var(--ease-standard); }
        body.dark .backlog-item { background:var(--bg2); border-color:rgba(var(--accent-rgb),0.2); }
        .backlog-item-top { display:flex; align-items:flex-start; justify-content:space-between; gap:var(--space-8); }
        .backlog-item-title { font-size:var(--fs-body); flex:1; }
        .backlog-item-meta { display:flex; gap:var(--space-5); flex-wrap:wrap; margin-top:var(--space-6); align-items:center; }
        .backlog-item.project-accent { border-right:var(--border-medium) solid var(--project-color); }
        .backlog-item.project-accent:hover, body.dark .backlog-item.project-accent { border-right-color:var(--project-color); }
        /* Same body.dark .backlog-item specificity trap as .project-accent
           above -- border-color:var(--accent) was inline before this cleanup. */
        .backlog-item.fin-goal-suggest-card { flex-direction:column; align-items:stretch; gap:var(--space-6); border-color:var(--accent); margin-bottom:var(--space-8); }
        body.dark .backlog-item.fin-goal-suggest-card { border-color:var(--accent); }
        .backlog-item.am-finance-suggest-card { flex-direction:column; align-items:stretch; gap:var(--space-6); border-color:var(--warning); margin-bottom:var(--space-8); }
        body.dark .backlog-item.am-finance-suggest-card { border-color:var(--warning); }
        .backlog-item-hier-tag { font-size:var(--fs-label); color:var(--text2); }
        .backlog-status { padding:var(--space-2) 8px; border-radius:var(--radius-md); font-size:var(--fs-label); }
        .backlog-status.ready { background:#e6f4f4; color:var(--accent-dark); }
        .backlog-status.conditional { background:#fff0e6; color:var(--gold); }
        /* MORNING CARD */
        /* Expand/collapse (Sprint 8 Phase 2 Batch 4, 2026-08-28) — CSS Grid
           grid-template-rows:1fr/0fr instead of a fixed max-height. A
           max-height ceiling (previously 600px) clips whenever real
           content (mood/energy/sleep pickers, conditional time inputs)
           grows taller than the guessed cap, especially under font-lg;
           the grid track has no ceiling to guess. Padding/border live on
           the inner wrapper, not this element, so collapsing the grid row
           to 0fr also removes them with nothing left to show.
           grid-template-rows is deliberately NOT transitioned - confirmed
           live in this environment that animating it via a class toggle
           (1fr<->0fr) never completes (stuck at the start value
           indefinitely, though the end value applies instantly with no
           transition), a real engine limitation independent of any value
           here. opacity/margin still animate for a fade+collapse feel;
           the row itself snaps, which is a safe, correct fallback. */
        .morning-card { background:linear-gradient(155deg,var(--accent-dark),var(--accent)); border-radius:var(--radius-lg); margin-bottom:var(--space-12); display:grid; grid-template-rows:1fr; transition:opacity var(--dur-slow) var(--ease-standard), margin var(--dur-slow) var(--ease-standard); overflow:hidden; }
        .morning-card.collapsed { grid-template-rows:0fr; opacity:0; margin:0; pointer-events:none; }
        .morning-card > .morning-card-inner { min-height:0; overflow:hidden; padding:var(--space-18) 16px; }
        .morning-card.collapsed > .morning-card-inner { padding:0; }
        /* FAB/font-lg clearance (Sprint 8 final cleanup, 2026-08-28) — at
           desktop width (#mainFab{bottom:32px}, see the min-width:900px
           block below) with font-lg active, the expanded card's own
           content can grow tall enough to reach down into #mainFab's fixed
           band (confirmed: mood/energy rows + "Dismiss card permanently"
           sitting directly under the FAB, unclickable). Bounding only the
           INNER wrapper (not .morning-card itself) keeps the outer grid's
           1fr/0fr collapse transition untouched — this rule only ever
           engages once already-expanded content would exceed the cap, so
           it does not affect the collapse animation this file already
           moved away from a fixed max-height for (see comment above).
           Not scoped narrower than min-width:900px/font-lg — normal font
           size and mobile (.fab{bottom:154px}) don't reproduce this. */
        @media (min-width:900px) {
            body.font-lg .morning-card > .morning-card-inner { max-height:calc(100vh - 230px); overflow-y:auto; }
        }
        .morning-title { font-size:var(--fs-heading-md); font-weight:700; color:var(--text-on-accent); margin:0 0 var(--space-10); letter-spacing:-0.2px; }
        .morning-msg { font-size:var(--fs-body); line-height:1.6; color:rgba(255,255,255,0.8); margin-bottom:var(--space-16); min-height:38px; }
        /* Mood/sleep box + its mood-row gap — pulled out of inline styles
           (2026-08-28, mobile FAB overlap fix below) so the <900px block
           below can override them; base values here are byte-identical
           to the inline styles they replace, so desktop is unaffected. */
        .morning-mood-sleep-box { background:var(--bg2); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-sm); padding:var(--space-10); margin-bottom:var(--space-10); }
        .morning-mood-row { margin-bottom:var(--space-10); }
        .morning-dismiss-row { text-align:center; margin-top:var(--space-8); }
        .energy-title-row { margin-bottom:var(--space-4); }
        .energy-slider-emoji { text-align:center; font-size:var(--font-size-28); margin-bottom:var(--space-4); transition:transform var(--dur-fast) var(--ease-standard); }
        .energy-slider-emoji.pulse { animation:energySliderPulse var(--dur-slow) var(--ease-standard); }
        @keyframes energySliderPulse { 0%{transform:scale(1)} 45%{transform:scale(1.35)} 100%{transform:scale(1)} }
        .sleep-gauge { width:100%; max-width:160px; height:6px; background:rgba(0,0,0,0.08); border-radius:var(--radius-full); margin-top:var(--space-8); overflow:hidden; }
        body.dark .sleep-gauge { background:rgba(255,255,255,0.08); }
        .sleep-gauge-fill { height:100%; width:0%; border-radius:var(--radius-full); background:var(--accent); transition:width var(--dur-base) var(--ease-standard),background var(--dur-base) var(--ease-standard); }
        .sleep-gauge-fill.low { background:var(--warning); }
        .sleep-gauge-fill.high { background:var(--gold); }
        .sleep-gauge-label { font-size:var(--fs-caption); color:var(--text3); margin-top:var(--space-3); }
        .energy-slider { width:100%; -webkit-appearance:none; appearance:none; height:6px; border-radius:var(--radius-full); background:linear-gradient(90deg,var(--color-energy-low),var(--gold),var(--warning)); outline:none; cursor:pointer; }
        .energy-slider::-webkit-slider-thumb { -webkit-appearance:none; width:22px; height:22px; border-radius:var(--radius-full); background:#fff; border:var(--border-thin) solid #d4a017; cursor:pointer; }
        .energy-slider::-moz-range-thumb { width:22px; height:22px; border-radius:var(--radius-full); background:#fff; border:var(--border-thin) solid #d4a017; cursor:pointer; }
        .energy-slider-label { text-align:center; font-size:var(--fs-label); color:rgba(255,255,255,0.65); margin-top:var(--space-4); }
        .oneswipe-pill { display:flex; background:rgba(255,255,255,0.08); border-radius:20px; padding:var(--space-3); margin-top:var(--space-10); margin-bottom:var(--space-8); }
        .oneswipe-pill-opt { flex:1; text-align:center; padding:var(--space-6) 4px; border-radius:18px; font-size:var(--fs-label); color:rgba(255,255,255,0.55); cursor:pointer; transition:all var(--dur-base) var(--ease-standard); }
        .oneswipe-pill-opt.selected { background:rgba(184,134,11,0.3); color:var(--gold-light); }
        .time-inputs { display:none; gap:var(--space-6); align-items:center; margin-top:var(--space-8); }
        .time-inputs.show { display:flex; }
        .time-inputs input { flex:1; padding:var(--space-6) 8px; background:rgba(255,255,255,0.1); border:var(--border-hairline) solid rgba(255,255,255,0.2); border-radius:var(--radius-sm); color:var(--text-on-accent); font-family:inherit; font-size:var(--font-size-16); outline:none; text-align:center; }
        .time-inputs label { font-size:var(--fs-label); color:rgba(255,255,255,0.55); white-space:nowrap; }
        .gen-btn { width:100%; margin-top:var(--space-14); padding:var(--space-8); border-radius:var(--radius-sm); border:var(--border-hairline) solid rgba(184,134,11,0.4); background:rgba(184,134,11,0.18); color:var(--gold-light); font-family:inherit; font-size:var(--font-size-12); cursor:pointer; transition:all var(--dur-base) var(--ease-standard); }
        .gen-btn:hover { background:rgba(184,134,11,0.28); }
        .gen-btn:disabled { opacity:0.35; cursor:not-allowed; }
        /* Mobile FAB/morning-card clearance (mobile-FAB-overlap fix,
           2026-08-28) — at genuine 375px width, normal font size, the
           un-dismissed morning card's own tail AND the day-load card
           right after it both land inside .fab's fixed 154-204px-from-
           bottom band (measured: 19px overlap on each — reproduces at
           normal font size, independent of the font-lg pattern fixed
           above). Tightening the card's internal vertical rhythm (not
           clipping/scrolling it, unlike the font-lg fix above — that
           technique was tried here first and rejected because it hides
           the primary "مهام اليوم" button and the dismiss link behind an
           unlabeled scroll area) clears both while keeping every row
           fully visible. Scoped to <900px, the same breakpoint
           .nav-bottom/#mainFab already use to tell mobile from desktop,
           so desktop's own spacing is untouched. */
        @media (max-width:899px) {
            .morning-card > .morning-card-inner { padding:var(--space-8) 16px; }
            .morning-title { margin-bottom:var(--space-4); }
            .morning-msg { margin-bottom:var(--space-8); }
            .morning-mood-sleep-box { padding:var(--space-6); margin-bottom:var(--space-6); }
            .morning-mood-row { margin-bottom:var(--space-6); }
            .oneswipe-pill { margin-top:var(--space-6); margin-bottom:var(--space-4); }
            .oneswipe-pill-opt { padding:var(--space-4) 4px; }
            .gen-btn { margin-top:var(--space-6); padding:var(--space-6); }
            .morning-dismiss-row { margin-top:var(--space-4); }
            /* font-lg compounds the same overlap (measured 82px at
               desktop scope, 53px here even after the trims just above)
               since --space-* tokens scale 1.15x under body.font-lg —
               a second, tighter tier, higher-specificity so it wins over
               the trims above without needing !important. Verified live:
               without this tier the day-load card still overlapped the
               FAB by 14px at font-lg; with it, clearance is +20px. */
            body.font-lg .morning-card > .morning-card-inner { padding:var(--space-6) 16px; }
            body.font-lg .morning-title { margin-bottom:var(--space-2); }
            body.font-lg .morning-msg { margin-bottom:var(--space-4); min-height:0; }
            body.font-lg .morning-mood-sleep-box { padding:var(--space-2) var(--space-4); margin-bottom:var(--space-4); }
            body.font-lg .morning-mood-row { margin-bottom:var(--space-4); }
            body.font-lg .energy-title-row { margin-bottom:var(--space-2); }
            body.font-lg .sleep-gauge { margin-top:var(--space-3); }
            body.font-lg .sleep-gauge-label { margin-top:var(--space-1); }
            body.font-lg #sleepHoursInput { padding:var(--space-3) 8px; }
            body.font-lg .oneswipe-pill { margin-top:var(--space-3); margin-bottom:var(--space-2); }
            body.font-lg .oneswipe-pill-opt { padding:var(--space-2) 4px; }
            body.font-lg .gen-btn { margin-top:var(--space-2); padding:var(--space-4); }
            body.font-lg .morning-dismiss-row { margin-top:var(--space-1); }
        }
        /* DAY LOAD */
        .day-load { background:var(--bg2); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.12); border-radius:var(--radius-sm); padding:var(--space-9) 12px; margin-bottom:var(--space-12); display:flex; align-items:center; justify-content:space-between; box-shadow:var(--shadow-card); transition:box-shadow var(--dur-slow) var(--ease-standard),border-color var(--dur-slow) var(--ease-standard); }
        body.dark .day-load { background:var(--bg2); border-color:rgba(var(--accent-rgb),0.2); }
        .day-load.glow-warn { box-shadow:0 0 0 1px rgba(184,134,11,0.25),0 0 14px rgba(184,134,11,0.18); border-color:rgba(184,134,11,0.35); }
        .day-load.glow-over { box-shadow:0 0 0 1px rgba(200,90,0,0.3),0 0 18px rgba(200,90,0,0.25); border-color:rgba(200,90,0,0.4); }
        .day-load-label { font-size:var(--fs-label); color:var(--text2); }
        .day-load-bar { flex:1; height:4px; background:var(--bg); border-radius:var(--radius-full); margin:0 10px; }
        .day-load-fill { height:100%; border-radius:var(--radius-full); background:var(--accent); transition:width var(--dur-slow) var(--ease-standard); }
        .day-load-num { font-size:var(--fs-label); color:var(--text3); white-space:nowrap; }
        /* CALENDAR */
        .cal-grid { display:grid; grid-template-columns:repeat(7,1fr); gap:var(--space-3); margin-bottom:var(--space-16); }
        .cal-day { aspect-ratio:1; border-radius:var(--radius-sm); border:var(--border-hairline) solid transparent; background:none; display:flex; flex-direction:column; align-items:center; justify-content:center; cursor:pointer; font-size:var(--fs-body); color:var(--text2); transition:all var(--dur-fast) var(--ease-standard); font-family:inherit; position:relative; }
        .cal-day:hover { background:#e6f4f4; }
        .cal-day.today { background:#e6f4f4; border-color:var(--accent); color:var(--accent); font-weight:600; }
        .cal-day.selected { background:var(--accent); color:var(--text-on-accent); border-color:var(--accent); }
        .cal-day.has-tasks::after { content:''; position:absolute; bottom:3px; width:4px; height:4px; border-radius:var(--radius-full); background:var(--gold); }
        .cal-day.selected::after { background:var(--text-on-accent); }
        .cal-day.other-month { color:var(--text3); opacity:0.5; }
        .month-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:var(--space-12); }
        .month-nav { width:32px; height:32px; border-radius:var(--radius-sm); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.12); background:var(--bg2); color:var(--text2); cursor:pointer; display:flex; align-items:center; justify-content:center; font-size:var(--font-size-16); font-family:inherit; transition:all var(--dur-fast) var(--ease-standard); }
        .month-nav:hover { border-color:var(--accent); color:var(--accent); }
        .month-title { font-size:var(--font-size-15); font-weight:500; color:var(--text1); }
        .cal-weekdays { display:grid; grid-template-columns:repeat(7,1fr); gap:var(--space-2); margin-bottom:var(--space-4); }
        .cal-wd { text-align:center; font-size:var(--fs-caption); color:var(--text3); padding:var(--space-4) 0; }
        /* CAL DAY PANEL */
        .cal-day-panel { background:var(--bg2); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-md); padding:var(--space-12); margin-top:var(--space-10); }
        .cal-day-panel-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:var(--space-10); }
        .cal-day-panel-title { font-size:var(--fs-body); font-weight:600; color:var(--text1); }
        .cal-day-panel-close { background:none; border:none; color:var(--text3); font-size:var(--icon-glyph-16); cursor:pointer; padding:var(--space-4); border-radius:var(--radius-xs); }
        .cal-day-panel-close:hover { color:var(--text1); }
        body.dark .cal-day-panel { background:var(--bg2); border-color:var(--border); }

        /* MODALS */
        /* Sprint 11 — was display:none/flex, which can't transition (a
           display change is instant, so the old `transition:background`
           here was dead CSS; entrance only worked via the `fadeIn`
           animation on .open, and close had no exit motion at all).
           visibility+opacity keeps the same .open toggle (no JS call sites
           touched) but now genuinely animates in both directions. */
        .modal-overlay { position:fixed; inset:0; background:rgba(10,74,74,0); z-index:100; visibility:hidden; opacity:0; display:flex; align-items:flex-end; justify-content:center; pointer-events:none; transition:opacity var(--dur-base) var(--ease-standard), visibility 0s var(--dur-base), background var(--dur-base) var(--ease-standard); }
        /* Inline-style cleanup, Part C z-index scale (2026-09-09) — see the
           --z-* token block in :root for the audit this scale is based on. */
        .modal-overlay.modal-overlay-elevated { z-index:var(--z-modal); }
        .modal-overlay.modal-overlay-top-tier { z-index:var(--z-modal-top); }
        .confetti-canvas { position:fixed; inset:0; pointer-events:none; z-index:var(--z-overlay-top); display:none; }
        .modal-overlay.open { visibility:visible; opacity:1; background:rgba(10,74,74,0.55); pointer-events:auto; transition:opacity var(--dur-base) var(--ease-standard), background var(--dur-base) var(--ease-standard); }
        .modal { background:var(--bg2); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.22); border-radius:var(--radius) var(--radius) 0 0; padding:var(--space-14); width:100%; max-width:var(--modal-max-width); max-height:72vh; overflow-y:auto; animation:slideUpMobile var(--dur-base) var(--ease-standard) both; }
        body.dark .modal { background:var(--bg2); border-color:rgba(var(--accent-rgb),0.35); }
        /* Save-button-below-viewport fix (Item 3) — a long form (6-7
           fields) plus a tall base font size (font-lg) can push
           #customRecordModal's content past its max-height; overflow-y:auto
           on the whole box already made it scrollable, but the Save button
           was the LAST thing in that same scrolled area, so at rest (before
           the user scrolls) it renders below the fold with no signal that
           more content — including the primary action — exists below.
           Scoped to #customRecordModal only (confirmed by direct
           measurement — accountModal/budgetModal and other .modal-overlay
           forms don't reach this height even at font-lg): turns .modal into
           a flex column where only the fields area scrolls
           (min-height:0 is required for a flex child's overflow:auto to
           actually clip instead of growing the flex container) while the
           title and footer stay outside that scroll region as fixed flex
           items — the Save button is now always on screen, no scrolling
           required at all, which is strictly stronger than "reachable via
           scroll." A plain position:sticky footer (tried first) does NOT
           achieve this: sticky only locks an element in place once
           scrolling reaches it, it does not pull a last-child element into
           view before the user has scrolled down to it. */
        #customRecordModal .modal { display:flex; flex-direction:column; overflow-y:hidden; }
        #customRecordModal .modal-title { flex:0 0 auto; }
        #customRecordModal #customRecordModalFields { flex:1 1 auto; min-height:0; overflow-y:auto; }
        .modal-sticky-footer { flex:0 0 auto; margin:var(--space-10) 0 0; box-shadow:0 -6px 10px -6px rgba(0,0,0,0.18); }
        /* Global Layout Consistency — نفس ارتفاع الهيدر ونفس المسافة بعده
           في كل المودالز بدون استثناء. */
        .modal-title { font-size:var(--fs-body); font-weight:500; min-height:30px; margin-bottom:var(--space-14); color:var(--accent-dark); display:flex; align-items:center; justify-content:space-between; }
        /* إيقاع رأسي موحد للحقول جوه المودالز (الـ inline styles القديمة
           8/10px بتتفوق عادي — دي القاعدة الافتراضية للجديد وغير المنسّق). */
        /* [T-358 P5] The vertical rhythm of form fields is set here ONLY (the rule below used to repeat it). The :not() chain sits inside
           :where() so it adds no specificity: this rule is (0,1,1), the same as .modal select / .modal textarea, and a plain
           .modal input.<class> rule (0,2,1) overrides the margin without repeating its class. */
        .modal input:where(:not([type=hidden]):not([type=checkbox]):not([type=radio])), .modal select, .modal textarea { margin-bottom:var(--space-10); }
        /* 44px tap target (Tap Targets Under 44px sprint, Batch 1) — was
           26-28x24-27. min-width/min-height + inline-flex centring is the
           same idiom already used for .refl-star-btn (line ~4273); the
           .icon child needs its own rule below to cancel the global
           [data-icon] 4px trailing margin, or the × sits off-centre. */
        .modal-close { background:none; border:none; cursor:pointer; color:var(--text3); font-size:var(--font-size-16); line-height:1; padding:var(--space-4); min-width:44px; min-height:44px; display:inline-flex; align-items:center; justify-content:center; border-radius:var(--radius-xs); transition:color var(--dur-fast) var(--ease-standard); }
        .modal-close:hover { color:var(--text1); }
        .modal-close .icon { margin-inline-end:0; }
        .modal-label { font-size:var(--font-size-12); color:var(--text3); margin-bottom:var(--space-4); display:block; letter-spacing:0.3px; text-transform:uppercase; }
        .modal input:not([type=checkbox]):not([type=radio]),.modal textarea,.modal select { width:100%; background:var(--bg); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.22); border-radius:var(--radius-sm); padding:var(--space-8) 10px; color:var(--text1); font-family:inherit; font-size:var(--font-size-16); outline:none; direction:rtl; transition:border-color var(--dur-fast) var(--ease-standard); }
        /* [T-342] Stages Manager's "+ مرحلة جديدة" box declares u-mb-6 (6px) but .modal input (higher specificity) won with 10px. */
        #smNewName { margin-bottom:var(--space-6); }
        /* Disabled form inputs had zero visual styling (Sprint 8 Phase 2
           Batch 2, item 3) -- reuses the existing button:disabled idiom. */
        .modal input:disabled,.modal textarea:disabled,.modal select:disabled { opacity:0.5; cursor:not-allowed; background:var(--bg3); }
        /* RTL CSS Keystone Fix (2026-08-26) — see body.lang-ltr above. */
        /* [T-364] Text inputs are excluded on purpose: their width/direction/border come from the (0,3,1) rule above, which beat the
           former `.modal input` direction and `.modal input:focus` selectors here (never applied; deleted, zero computed difference). */
        body.lang-ltr .modal textarea, body.lang-ltr .modal select { direction:ltr; }
        .modal textarea:focus,.modal select:focus { border-color:var(--accent); }
        .modal-sep { height:3px; background:rgba(var(--accent-rgb),0.35); border-radius:var(--radius-full); margin:var(--space-10) 0; }
        /* Shared button-system base (Button System sprint, 2026-08-06) —
           declarations genuinely identical across .btn-primary/.btn-cancel/
           .btn-inline. .back-btn is deliberately pill-shaped (20px radius)
           and excluded from the radius merge. */
        .btn-primary, .btn-cancel, .btn-inline { font-family:inherit; cursor:pointer; border-radius:var(--radius-sm); }
        .btn-primary { flex:1; padding:var(--space-10); border:var(--border-hairline) solid var(--accent); background:var(--accent); color:var(--text-on-accent); font-size:var(--fs-body); transition:all var(--dur-base) var(--ease-standard); }
        .btn-primary:hover { background:var(--accent-dark); }
        .btn-cancel { padding:var(--space-10) 14px; border:var(--border-hairline) solid rgba(var(--accent-rgb),0.12); background:none; color:var(--text2); font-size:var(--fs-body); transition:border-color var(--dur-fast) var(--ease-standard), color var(--dur-fast) var(--ease-standard); }
        .btn-cancel:hover { border-color:var(--accent); color:var(--text1); }
        /* .btn-cancel structurally doubles as a destructive action in modal
           footers (delete project/idea/ambition/tag/etc.) — was previously
           an inline style="color:var(--danger)" per site (Button System
           sprint, Batch 2); same modifier idiom as .btn-inline.danger. */
        .btn-cancel.danger { color:var(--danger); }
        .modal-actions { display:flex; gap:var(--space-8); margin-top:var(--space-10); }
        /* Bottom-nav clearance (Sprint 8 Phase 2 Batch 2, item 2; carried
           over from Sprint 9) — .modal sits bottom-anchored in its overlay
           (align-items:flex-end) with no gap from the viewport edge, so on
           any width where the fixed .nav-bottom bar is visible (<900px,
           its own show/hide breakpoint above) its 58px band sits directly
           over the modal's last row of buttons. Extra bottom margin on the
           actions row grows the modal's own scrollable content height,
           which — because the modal is bottom-anchored, not top-anchored —
           lifts the buttons clear of the bar instead of just adding blank
           space nothing else pushes against. */
        @media (max-width:899px) {
            .modal-actions { margin-bottom:calc(58px + env(safe-area-inset-bottom,0)); }
        }
        /* STREAK */
        /* Fluid hero typography (Sprint 8 Phase 2 Batch 4, item 4,
           2026-08-28) - clamp() calibrated against 320-430px, the app's
           own min-to-max content-column width (max-width:430px, base
           rule): fluid only below 430px (real narrow phones), flat at the
           current fixed value at 430px and up (desktop's fixed-width
           column gains nothing from a wider preferred term). min/max are
           existing --font-size-* tokens, not new pixel values - stays
           <=2.5x (WCAG), and both ends still respond to body.font-sm/
           font-lg since those tokens are already scaled (item 1). */
        .streak-big { font-size:clamp(var(--fs-display-lg), calc(25.5vw - 49.5px), var(--font-size-60)); font-weight:600; color:var(--accent); line-height:1; }
        .streak-sub { font-size:var(--fs-body); color:var(--text3); margin:var(--space-6) 0 16px; }
        .streak-tracks { display:flex; flex-direction:column; gap:var(--space-7); margin-bottom:var(--space-14); }
        .streak-track-row { display:flex; align-items:center; justify-content:space-between; padding:var(--space-7) 11px; background:var(--bg); border-radius:var(--radius-sm); }
        .streak-track-name { font-size:var(--font-size-12); }
        .streak-track-val { font-size:var(--font-size-12); color:var(--gold); font-weight:500; }
        /* TOAST */
        #toastStack { position:fixed; bottom:154px; left:50%; transform:translateX(calc(-50% - 0px)); width:calc(min(430px,100vw) - 32px); z-index:9999; display:flex; flex-direction:column-reverse; gap:var(--space-6); pointer-events:none; }

        /* Save-Failure Banner (Sprint 14 Remediation Batch 1, RB-8) — unlike
           .toast (auto-hides), this stays on screen for as long as
           localStorage writes keep failing (quota exceeded), since a
           5-second toast is not enough warning for an ongoing condition
           that risks real data loss on reload/close. See _showSaveFailureBanner(). */
        /* [T-378] was position:fixed at top:0, which sat on top of the header (and the desktop sidebar) and hid the menu button; now a sibling right under the
           header like the other banners, sticky below it. */
        .save-failure-banner { position:sticky; top:var(--header-h); z-index:9; background:var(--danger); color:var(--text-on-accent);
            padding:var(--space-10) var(--space-16); display:flex; align-items:center; justify-content:center; flex-wrap:wrap; gap:var(--space-12);
            font-size:var(--fs-label); line-height:1.4; text-align:center; box-shadow:var(--shadow-overlay); }
        .save-failure-banner-btn { background:var(--text-on-accent); color:var(--danger); border:none; border-radius:var(--radius-xs);
            padding:var(--space-10) var(--space-16); font-size:var(--fs-label); font-weight:bold; cursor:pointer; font-family:inherit; min-height:36px; }
        /* [T-383] the same banner shell in the accent colour (not an error): the «new version» banner and the sync-locked banner with its field */
        .pwa-banner, .sync-locked-banner { background:var(--accent); }
        .pwa-banner .save-failure-banner-btn, .sync-locked-banner .save-failure-banner-btn { color:var(--accent); }
        .save-failure-banner-input { background:var(--text-on-accent); color:var(--text1); border:none; border-radius:var(--radius-xs);
            padding:var(--space-8) var(--space-12); min-height:36px; flex:1 1 140px; max-width:220px; font-family:inherit; }
        /* [T-329] Gamification off (state.settings.productivity.gamificationEnabled === false): body class set by renderXPBar() */
        body.gamification-off .xp-bar-row, body.gamification-off #dashAchievementsCard { display:none !important; }
        /* [T-327] Calm, non-blocking backup reminder (not an error: no danger colour). */
        .backup-nudge { position:sticky; top:var(--header-h); z-index:9; background:var(--bg2); color:var(--text1);
            border-bottom:var(--border-hairline) solid rgba(var(--accent-rgb),0.35); padding:var(--space-10) var(--space-16);
            display:flex; align-items:center; justify-content:center;
            flex-wrap:wrap; gap:var(--space-10); font-size:var(--fs-label); line-height:1.5; text-align:center; box-shadow:var(--shadow-overlay); }
        /* [T-375] Banners are siblings right under the header, each sticky at the same top: two or more would sit on top of each other while scrolling
           and eat the screen at 390. Only the first stays sticky; the others scroll away with the page. */
        .backup-nudge ~ .backup-nudge, .backup-nudge ~ .save-failure-banner, .save-failure-banner ~ .backup-nudge, .save-failure-banner ~ .save-failure-banner { position:static; }
        .backup-nudge-text { flex:1 1 100%; }
        .backup-nudge-btn { min-height:40px; padding:var(--space-8) var(--space-16); font-size:var(--fs-label); }

        /* --- Unified Tooltip Component --- (Level 1/2/3 كلهم بيستخدموه) */
        .masari-tooltip { position:fixed; z-index:9999; background:var(--bg2,#152020); color:var(--text1,#fff);
            border:var(--border-hairline) solid var(--border,rgba(var(--accent-rgb),0.2)); border-radius:var(--radius-sm); padding:var(--space-6) 10px;
            font-size:var(--fs-label); line-height:1.4; max-width:220px; text-align:center; pointer-events:none;
            white-space:pre-line; opacity:0; transform:translateY(4px); transition:opacity var(--dur-fast) var(--ease-standard),transform var(--dur-fast) var(--ease-standard);
            box-shadow:0 2px 10px rgba(0,0,0,0.15); }
        .masari-tooltip.open { opacity:1; transform:translateY(0); }
        .toast { display:flex; align-items:center; gap:var(--space-8); padding:var(--space-10) 13px; border-radius:var(--radius-sm); font-size:var(--font-size-12); line-height:1.5; box-shadow:0 4px 16px rgba(var(--accent-rgb),0.1); pointer-events:auto; animation:cardIn var(--dur-base) var(--ease-standard) both; transition:opacity var(--dur-slow) var(--ease-standard); border:var(--border-hairline) solid transparent; }
        .toast.info { background:var(--toast-info-bg); color:var(--accent-dark); border-color:rgba(var(--accent-rgb),0.22); }
        .toast.ok { background:var(--toast-ok-bg); color:var(--success); border-color:rgba(45,122,74,0.25); }
        .toast.warn { background:var(--toast-warn-bg); color:var(--orange); border-color:rgba(200,90,0,0.25); animation:cardIn var(--dur-base) var(--ease-standard) both, toastWarnPulse var(--dur-slow) var(--ease-standard) var(--dur-base) 1; }
        .toast.err { background:var(--toast-err-bg); color:var(--red); border-color:rgba(192,57,43,0.25); animation:toastErrFade var(--dur-slow) var(--ease-standard) both; }
        /* Achievement (2026-07-22) — celebratory, not a status report: gold
           gradient + a small scale-bounce instead of the plain slide every
           other type uses, so a genuine milestone visually stands apart. */
        .toast.ach { background:linear-gradient(135deg,var(--gold-light),var(--gold)); color:var(--color-achievement-text); border-color:rgba(184,134,11,0.4); box-shadow:0 4px 20px rgba(184,134,11,0.35); animation:toastAchPop var(--dur-slow) cubic-bezier(.34,1.56,.64,1) both; }
        @keyframes toastWarnPulse { 0%,100% { transform:scale(1); } 40% { transform:scale(1.025); } }
        @keyframes toastErrFade { from { opacity:0; } to { opacity:1; } }
        @keyframes toastAchPop { 0% { opacity:0; transform:scale(0.85) translateY(6px); } 60% { opacity:1; transform:scale(1.04) translateY(0); } 100% { transform:scale(1); } }
        /* Inline-style cleanup (2026-09-09) — moved from JS-built inline style="" attributes */
        .toast-icon-wrap { display:inline-flex; align-items:center; gap:var(--space-6); min-width:0; }
        .toast-retry-btn { margin-inline-start:var(--space-6); }
        .toast-secondary-btn { margin-inline-start:var(--space-6); }
        .toast-countdown { width:20px; height:20px; border-radius:50%; border:var(--border-hairline) solid currentColor; display:inline-flex; align-items:center; justify-content:center; font-size:var(--fs-label); font-weight:700; flex-shrink:0; opacity:0.85; }
        .toast-close-btn { background:none; border:none; color:inherit; cursor:pointer; font-size:var(--fs-heading-sm); flex-shrink:0; min-width:24px; min-height:24px; display:inline-flex; align-items:center; justify-content:center; }
        /* FAB — single button, always horizontally centered on the app's
           own screen (not offset to one side). Used to be paired with a
           separate #fabMoreBtn ("⋯") for extra per-tab actions; merged
           into this one button per explicit product decision — every
           NAVIGATION_REGISTRY module's fab.speedDial already listed the
           primary action as its own first entry, so showing that list on
           every press (see FabEngine.primaryAction()) loses nothing. */
        /* bottom:154px + 50px height = spans up to 204px from viewport
           bottom. body's padding-bottom (above) must clear that whole span
           with a visible margin — it was 148px (less than even the FAB's
           bottom edge), which is why the FAB visually sat on top of the
           last item in a long list (2026-07-24 fix, most noticeable on
           Habits since it's the page most likely to scroll that far). */
        .fab { position:fixed; bottom:154px; left:50%; transform:translateX(-50%); width:50px; height:50px; border-radius:var(--radius-full); background:var(--accent); color:var(--text-on-accent); border:none; font-size:var(--fs-stat); cursor:pointer; display:flex; align-items:center; justify-content:center; box-shadow:0 4px 20px rgba(var(--accent-rgb),0.35); z-index:20; transition:transform var(--dur-base) var(--ease-standard),background var(--dur-base) var(--ease-standard),opacity var(--dur-base) var(--ease-standard); font-family:inherit; }
        .fab:hover { background:var(--accent-dark); }
        body.focus-nav-active .fab { display:none; }
        /* Scroll-aware FAB (mobile FAB-overlap fix, 2026-08-28) — see
           _fabWatchOverlap() near showWorkspaceModule(). Knowledge/Systems
           Marketplace's first card is 150-380px tall, far bigger than the
           FAB's own 50px band, so no reasonable clearance/spacing trim
           (unlike the morning-card fix above) can avoid the overlap
           without hiding real content. Fading the FAB out specifically
           while it would sit on top of that first card — restoring once
           scrolled past — leaves the card fully readable/tappable instead. */
        /* First-run fixes (2026-10-05): the yielded FAB stays tappable. It used to
           be opacity:0.12 + pointer-events:none, which switched the primary
           create action off at 390px as soon as the first task's card landed
           behind it (the card stays tappable everywhere outside the FAB's own
           50px footprint, and scrolling moves it clear). */
        .fab.fab-yield { opacity:0.5; }
        #focusTimer { position:fixed; bottom:210px; left:50%; transform:translateX(calc(-50% + 145px)); background:var(--accent); color:var(--text-on-accent); border-radius:16px; padding:var(--space-8) 14px; font-size:var(--font-size-12); font-weight:600; display:none; flex-direction:column; gap:var(--space-6); z-index:20; box-shadow:0 4px 16px rgba(var(--accent-rgb),0.4); min-width:210px; max-width:260px; }
        #focusTimer.ft-paused { background:var(--text3); }
        #focusTimer .ft-task { font-size:var(--font-size-12); font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
        #focusTimer .ft-row { display:flex; align-items:center; justify-content:space-between; gap:var(--space-10); }
        #focusTimer .ft-times { display:flex; align-items:baseline; gap:var(--space-8); font-family:monospace; }
        #focusTimer .ft-times #focusTimerText { font-size:var(--fs-heading-sm); }
        #focusTimer .ft-remaining { font-size:var(--fs-caption); color:rgba(255,255,255,0.75); font-family:inherit; white-space:nowrap; }
        #focusTimer .ft-controls { display:flex; gap:var(--space-4); }
        #focusTimer button { background:rgba(255,255,255,0.2); border:none; color:var(--text-on-accent); border-radius:var(--radius); padding:var(--space-2) 8px; font-size:var(--fs-label); cursor:pointer; font-family:inherit; }
        .tl-task-chip.tl-active-session { outline:2px solid var(--accent); outline-offset:-1px; box-shadow:0 0 0 3px rgba(var(--accent-rgb),0.15); }
        /* "Right now" hour + "next up" chip — Premium UI Sprint (Timeline
           Phase 1). Pure visual weight, no new state: tl-hour-now is set on
           the current hour's row in renderTimeline(), tl-next-up on the
           first not-done chip at/after now in _renderTimelineChipHTML(). */
        .tl-task-chip.tl-next-up { border-color:rgba(var(--accent-rgb),0.4); box-shadow:var(--tl-bar-inset,0 0 transparent),0 0 0 1px rgba(var(--accent-rgb),0.14),var(--shadow-card); }
        .tl-task-chip.tl-next-up .tl-task-name { font-weight:700; }
        .tl-task-chip.done,.tl-task-chip.tl-archived { box-shadow:none; }
        .advanced-toggle:hover { border-color:var(--accent); color:var(--accent); }
        .folder-header { display:flex; align-items:center; gap:var(--space-8); padding:var(--space-12) 14px; color:var(--text-on-accent); font-family:inherit; font-size:var(--fs-body); font-weight:600; cursor:pointer; border-radius:var(--radius-md); transition:filter var(--dur-fast) var(--ease-standard); }
        body.dark .folder-header { filter:brightness(0.85); }
        .folder-header:hover { filter:brightness(1.1); }
        .folder-header-ic { width:var(--icon-box-24); height:var(--icon-box-24); border-radius:var(--radius-full); background:rgba(255,255,255,0.25); display:flex; align-items:center; justify-content:center; font-size:var(--fs-heading-sm); flex-shrink:0; }
        .folder-header-label { flex:1; }
        .folder-header-count { background:rgba(255,255,255,0.28); border-radius:var(--radius-pill); padding:var(--space-2) 9px; font-size:var(--fs-label); }
        .folder-header-arrow { font-size:var(--font-size-12); opacity:0.85; }
        /* Animations */
        @keyframes cardIn { from { opacity:0; transform:translateY(10px); } to { opacity:1; transform:translateY(0); } }
        @keyframes slideUpMobile { from { opacity:0; transform:translateY(60px); } to { opacity:1; transform:translateY(0); } }
        @keyframes fadeIn { from { opacity:0; } to { opacity:1; } }
        /* Conflict warning */
        .tl-conflict-warning { border-inline-start:var(--border-medium) solid var(--color-urgent) !important; background-color:rgba(211,51,51,0.08) !important; }
        /* Energy Distribution */
        .day-load-fill.warn { background:var(--gold); }
        .day-load-fill.over { background:var(--red); }
        /* Timeline: empty hour strip */
        .tl-gap { display:flex; align-items:center; justify-content:space-between; gap:var(--space-8); padding-block:0; padding-inline-start:calc(var(--tl-card-inset) + var(--space-8)); padding-inline-end:6px; box-sizing:border-box; margin-inline-start:var(--tl-row-inset); border-top:var(--border-hairline) solid rgba(var(--accent-rgb),0.08); cursor:pointer; opacity:0.55; transition:opacity var(--dur-fast) var(--ease-standard); position:relative; }
        .tl-gap:hover { opacity:1; }
        .tl-gap.tl-drop-over { opacity:1; background:rgba(var(--accent-rgb),0.06); border-top:var(--border-thin) solid var(--accent); }
        .tl-gap-compressed { opacity:0.4; }
        .tl-gap-text { font-size:var(--fs-caption); color:var(--text3); }
        .tl-gap-add-btn { font-size:var(--fs-heading-sm); color:var(--text3); width:18px; height:18px; border-radius:var(--radius-full); border:var(--border-hairline) dashed rgba(var(--accent-rgb),0.3); display:flex; align-items:center; justify-content:center; flex-shrink:0; }
        .tl-gap-add-btn svg { width:11px; height:11px; }
        /* Timeline: nizol block — striped rest-window shading on the
           proportional segment loop's own wrapper classes (Task 5 review
           finding #1). The old .tl-slot-based rule and its .tl-hour-label
           color override were removed as dead code (Task 6) once .tl-slot
           was confirmed to no longer render in the new DOM; .tl-hour-label
           itself doesn't render in the new segment loop either (Task 3's
           promoted per-chip time line replaced it), so no equivalent color
           override exists here. */
        .tl-item-wrap.nizol-block, .tl-gap.nizol-block { background:repeating-linear-gradient(45deg,rgba(var(--warning-rgb),0.04),rgba(var(--warning-rgb),0.04) 4px,transparent 4px,transparent 10px); }
        /* Item rows need their own indicator ON the chip (final-review
           Important #4a, 2026-09-04) — .tl-item-wrap's content is
           .tl-task-chip, which paints an opaque background-color over the
           wrapper's full box, so the striping above never showed on an item
           row (it does work on .tl-gap, which has no opaque child — that
           half is untouched). Still true after the icon-on-spine redesign
           moved the chip one level down, inside .tl-item-row: the row itself
           is transparent, so the chip's opaque fill still covers the same
           area of the wrapper it always did.
           Deliberately the SAME repeating-gradient technique as the two
           rules above rather than a border: the first attempt at this used
           border-inline-start, which in RTL (this app's default direction)
           resolves to the same physical edge as the .tl-type-x and .bill-chip
           rules' own physical border-right category stripe, so the two silently
           overwrote each other — and body.dark .tl-task-chip.tl-type-* won
           outright at higher specificity, making the indicator invisible.
           background-image is a property nothing else on the chip sets, so
           it can't collide with the border-based category stripe on any
           physical edge, in any direction or theme. It is the LONGHAND on
           purpose; every chip background rule above is a background-color
           longhand for the same reason (see the note at .tl-task-chip). */
        .tl-task-chip.tl-chip-nizol { background-image:repeating-linear-gradient(45deg,rgba(var(--warning-rgb),0.04),rgba(var(--warning-rgb),0.04) 4px,transparent 4px,transparent 10px); }
        /* Timeline: now-line */
        /* -50px was "far enough out to cross the spine" back when the spine sat
           4px outside the row's edge. The spine now sits ON that edge and the
           badge straddles it, so the line starts at the spine itself and its
           pulsing head-dot (the ::before below, -6px/14px = centered on the
           line's own start) lands on the spine too, next to the badges rather
           than floating in the hour column. Same derived formula as the badge
           and the divider dot. (2026-09-04) */
        .tl-now-line { position:absolute; inset-inline-start:calc(var(--tl-spine-x) - var(--tl-edge-pad)); inset-inline-end:0; height:2px; background:var(--accent); z-index:2; pointer-events:none; }
        .tl-now-line::before { content:''; position:absolute; inset-inline-start:-6px; top:-6px; width:14px; height:14px; border-radius:var(--radius-full); background:var(--accent); box-shadow:var(--shadow-ring-pulse); animation:tlNowPulse 2.4s ease-in-out infinite; }
        @keyframes tlNowPulse { 0%,100% { box-shadow:var(--shadow-ring-pulse); } 50% { box-shadow:0 0 0 7px rgba(var(--accent-rgb),0.08); } }
        /* Timeline: drag states */
        .tl-task-chip[draggable=true] { cursor:grab; }
        .tl-task-chip.tl-dragging { opacity:0.35; transform:scale(0.97); box-shadow:none; }
        /* [T-246] the lifted copy that follows the finger during a touch move; never hit-testable */
        .tl-touch-ghost { position:fixed; z-index:var(--z-overlay-top); pointer-events:none; max-width:70vw; transform:translate(-50%, -120%); padding:var(--space-8) var(--space-12); border-radius:var(--radius-sm); background:var(--bg); color:var(--text1); border:var(--border-thin) solid var(--accent); box-shadow:var(--shadow-overlay); font-size:var(--fs-caption); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
        /* Same sibling problem as .tl-item-row.done (2026-09-04 fix round):
           the badge and hour column are no longer inside the chip, so the rule
           above stopped fading them and a dragged row left a fully-saturated
           icon pinned on the spine at the source position — reading as "still
           here" while the card reads as "lifted out". tlDragStart mirrors the
           class onto the row (and tlDragEnd clears it).
           Opacity only, no transform: the chip's scale(0.97) is card feedback,
           and shrinking an absolutely-positioned badge that is deliberately
           centred on the spine buys nothing. */
        .tl-item-row.tl-dragging > .tl-kind-badge,
        .tl-item-row.tl-dragging > .tl-item-hour-col { opacity:0.35; }
        /* Color-only, exactly as the deleted .tl-slot.tl-drop-target was —
           .tl-item-wrap's base rule above now reserves the border-top
           width/style permanently (transparent), so toggling this class on
           every row at drag-start recolors in place instead of reflowing.
           Task 6's fix round restated the full shorthand here because
           .tl-item-wrap then had no border to override; that reintroduced
           the reflow the .tl-slot design had avoided (final-review
           Important #3, 2026-09-04). */
        .tl-item-wrap.tl-drop-target { border-top-color:rgba(var(--accent-rgb),0.2); }
        .tl-item-wrap.tl-drop-over { background:rgba(var(--accent-rgb),0.06) !important; border-top:var(--border-thin) solid var(--accent) !important; }
        .tl-drop-indicator { position:absolute; right:6px; left:6px; height:3px; background:var(--accent); border-radius:var(--radius-full); opacity:0; pointer-events:none; }
        .tl-task-chip.tl-drop-above .tl-drop-indicator { top:-2px; opacity:1; }
        .tl-task-chip.tl-drop-below .tl-drop-indicator { bottom:-2px; opacity:1; }
        .tl-task-chip.tl-drop-above { transform:translateY(3px); }
        .tl-task-chip.tl-drop-below { transform:translateY(-3px); }
        /* Timeline: resize handle */
        .tl-resize-handle { position:absolute; bottom:0; left:0; right:0; height:8px; cursor:ns-resize; display:flex; align-items:flex-end; justify-content:center; }
        .tl-resize-handle::after { content:''; width:24px; height:2px; margin-bottom:3px; background:rgba(var(--accent-rgb),0.3); border-radius:var(--radius-full); }
        /* Touch: taller invisible hit area (grows upward inside the chip, which clips overflow); the 2px line stays where it was. */
        @media (pointer:coarse) { .tl-resize-handle { height:20px; } }
        /* [T-279] A short chip (under 60px high, see _tlResizeStripCompact) keeps only a centred 96x12px strip at its bottom edge under a coarse pointer, so a swipe or a long-press move can start anywhere else on the card. The 2px line inside it stays centred. */
        @media (pointer:coarse) { .tl-resize-handle[data-tl-compact] { left:calc(50% - 48px); right:auto; width:96px; height:12px; } }
        .tl-task-chip.tl-resizing { box-shadow:0 0 0 2px var(--accent); }
        /* Timeline: swipe */
        .tl-swipe-wrap { position:relative; margin-bottom:var(--space-3); }
        .tl-swipe-bg { position:absolute; inset:0; border-radius:var(--radius-xl); display:flex; align-items:center; justify-content:space-between; padding:0 14px; font-size:var(--font-size-12); font-weight:600; color:var(--text-on-accent); opacity:0; pointer-events:none; }
        .tl-swipe-bg.show-right { background:var(--accent); opacity:1; justify-content:flex-start; }
        .tl-swipe-bg.show-left { background:var(--gold); opacity:1; justify-content:flex-end; }
        .tl-swipe-wrap .tl-task-chip { position:relative; z-index:1; transition:transform var(--dur-fast) var(--ease-standard); margin-bottom:0; }
        .tl-swipe-wrap .tl-task-chip.swiping { transition:none; }
        /* Timeline: fixed / recurring — per archive/44 Part A2 decision #6,
           fixed-time no longer carries its own separate color (shown only via
           the revealed tag icon); .fixed-task/.recurring-fixed are still
           applied in JS but intentionally carry no border/background here so
           the item's own type-group color (the .tl-type- rules and .bill-chip
           above) is what renders, not overridden by a same-specificity,
           later-declared rule regardless of item type. */
        /* Timeline Priority: overdue bills stand out more than upcoming ones */
        .tl-task-chip.tl-bill-overdue { border-right:var(--border-medium) solid var(--danger) !important; background-color:rgba(192,57,43,0.08) !important; }
        .tl-task-chip.tl-bill-overdue .tl-task-name { color:var(--danger); font-weight:700; }
        .tl-task-chip.done .tl-task-name { text-decoration:line-through; }
        /* Timeline: effort dot */
        .tl-effort-dot { width:6px; height:6px; border-radius:var(--radius-full); flex-shrink:0; }
        .effort-heavy { background:var(--danger); }
        .effort-medium { background:var(--warning); }
        .effort-light { background:var(--success); }
        /* Timeline: badges */
        .dep-pending-badge,.task-tag-badge { display:inline-block; font-size:var(--fs-caption); padding:var(--space-1) 5px; border-radius:var(--radius-xs); margin:var(--space-1) 2px 0 0; }
        .dep-pending-badge { background:rgba(200,90,0,0.1); color:var(--warning); }
        .task-tag-badge { background:rgba(var(--accent-rgb),0.08); color:var(--accent); }
        /* Timeline: completing animation */
        @keyframes bounce { 0%,100%{transform:scale(1)} 40%{transform:scale(1.3)} 70%{transform:scale(0.9)} }
        @keyframes tlCompleteFlash { 0% { box-shadow:0 0 0 0 rgba(var(--accent-rgb),0.35),var(--shadow-card); } 100% { box-shadow:0 0 0 10px rgba(var(--accent-rgb),0),var(--shadow-card); } }
        .tl-task-chip.completing { animation:cardIn var(--dur-slow) var(--ease-standard),tlCompleteFlash var(--dur-slow) var(--ease-standard); }
        .tl-check.bounce { animation:bounce var(--dur-slow) var(--ease-standard); }
        .completing { animation:cardIn var(--dur-slow) var(--ease-standard); }
        /* XP Breakdown micro-popover (Progression Completion Initiative,
           Phase 7) — anchored, not routed through the shared toast()
           queue, deliberately lighter than a toast: task completion is
           too high-frequency for a full toast per the existing "no XP
           breakdown toast on every tick" rule, but the request still
           wants a quiet "why did I get this XP" signal. */
        @keyframes xpMicroPop { 0%{opacity:0; transform:translateY(4px) scale(0.9);} 15%{opacity:1; transform:translateY(-2px) scale(1);} 80%{opacity:1; transform:translateY(-2px) scale(1);} 100%{opacity:0; transform:translateY(-10px) scale(0.95);} }
        .xp-micro-popover { position:fixed; z-index:5000; pointer-events:none; background:var(--bg2); color:var(--text1); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.35); border-radius:var(--radius-xs); padding:var(--space-4) 9px; font-size:var(--fs-label); white-space:nowrap; box-shadow:0 2px 8px rgba(0,0,0,0.18); animation:xpMicroPop 2.4s ease forwards; }
        /* Responsive */
        @media (max-width:400px) { body { padding-bottom:var(--space-230); } .nav-bottom-item { min-width:50px; font-size:var(--fs-micro); } .modal { max-height:80vh; padding:var(--space-12); }
            /* I-20's old fix compressed header-zone-middle's own gap to 2px
               here to fit up to 4 unshrinkable 44px icon buttons plus the
               focus-session indicator — that made adjacent circular buttons
               read as touching/overlapping (UI/UX fixes batch, 2026-09-12,
               Part A #1). Superseded: .header-zone-middle now keeps its
               normal var(--space-8) gap at every width and overflow-x:auto
               scrolls instead of compressing — see that rule's own comment. */
        }

        /* ===== UI POLISH ===== */
        /* filter-row scrolls horizontally on all screens */
        /* Better timeline hour label padding */
        /* padding-inline-start, not padding-right (final-review Critical #1,
           2026-09-04) — this padding IS the spine gutter, and .timeline's
           own positioned children (.timeline::before, .tl-now-line,
           .tl-period-divider::before) were converted to inset-inline-start
           in Task 4. Leaving the containing block's own padding physical
           made the two resolve to opposite sides in LTR (gutter right,
           spine left → spine drew through the chips, divider dot outside
           the box). RTL is unchanged: inline-start === right there. */
        .timeline { min-height:100px; padding-inline-start:var(--tl-edge-pad); position:relative; }
        /* Timeline "journey" connecting line — Premium UI Sprint (Timeline
           Phase 1). Pure render-layer addition threaded through the hour-label
           gutter (--tl-edge-pad); sits behind everything by DOM order alone
           (this ::before paints first, every .tl-hour/.tl-period-divider that
           follows in the markup paints over it) — no z-index needed.
           Execution-progress spine (Timeline Phase 3, 2026-07-31) — the line
           is solid up to --tl-progress-pct (how far "now" is through the
           rendered range, set inline by renderTimeline() from the same
           nowHour/minH/maxH it already computes) and faded after — the
           spine itself shows how much of the day has passed. */
        /* inset-inline-start is now derived from --tl-spine-x (2026-09-04
           icon-on-spine redesign) instead of the old bare 42px literal, and
           --tl-spine-x === --tl-edge-pad, so the line sits exactly on
           .timeline's content-box edge. The -1px is half the 2px width, so
           the visual CENTER of the line — not its leading edge — is what lands
           on --tl-spine-x; the kind badge and the period-divider dot are both
           centered on the same x, which is what makes them read as threaded
           onto it. */
        .timeline::before { content:''; position:absolute; top:6px; bottom:6px; inset-inline-start:calc(var(--tl-spine-x) - 1px); width:2px; background:linear-gradient(to bottom, rgba(var(--accent-rgb),0.55) 0%, rgba(var(--accent-rgb),0.55) var(--tl-progress-pct,30%), rgba(var(--accent-rgb),0.1) var(--tl-progress-pct,30%), rgba(var(--accent-rgb),0.1) 100%); border-radius:var(--radius-full); pointer-events:none; }
        .tl-period-divider { display:flex; align-items:center; margin:var(--space-16) 0 8px; position:relative; }
        .tl-period-divider-label { display:inline-flex; align-items:center; gap:var(--space-6); background:var(--bg); padding-right:var(--space-2); font-size:var(--fs-label); font-weight:700; color:var(--text3); }
        /* Milestone marker (Timeline Phase 3, 2026-07-31) — a real waypoint
           dot ON the connecting line at each day-period transition, not just
           a floating label. Real-usage bug fix: this needed the same
           42px-from-.timeline's-edge x-position as .timeline::before, but
           .tl-period-divider is itself a child laid out INSIDE .timeline's
           content box (already inset by .timeline's own --tl-edge-pad
           padding-right), so a plain "right:42px" here was measured from
           the DIVIDER's own edge, landing the dot ~46px further left than
           intended — inside the chip content area itself instead of the
           spine's gutter, where it could sit right on top of a chip's
           leading kind-badge icon. Same correction .tl-hour-label already
           applies (right:calc(var(--tl-edge-pad) * -1)) for the same
           containing-block mismatch, offset by the extra 42px to match the
           spine's exact position instead of the label's edge position. */
        /* 2026-09-04: the "+ 42px" literal became var(--tl-spine-x), and since
           --tl-spine-x === --tl-edge-pad the whole calc now resolves to 0 —
           i.e. the containing-block mismatch this comment describes is gone by
           construction, not corrected after the fact. Left as the explicit
           subtraction rather than a bare 0 so it stays correct if the spine is
           ever moved off the content edge again. Identical formula to
           .tl-item-wrap .tl-kind-badge's, which is what makes the badge and
           this dot land on the same x — verified by getBoundingClientRect in
           both RTL and LTR. */
        .tl-period-divider::before { content:''; position:absolute; top:50%; inset-inline-start:calc(var(--tl-spine-x) - var(--tl-edge-pad)); width:10px; height:10px; margin-top:-5px; margin-inline-start:-5px; border-radius:50%; background:var(--accent); box-shadow:0 0 0 3px var(--bg); z-index:1; }
        .tl-period-divider-label svg { width:13px; height:13px; }
        .tl-period-divider-label svg.tl-period-icon-flip { transform:scaleY(-1); }
        /* Component separation (Premium UI Sprint, Timeline Phase 2,
           2026-07-31) — Anytime Today / Unscheduled used to just be a
           colored label floating above a chip list, blending into the page.
           Real card framing now makes them read as distinct zones, outside
           the hour-grid's flowing connecting line on purpose (they have no
           time, so they shouldn't look threaded into the timed flow) —
           right padding still matches the hour row's own gutter (--tl-
           edge-pad/--tl-row-inset, unchanged) so their chips stay
           horizontally aligned with the grid above/below.
           Left padding corrected 10px→var(--space-6) (2026-08-29,
           no-time-vs-timed row width bug): only the right side was ever
           reconciled against the hour row's own gutter (see the comment
           below) — the left side was still a bare, unrelated 10px literal
           against .tl-slot's real 6px padding-left (masari.html ~875),
           leaving these chips ~4px narrower than a real scheduled Timeline
           chip at any width. The section's own 1px border (intentional
           card framing per this comment) accounts for the remaining ~1px
           and is not part of this fix. */
        #anytimeTodaySection, #recurringUnscheduledSection { background:var(--bg2); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-lg); padding:var(--space-10) 0 8px var(--space-6); box-shadow:var(--shadow-card); }
        /* Negative habits card (end of day, outside the time grid): tier-3 weight, own box. */
        #negHabitsTodaySection { background:var(--bg2); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.3); border-radius:var(--radius-lg); box-shadow:0 2px 8px rgba(var(--accent-rgb),0.22); overflow:hidden; }
        /* >=900px the floating + is not watched by _fabWatchOverlap and sits ~32px above the viewport bottom: reserve room below the last card so it never covers it at scroll end. */
        @media (min-width:900px) { #negHabitsTodaySection { margin-bottom:96px; } }
        .neg-card-head { display:flex; align-items:center; gap:var(--space-6); width:100%; min-height:44px; padding:var(--space-6) var(--space-10); background:none; border:none; color:var(--text1); font-family:inherit; font-size:var(--fs-heading-sm); font-weight:700; cursor:pointer; text-align:start; }
        .neg-card-title { flex:1; }
        .neg-card-count { font-weight:700; color:var(--text2); font-variant-numeric:tabular-nums; }
        .neg-card-body { padding:0 var(--space-10) var(--space-8); display:flex; flex-direction:column; gap:var(--space-8); }
        .neg-card-row { display:flex; flex-direction:column; gap:var(--space-6); }
        .neg-card-name { font-weight:600; color:var(--text1); }
        .tl-section-heading { display:flex; align-items:center; gap:var(--space-6); font-size:var(--fs-label); font-weight:700; color:var(--text3); margin-bottom:var(--space-8); padding-left:var(--space-2); }
        .tl-section-heading-anytime { color:var(--gold); }
        /* نفس مساحة صف الساعة (.tl-hour margin-right) + حاوية الـ Timeline —
           عشان كروت "مهام بدون وقت محدد" تتساوى أفقياً مع كروت الـ Timeline
           تلقائياً لو المسافات دي اتغيرت. مصدر واحد: --tl-edge-pad / --tl-row-inset. */
        /* padding-inline-start — same gutter as .timeline's above, so it has
           to flip with it in LTR (final-review Critical #1, 2026-09-04). */
        /* 2026-09-04 icon-on-spine redesign — the alignment target moved. A
           Timeline card no longer starts at .timeline's content edge; it
           starts --tl-card-inset further in, because the badge occupies that
           strip. These two sections have no spine and no hour column, so their
           badge is still an in-flow flex child (--tl-badge-size + the row's
           --tl-badge-gap) ahead of their card. Subtracting exactly that much
           lands BOTH their badge and their card on the same x as the
           Timeline's — better alignment than before, not just preserved.
           --tl-badge-size here is deliberately the :root DEFAULT, and stays
           correct after the 2026-09-04 duration-scaled badge: the inline
           per-item override is emitted only on rows that have a spine to be
           centered on, so these two sections' badges really are 36px, while
           --tl-card-inset (the Timeline card's x) keys off --tl-badge-size-max.
           Re-checked at the new numbers: 78 + 0 + 28 - 36 - 6 = 64, + 36 badge
           + 6 gap = 106, and the Timeline's own card sits at 78 + 28 = 106. */
        #recurringUnscheduledSection, #anytimeTodaySection { padding-inline-start:calc(var(--tl-edge-pad) + var(--tl-row-inset) + var(--tl-card-inset) - var(--tl-badge-size) - var(--tl-badge-gap)); }
        /* Improved modal inputs in dark mode */
        body.dark .modal input, body.dark .modal textarea, body.dark .modal select { background:var(--bg3); border-color:var(--border); color:var(--text1); }
        body.dark .modal input:focus, body.dark .modal textarea:focus, body.dark .modal select:focus { border-color:var(--accent); }
        /* Dark mode — missing elements */
        /* .tl-task-name/.tl-task-track/.tl-hour-label dark-mode overrides
           removed (Sprint 13 Phase 2) — their base rules now use var(--text1)/
           var(--text3) directly, so they resolve correctly per-mode without
           a separate override. */
        body.dark .day-load-label { color:var(--text2); }
        body.dark .day-load-num { color:var(--text3); }
        body.dark .day-load-bar { background:var(--bg3); }
        body.dark .cal-day { color:var(--text2); }
        body.dark .cal-day:hover { background:var(--bg3); }
        body.dark .cal-day.today { background:rgba(var(--accent-rgb),0.15); border-color:var(--accent); color:var(--accent); }
        body.dark .month-title { color:var(--text1); }
        body.dark .cal-wd { color:var(--text3); }
        body.dark .modal-title { color:var(--accent); }
        body.dark .advanced-toggle { background:var(--bg3); color:var(--text2); border-color:var(--border); }
        body.dark .dep-pending-badge, body.dark .task-tag-badge { background:var(--bg3); color:var(--text2); }
        body.dark .backlog-status { background:rgba(var(--accent-rgb),0.15); color:var(--text2); }
        body.dark .backlog-status.ready { background:rgba(var(--accent-rgb),0.12); color:var(--text2); }
        body.dark .backlog-status.conditional { background:rgba(200,90,0,0.12); color:var(--warning); }
        body.dark .pill-group button { background:var(--bg3); color:var(--text2); border-color:var(--border); }
        body.dark .dash-stat-row { border-color:var(--border); }
        body.dark .dash-stat-num { color:var(--text1); }
        body.dark .filter-btn.active { background:var(--accent); color:var(--text-on-accent); border-color:var(--accent); }

        /* ===== UI CONSISTENCY SYSTEM ===== */

        /* --- Pill Group (track/subtrack/project selectors) --- */
        .pill-group { display:flex; flex-wrap:wrap; gap:var(--space-4); margin-bottom:var(--space-6); }
        .pill-group .filter-btn { font-size:var(--fs-label); padding:var(--space-3) 10px; }
        /* Finance UX Redesign — صف مزدوج جوه المودالز: حقلين جنب بعض بدل
           عمود واحد طويل، لتقليل المساحة الرأسية وسرعة إتمام العملية. */
        .modal-row2 { display:grid; grid-template-columns:1fr 1fr; gap:0 10px; align-items:start; }
        .modal-row2 > div { min-width:0; }
        /* زرار "＋ إضافة ملاحظة" — الملاحظات مخفية لحد ما المستخدم يطلبها */
        .modal-notes-toggle { background:none; border:var(--border-hairline) dashed rgba(var(--accent-rgb),0.35); border-radius:var(--radius-sm); color:var(--accent); font-family:inherit; font-size:var(--fs-label); padding:var(--space-6) 10px; cursor:pointer; width:100%; text-align:center; }
        .modal-notes-toggle:hover { background:rgba(var(--accent-rgb),0.06); }

        /* --- Task Modal Progressive Sections (Task Creation System
           Redesign, 2026-07-29) — accordion-style collapsible sections
           shared by the unified Add/Edit task modal. Only one open at a
           time; a "completed" section keeps its content but shows a
           checkmark instead of the chevron affordance. --- */
        .task-section { border:var(--border-hairline) solid var(--border); border-radius:var(--radius-sm); margin-bottom:var(--space-8); overflow:hidden; }
        .task-section-header { display:flex; align-items:center; gap:var(--space-6); padding:var(--space-10) 12px; cursor:pointer; background:var(--bg2); user-select:none; }
        .task-section-title { flex:1; font-size:var(--font-size-12); font-weight:700; letter-spacing:0.3px; color:var(--text2); display:flex; align-items:center; gap:var(--space-6); }
        .task-section-check { display:none; color:var(--success); }
        .task-section.completed .task-section-check { display:inline-flex; }
        .task-section-chevron { color:var(--text3); transition:transform var(--dur-fast) var(--ease-standard); }
        .task-section.open .task-section-chevron { transform:rotate(180deg); }
        .task-section-body { display:none; padding:var(--space-12); }
        .task-section.open .task-section-body { display:block; }
        body.dark .task-section-header { background:var(--bg3); }

        /* --- Tag Pill --- */
        .tag-pill { display:inline-flex; align-items:center; gap:var(--space-4); padding:var(--space-2) 8px; border-radius:20px;
            background:rgba(var(--accent-rgb),0.08); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.18);
            color:var(--accent); font-size:var(--fs-label); font-family:inherit; cursor:default; }
        body.dark .tag-pill { background:rgba(var(--accent-rgb),0.15); border-color:rgba(var(--accent-rgb),0.3); color:var(--text2); }
        .tag-pill.is-active-range { background:var(--teal,#0D6E6E); color:var(--text-on-accent); }
        .sc-chip.is-inherited { opacity:0.65; }
        .sc-chip.is-low-confidence { border-color:var(--warning); }
        .sc-chip.is-ambiguous-tie { border-color:var(--danger); }
        .is-done-text { text-decoration:line-through; opacity:0.5; }
        .dash-stat-row.done { text-decoration:line-through; opacity:0.5; }
        .ambition-linked-item.done { text-decoration:line-through; opacity:0.6; }
        .undo-op-icon { color:var(--op-color); }
        .undo-op-badge { color:var(--op-color); background:color-mix(in srgb, var(--op-color) 13%, transparent); font-size:var(--fs-caption); font-weight:600; border-radius:var(--radius-xl); padding:var(--space-2) 9px; }
        .status-badge.is-status-color { color:var(--status-color); background:color-mix(in srgb, var(--status-color) 13%, transparent); }
        .backlog-item.pri-high { border-right:var(--border-medium) solid var(--danger); }
        .backlog-item.pri-medium { border-right:var(--border-medium) solid var(--color-priority-medium); }
        .backlog-item.pri-low { border-right:var(--border-medium) solid var(--border); }
        .backlog-item.is-read { opacity:0.6; }
        .notif-title-text { font-weight:700; }
        .notif-title-text.is-read { font-weight:400; }
        .ts-table-cell { font-weight:500; }
        .ts-table-cell.is-root-depth { font-weight:700; }
        /* touch-action:none scoped to this element only (Thinking Space
           Canvas Phase 3b) — suppresses the browser's own native pinch-
           zoom/pan/double-tap-zoom gesture specifically on the canvas so
           it doesn't fight with the custom pinch-to-zoom handling in
           tsPanStart/Move/End below; native page pinch-zoom (viewport
           meta allows up to 5x) is untouched everywhere else. */
        #tsViewport { cursor:grab; touch-action:none; }
        #tsViewport.is-connect-mode { cursor:crosshair; }
        #tsConnectHint { display:none; }
        #tsConnectHint.is-connect-mode { display:block; }
        .dash-stat-row.is-linked { cursor:pointer; }
        .knowledge-graph-node { cursor:pointer; }
        .knowledge-graph-node.is-dimmed { opacity:0.15; }
        .kpi-group-label { font-size:var(--fs-caption); font-weight:600; color:var(--text3); text-transform:uppercase; letter-spacing:0.04em; margin:10px 0 4px; }
        .kpi-group-label.is-first { margin-top:0; }
        .ts-type-section-title.is-search-results { margin:0 0 6px; }
        .ts-type-section-title.is-search-results.has-recent { margin-top:10px; }
        .heatmap-grid { display:grid; grid-template-columns:repeat(10,minmax(24px,1fr)); gap:var(--space-2); justify-items:center; align-items:center; }
        .heatmap-grid.is-compact { grid-template-columns:repeat(10,minmax(12px,1fr)); }
        #amAdvancedSection, #appearanceAdvancedSection, #generalAdvancedSection, #taskAdvancedSection, #habitAdvancedSection, #knowledgeAdvancedSection, #ambitionAdvancedSection, #accountAdvancedSection, #finTxExpenseAdvancedSection, #billAdvancedSection, #budgetAdvancedSection, #goalAdvancedSection, #customRecordAdvancedSection, #debtAdvancedSection { display:none; }
        #amAdvancedSection.is-expanded, #appearanceAdvancedSection.is-expanded, #generalAdvancedSection.is-expanded, #taskAdvancedSection.is-expanded, #habitAdvancedSection.is-expanded, #knowledgeAdvancedSection.is-expanded, #ambitionAdvancedSection.is-expanded, #accountAdvancedSection.is-expanded, #finTxExpenseAdvancedSection.is-expanded, #billAdvancedSection.is-expanded, #budgetAdvancedSection.is-expanded, #goalAdvancedSection.is-expanded, #customRecordAdvancedSection.is-expanded, #debtAdvancedSection.is-expanded { display:block; }
        .tag-pill.active { background:var(--accent); border-color:var(--accent); color:var(--text-on-accent); font-weight:600; }
        .tag-remove { cursor:pointer; color:var(--text3); font-size:var(--fs-caption); line-height:1; border:none; background:none; padding:0; font-family:inherit; }
        .tag-remove:hover { color:var(--danger); }

        /* --- Inline Action Button (small, used inside JS-rendered rows) --- */
        .btn-inline { padding:var(--space-3) 10px; border:var(--border-hairline) solid var(--border);
            background:var(--bg3); color:var(--text2); font-size:var(--fs-label);
            transition:all var(--dur-fast) var(--ease-standard); }
        .btn-inline:hover { border-color:var(--accent); color:var(--accent); }
        .btn-inline.danger { border-color:rgba(var(--danger-rgb),0.3); color:var(--danger); }
        .btn-inline.danger:hover { background:rgba(var(--danger-rgb),0.1); }
        .btn-inline.success { border-color:rgba(39,174,96,0.4); color:var(--success); }
        .btn-inline.success.active { background:var(--success); color:var(--text-on-accent); border-color:var(--success); }
        /* --- Ghost (color-adaptive) --- .btn-inline assumes a normal page
           background; .btn-ghost has none of its own — it inherits
           background/text color from whatever container it sits in
           (e.g. a colored toast: info/success/warn/err). Button System
           sprint, Batch 3 — was .toast-retry-btn's own inline style. */
        .btn-ghost { background:none; border:var(--border-hairline) solid currentColor; border-radius:5px; color:inherit; font-family:inherit; cursor:pointer; font-size:var(--font-size-12); padding:var(--space-2) 8px; display:inline-flex; align-items:center; gap:var(--space-5); flex-shrink:0; }
        /* Negative-habit نجحت/وقعت buttons only (scoped past .btn-inline so
           the many unrelated .btn-inline.danger delete buttons elsewhere
           keep their plain flat style) — same gradient-pill look and exact
           {color}cc→{color} formula as gradientPill()/.gpill (the pillar
           filter pills), per explicit user request to match that style.
           Always tinted (not just when active); the active/logged-today
           one gets a ring instead of an on/off color swap. */
        .btn-inline.neg-habit-btn { flex:1; border-radius:var(--radius-pill); color:var(--text-on-accent); border:none; font-weight:600; text-shadow:0 1px 2px rgba(0,0,0,0.25); transition:filter var(--dur-fast) var(--ease-standard),box-shadow var(--dur-fast) var(--ease-standard); }
        .neg-habit-btn:hover { filter:brightness(1.08); }
        .neg-habit-btn.success { background:linear-gradient(135deg,#2d7a4acc,var(--success)); }
        .neg-habit-btn.danger { background:linear-gradient(135deg,#c0392bcc,var(--danger)); }
        .neg-habit-btn.success.active { box-shadow:0 0 0 2px rgba(39,174,96,0.4); }
        .neg-habit-btn.danger.active { box-shadow:0 0 0 2px rgba(192,57,43,0.4); }

        /* --- Toggle Switch (يحل محل زرار ✓/⏸ القديم لكل إعدادات ON/OFF) ---
           الصفحة dir="rtl" دايمًا (مفيش تبديل ديناميكي لـ dir حتى مع
           English UI) — الوضع الافتراضي (OFF) بيبان يمين، (ON) بيتحرك شمال،
           بما يطابق اتجاه القراءة. */
        .settings-toggle-row { cursor:pointer; user-select:none; display:flex; align-items:center; gap:var(--space-10); }
        .settings-pill-row { display:flex; align-items:center; justify-content:space-between; gap:var(--space-12); }
        .settings-pill-row > span:first-child { flex-shrink:0; }
        .settings-pill-row > .pill-group { justify-content:flex-end; min-width:0; }
        .settings-toggle-row:focus-visible { outline:2px solid var(--accent); outline-offset:2px; border-radius:var(--radius-sm); }
        .switch-track { position:relative; display:inline-block; width:40px; height:24px; flex-shrink:0;
            background:var(--border); border-radius:var(--radius-pill); transition:background var(--dur-fast) var(--ease-standard); }
        .switch-track.on { background:var(--accent); }
        .switch-knob { position:absolute; top:2px; right:2px; width:20px; height:20px; border-radius:50%;
            background:#fff; box-shadow:0 1px 2px rgba(0,0,0,0.25); transition:transform var(--dur-fast) var(--ease-standard); }
        .switch-track.on .switch-knob { transform:translateX(-16px); }

        /* --- Count Badge (habit multi-count display) --- */
        .count-badge { display:inline-flex; align-items:center; justify-content:center;
            min-width:36px; font-size:var(--font-size-12); color:var(--text2); font-weight:500; }

        /* --- Habit toggle button states (replaces scattered inline styles) --- */
        .habit-toggle-btn { padding:var(--space-4) 10px; border-radius:var(--radius-sm); border:var(--border-hairline) solid var(--border);
            background:transparent; color:var(--text1); cursor:pointer; font-family:inherit;
            font-size:var(--font-size-12); transition:all var(--dur-fast) var(--ease-standard); }
        /* .habit-toggle-btn.done and .btn-inline.active were byte-identical
           declarations (Button System sprint, Batch 4) — merged. The rest
           of .habit-toggle-btn's base rule stays its own: real deltas from
           .btn-inline (transparent bg, --text1, 6px radius) that would
           change its rendered look if forced to match. */
        .habit-toggle-btn.done, .btn-inline.active { background:var(--accent); border-color:var(--accent); color:var(--text-on-accent); }

        /* --- Streak display --- */
        .streak-chip { font-size:var(--fs-label); color:var(--text3); margin-right:var(--space-4); }

        /* --- Progress bar (unified) --- */
        .prog-bar-wrap { flex:1; height:4px; background:rgba(var(--accent-rgb),0.1); border-radius:var(--radius-full); overflow:hidden; }
        .prog-bar-fill { height:100%; border-radius:var(--radius-full); background:var(--accent); transition:width var(--dur-slow) var(--ease-standard); }
        .prog-bar-fill.warn { background:var(--gold); }
        .prog-bar-fill.danger { background:var(--danger); }

        /* --- Status badge (project/task status) --- */
        /* Base rule + is-success/is-warning/is-danger/is-on-dark modifiers
           relocated here from the Finance section (Sprint 9 Phase 2 Batch 2,
           item 19) -- organizational only, .status-badge isn't Finance-
           specific and this file already had an "active/paused/completed"
           modifier set for the same class sitting right here. */
        .status-badge { display:inline-flex; align-items:center; padding:var(--space-2) 8px; border-radius:var(--radius-pill); font-size:var(--fs-label); font-weight:600; white-space:nowrap; }
        .status-badge.is-success { color:var(--success); background:rgba(45,122,74,0.12); }
        .status-badge.is-warning { color:var(--warning); background:rgba(var(--warning-rgb),0.12); }
        .status-badge.is-danger { color:var(--danger); background:rgba(var(--danger-rgb),0.12); }
        .status-badge.is-on-dark { color:var(--text-on-accent); background:rgba(255,255,255,0.18); }
        .status-badge.active  { background:rgba(var(--accent-rgb),0.1);  color:var(--accent); }
        .status-badge.paused  { background:rgba(200,90,0,0.1);    color:var(--warning); }
        .status-badge.completed { background:rgba(39,174,96,0.1); color:var(--success); }
        body.dark .status-badge.active    { background:rgba(var(--accent-rgb),0.2);  color:var(--text2); }
        body.dark .status-badge.paused    { background:rgba(200,90,0,0.15);   color:var(--warning); }
        body.dark .status-badge.completed { background:rgba(39,174,96,0.15);  color:#2ecc71; }


        /* --- Hover states for all interactive cards --- */
        .task-item:hover { border-color:rgba(var(--accent-rgb),0.22); box-shadow:var(--shadow-card-hover); }
        .tl-task-chip:hover { border-color:rgba(var(--accent-rgb),0.22); box-shadow:var(--tl-bar-inset,0 0 transparent),0 2px 6px rgba(var(--accent-rgb),0.1); }
        /* Premium Details pass (2026-07-31) — chip had hover but no press
           feedback; [draggable=true] already gets a "grab" cursor above,
           this adds the missing tactile tap response (same scale used by
           .gpill/.filter-btn elsewhere, reusing the chip's own existing
           token-based transition, no new one). */
        .tl-task-chip:active { transform:scale(0.98); }

        /* --- Consistent spacing tokens --- */
        /* gap-xs=4px gap-sm=6px gap-md=8px gap-lg=12px (used in flex/grid via inline style) */

        

        .backlog-item.is-active { border-color:var(--accent); }
        .backlog-item:hover { border-color:rgba(var(--accent-rgb),0.25); box-shadow:var(--shadow-card-hover); }
        /* Onboarding checklist (Sprint 08) is .backlog-item.done's only
           consumer [T-22, 2026-09-13] — dimming moved from the whole row
           to .onboarding-step-label only, so the completion checkmark
           (.onboarding-step-check, a row-level sibling of the label, not
           its descendant) renders at full opacity/color instead of being
           faded along with everything else. */
        .onboarding-step-label.done { opacity:0.55; }
        .onboarding-step-check { color:var(--success); flex-shrink:0; }
        

        /* ===== PRINT ===== */
        @media print {
            .header, .nav-sidebar, .nav-bottom, .fab, #toastStack, #focusTimer,
            .task-icon-btn, .modal-overlay,
            .filter-row, .filter-btn, .subnav, .advanced-toggle,
            button:not(.task-check) { display:none !important; }
            body { background:#fff !important; color:#000 !important; max-width:100% !important;
                padding:0 !important; font-size:11pt; direction:rtl; }
            /* RTL CSS Keystone Fix (2026-08-26) — see body.lang-ltr above. */
            body.lang-ltr { direction:ltr; }
            body.print-bw { filter:grayscale(1); }
            /* Print Themes (2026-07-25) — إضافة على B&W الموجود، مش بديل
               ليه: High Contrast لسهولة القراءة على ورق رخيص/طابعات ليزر
               ضعيفة (حدود أسمك + إلغاء أي تدرج لوني)، Minimal لتقليل الحبر
               فى طباعات كتير الصفحات (بيشيل الأيقونات الزخرفية والخلفيات،
               نص وحدود بس). */
            body.print-high-contrast { filter:contrast(1.4) grayscale(1); }
            body.print-high-contrast .dash-card, body.print-high-contrast .backlog-item, body.print-high-contrast .tl-task-chip { border:var(--border-thin) solid #000 !important; }
            body.print-minimal .dash-card, body.print-minimal .backlog-item, body.print-minimal .tl-task-chip { background:#fff !important; box-shadow:none !important; }
            body.print-minimal .icon, body.print-minimal [data-icon] { display:none !important; }
            .tab-content { display:none !important; }
            .tab-content[style*="display: block"], body.printing .tab-content[style*="display: block"] { display:block !important; }
            .dash-card { border:var(--border-hairline) solid #ccc !important; box-shadow:none !important; break-inside:avoid; }
            .tl-task-chip { border:var(--border-hairline) solid #ddd !important; box-shadow:none !important; break-inside:avoid; }
            .backlog-item { border:var(--border-hairline) solid #ccc !important; box-shadow:none !important; break-inside:avoid; }
            .task-item { border:var(--border-hairline) solid #ccc !important; box-shadow:none !important; }
            .tl-now-line { display:none !important; }
            h1,h2,h3 { page-break-after:avoid; }
            @page { margin:15mm; size:A4 portrait; }
        }

        /* ===== PRINT PREVIEW PANE (2026-07-25) — on-screen approximation of the
           @media print rules above, so the preview modal shows something close
           to what will actually print. Not pixel-exact (real pagination depends
           on the printer/browser), just the same theme filters + hidden chrome. */
        .print-preview-pane { background:var(--bg2); color:var(--text1); border-radius:var(--radius-sm); border:var(--border-hairline) solid var(--border); padding:var(--space-14); max-height:48vh; overflow:auto; }
        .print-preview-pane .header, .print-preview-pane .nav-sidebar, .print-preview-pane .nav-bottom,
        .print-preview-pane .fab, .print-preview-pane .task-icon-btn,
        .print-preview-pane .filter-row, .print-preview-pane .filter-btn,
        .print-preview-pane .subnav, .print-preview-pane .advanced-toggle,
        .print-preview-pane button:not(.task-check) { display:none !important; }
        .print-preview-pane.print-bw { filter:grayscale(1); }
        .print-preview-pane.print-high-contrast { filter:contrast(1.4) grayscale(1); }
        .print-preview-pane.print-minimal .icon, .print-preview-pane.print-minimal [data-icon] { display:none !important; }
        /* Report-style blocks (rpt-*) — same class names ReportingEngine.generate()
           emits for the popup print windows (see _reportDocHTML()); mirrored here
           so the same HTML also renders correctly inside .print-preview-pane. */
        .print-preview-pane .rpt-stats { display:flex; gap:var(--space-16); margin:var(--space-14) 0; flex-wrap:wrap; }
        .print-preview-pane .rpt-stat { background:var(--bg3); border-radius:var(--radius-sm); padding:var(--space-10) 16px; text-align:center; }
        .print-preview-pane .rpt-stat b { display:block; font-size:var(--font-size-20); color:var(--accent); }
        .print-preview-pane .rpt-stat span { font-size:var(--fs-label); color:var(--text2); }
        .print-preview-pane .rpt-table { width:100%; border-collapse:collapse; margin-top:var(--space-10); font-size:var(--fs-body); }
        .print-preview-pane .rpt-table th, .print-preview-pane .rpt-table td { border:var(--border-hairline) solid var(--border); padding:var(--space-6) 10px; text-align:right; }
        /* RTL CSS Keystone Fix (2026-08-26) — see body.lang-ltr near line 216. */
        body.lang-ltr .print-preview-pane .rpt-table th, body.lang-ltr .print-preview-pane .rpt-table td { text-align:left; }
        .print-preview-pane .rpt-table th { background:var(--bg3); }
        .print-preview-pane .rpt-muted { font-size:var(--fs-body); color:var(--text2); }
        .print-preview-pane .rpt-muted.sm { font-size:var(--font-size-12); }
        .print-preview-pane .rpt-decision { background:var(--bg3); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.2); border-radius:var(--radius-sm); padding:var(--space-4) 16px; margin:var(--space-14) 0; }
        .print-preview-pane .rpt-decision-row { margin:var(--space-8) 0; }
        .print-preview-pane .rpt-decision-row b { display:block; font-size:var(--fs-label); color:var(--accent); text-transform:uppercase; letter-spacing:.02em; }
        .print-preview-pane .rpt-decision-row p { margin:var(--space-2) 0 0; font-size:var(--fs-body); }
        .print-preview-pane .rpt-decision-action { border-top:var(--border-hairline) dashed rgba(var(--accent-rgb),0.33); padding-top:var(--space-8); }
        .print-preview-pane h3 { color:var(--accent); border-bottom:var(--border-thin) solid var(--accent); padding-bottom:var(--space-6); }
        .print-preview-pane .item { padding:var(--space-8) 0; border-bottom:var(--border-hairline) solid var(--border); display:flex; gap:var(--space-8); }
        .print-preview-pane .done { color:var(--success); }

        /* ===== FOCUS OVERLAY ===== */
        .pomodoro-overlay { position:fixed; inset:0; background:var(--bg); z-index:200; display:none; flex-direction:column; align-items:center; justify-content:center; gap:var(--space-18); padding:var(--space-20); }
        .pomodoro-overlay.show { display:flex; }
        .pomodoro-ring-wrap { position:relative; width:200px; height:200px; flex-shrink:0; }
        .pomodoro-ring-svg { transform:rotate(-90deg); }
        .pomodoro-ring-bg { fill:none; stroke:var(--bg3); }
        .pomodoro-ring-fill { fill:none; stroke:var(--accent); stroke-linecap:round; transition:stroke-dashoffset 1s linear; }
        .pomodoro-timer-overlay { position:absolute; inset:0; display:flex; align-items:center; justify-content:center; }
        /* Fluid hero typography - see .streak-big's comment above for the
           320-430px calibration rationale (Sprint 8 Phase 2 Batch 4, item 4). */
        .pomodoro-timer { font-size:clamp(var(--font-size-28), calc(21.8vw - 41.8px), var(--font-size-52)); font-weight:600; color:var(--accent); font-family:monospace; letter-spacing:2px; }
        .pomodoro-label { font-size:var(--fs-body); color:var(--text2); text-align:center; max-width:300px; }
        .pomodoro-controls { display:flex; gap:var(--space-10); flex-wrap:wrap; justify-content:center; }
        .pomodoro-controls button { min-width:80px; }

        /* ===== ZEN OVERLAY ===== */
        .zen-overlay { position:fixed; inset:0; background:var(--bg); z-index:200; display:none; flex-direction:column; align-items:center; justify-content:center; gap:var(--space-24); }
        .zen-overlay.show { display:flex; }
        .zen-circle { width:120px; height:120px; border-radius:var(--radius-full); background:var(--accent); opacity:0.6; }
        .zen-circle.breathing { animation:zenBreathe 8s ease-in-out infinite; }
        @keyframes zenBreathe { 0%,100%{transform:scale(1);opacity:0.5} 50%{transform:scale(1.4);opacity:0.8} }
        .zen-text { font-size:var(--fs-heading-md); color:var(--text2); font-weight:500; }
        .zen-close { padding:var(--space-8) 16px; border-radius:var(--radius-sm); border:var(--border-hairline) solid var(--border); background:var(--bg2); color:var(--text2); font-family:inherit; font-size:var(--fs-body); cursor:pointer; }


        /* ===== MOOD PICKER IN MODAL ===== */
        #moodPicker { gap:var(--space-8); }
        /* 44px tap target (App-Wide Mobile Input & Control Defects, Batch 4).
           Scoped to #moodPicker deliberately — 13 rules govern .filter-btn and
           only this variant is a fixed square; an unscoped change would reach
           58 sites across the app. */
        #moodPicker .filter-btn { font-size:var(--font-size-20); width:44px; height:44px; padding:0; display:flex; align-items:center; justify-content:center; border-radius:var(--radius-full); transition:transform var(--dur-fast) var(--ease-standard),box-shadow var(--dur-fast) var(--ease-standard),border-color var(--dur-fast) var(--ease-standard); }
        #moodPicker .filter-btn:active { transform:scale(0.92); }
        #moodPicker .filter-btn.active { transform:scale(1.14); box-shadow:var(--shadow-ring-active); }
        /* Matches #moodPicker .filter-btn's own specificity (ID+class) so this
           inline-style extraction keeps winning over the 44x44-circle default
           above, same as the inline style="" it replaced. */
        #moodPicker .filter-btn.mood-picker-btn { font-size:var(--fs-heading-md); padding:var(--space-6) 10px; }

        /* ===== ADVANCED TOGGLE ===== */
        .advanced-toggle { width:100%; text-align:right; padding:var(--space-10) 12px; background:var(--bg2); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-sm); color:var(--text1); font-family:inherit; font-size:var(--fs-body); cursor:pointer; margin-bottom:var(--space-6); display:block; transition:all var(--dur-fast) var(--ease-standard); }
        /* RTL CSS Keystone Fix (2026-08-26) — see body.lang-ltr near line 216. */
        body.lang-ltr .advanced-toggle { text-align:left; }
        .advanced-toggle:hover { background:var(--bg3); }

        /* ===== FINANCE PREMIUM UI ===== */
        /* Sub-nav */
        .fin-subnav { display:flex; overflow-x:auto; background:var(--bg2); border-bottom:var(--border-hairline) solid var(--border); padding:0 8px; gap:0; scrollbar-width:none; }
        .fin-subnav::-webkit-scrollbar { display:none; }
        .fin-subnav-btn { display:flex; flex-direction:column; align-items:center; gap:var(--space-2); padding:var(--space-8) 10px; border:none; background:none; color:var(--text3); font-family:inherit; font-size:var(--fs-caption); font-weight:500; cursor:pointer; white-space:nowrap; border-bottom:var(--border-thin) solid transparent; transition:all var(--dur-fast) var(--ease-standard); flex-shrink:0; }
        .fin-subnav-btn.active { color:var(--accent); border-bottom-color:var(--accent); }
        .fin-subnav-icon { font-size:var(--icon-glyph-16); }
        /* [T-311] Scroll-edge cue for the Finance strip (8 tabs overflow a phone-width bar; the recorded choice is to scroll,
           not shrink). A soft accent edge on whichever PHYSICAL side still has hidden tabs; NavigationEngine.
           syncContextTabsOverflow toggles .has-more-left / .has-more-right from where the tabs sit against the bar's edges,
           so it needs no RTL branch (the pure-CSS `local`-background version vanished under direction:rtl in Chrome).
           The repeated body.dark selector is needed because `body.dark .fin-subnav` resets the whole `background` shorthand. */
        .fin-subnav.fin-subnav-fade, body.dark .fin-subnav.fin-subnav-fade {
            background:
                linear-gradient(to right, var(--fin-subnav-fade-l, transparent), transparent) left center / 16px 100% no-repeat,
                linear-gradient(to left, var(--fin-subnav-fade-r, transparent), transparent) right center / 16px 100% no-repeat,
                var(--bg2);
        }
        .fin-subnav-fade.has-more-left { --fin-subnav-fade-l: rgba(var(--accent-rgb),0.30); }
        .fin-subnav-fade.has-more-right { --fin-subnav-fade-r: rgba(var(--accent-rgb),0.30); }
        body.dark .fin-subnav-fade.has-more-left { --fin-subnav-fade-l: rgba(255,255,255,0.40); }
        body.dark .fin-subnav-fade.has-more-right { --fin-subnav-fade-r: rgba(255,255,255,0.40); }
        /* Second-level nav variant (خواطري Compact Subnav Restyle) — same
           .fin-subnav-btn base, only scale-related properties overridden;
           active-color/weight/transition/cursor inherit unchanged. See
           the 'subnav-compact' renderVariant branch in
           NavigationEngine.renderContextTabs(). */
        .fin-subnav-btn.compact { flex-direction:row; gap:0; font-size:var(--fs-micro); padding:var(--space-6) var(--space-10); border-bottom-width:var(--border-hairline); }

        /* Finance What-If (Finance Redesign Phase 7, 2026-08-29) — inline
           form, not a modal, so its inputs need the same rules .modal
           input/select/textarea gets (that rule is scoped to .modal
           ancestors and would otherwise not apply here). font-size is left
           unset so the app-wide input/textarea/select 16px floor applies. */
        .fwi-param-form { display:flex; flex-direction:column; gap:var(--space-8); margin:var(--space-10) 0; }
        .fwi-param-form input, .fwi-param-form select { width:100%; background:var(--bg); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.22); border-radius:var(--radius-sm); padding:var(--space-8) 10px; color:var(--text1); font-family:inherit; outline:none; direction:rtl; transition:border-color var(--dur-fast) var(--ease-standard); }
        .fwi-param-form input:focus, .fwi-param-form select:focus { border-color:var(--accent); }
        body.dark .fwi-param-form input, body.dark .fwi-param-form select { background:var(--bg3); border-color:var(--border); color:var(--text1); }
        body.lang-ltr .fwi-param-form input, body.lang-ltr .fwi-param-form select { direction:ltr; }
        .fwi-empty-note { font-size:var(--font-size-12); color:var(--text3); text-align:center; padding:var(--space-10) 0; }
        .fwi-composed-list { display:flex; flex-wrap:wrap; gap:var(--space-6); margin-bottom:var(--space-8); }
        .fwi-chip { display:inline-flex; align-items:center; gap:var(--space-4); background:rgba(var(--accent-rgb),0.08); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-pill); padding:var(--space-4) var(--space-10); font-size:var(--fs-label); color:var(--text2); }
        .fwi-chip-remove { background:none; border:none; color:var(--danger); cursor:pointer; font-size:var(--fs-label); padding:0; line-height:1; }
        .fwi-result-box { background:rgba(var(--accent-rgb),0.06); border-radius:var(--radius-sm); padding:var(--space-10); margin-top:var(--space-8); }
        .fwi-result-oneliner { font-size:var(--fs-body); font-weight:600; color:var(--text1); margin-bottom:var(--space-6); }
        .fwi-extra { margin-top:var(--space-6); }
        .fwi-problem { font-size:var(--fs-label); color:var(--danger); margin-top:var(--space-6); }
        .fwi-details { margin-top:var(--space-8); padding-top:var(--space-8); border-top:var(--border-hairline) solid var(--border); }
        .fwi-detail-row { display:flex; justify-content:space-between; gap:var(--space-8); font-size:var(--fs-label); padding:var(--space-4) 0; color:var(--text2); }
        .fwi-detail-sub { font-size:var(--fs-caption); font-weight:600; color:var(--text3); margin-top:var(--space-8); }
        .fwi-compare-row { display:flex; gap:var(--space-10); margin-top:var(--space-8); }
        .fwi-compare-col { flex:1; min-width:0; }
        @media (max-width:600px) { .fwi-compare-row { flex-direction:column; } }

        /* Module */
        /* Global Layout Consistency — نفس البادينج الأفقي بتاع .tab-content
           و subviews الـ Planner (كانت 12px فبتكسر المحور البصري الموحد). */
        .fin-module { animation:finFadeIn var(--dur-fast) var(--ease-standard); padding:var(--space-14) 16px; }
        @keyframes finFadeIn { from{opacity:0;transform:translateY(6px)} to{opacity:1;transform:none} }

        /* Knowledge Domain (2026-07-18) */
        .knowledge-toolbar { display:flex; gap:var(--space-8); flex-wrap:wrap; align-items:center; margin-bottom:var(--space-14); }
        /* FAB/font-lg clearance (Sprint 8 final cleanup, 2026-08-28) — at
           desktop width the narrow content column (~350-400px, same width
           as mobile) forces this toolbar's 7 controls to wrap onto several
           rows; under font-lg each control is wide/tall enough that this
           wraps to 5 rows (~243px), pushing .knowledge-grid's empty-state
           text down into #mainFab's fixed bottom:32px band (confirmed:
           ~50px overlap, full FAB/text collision at rest, no scroll).
           Bounding the toolbar with internal scroll reclaims that height
           without touching any control's own size/legibility — same
           "matching the pattern" pattern only ID'd Knowledge b/c empty-
           state text is what auto-clipped. */
        @media (min-width:900px) {
            body.font-lg .knowledge-toolbar { max-height:150px; overflow-y:auto; }
        }
        .knowledge-toolbar input[type="text"], .knowledge-toolbar select { padding:var(--space-6) 10px; border-radius:var(--radius-sm); border:var(--border-hairline) solid var(--border); background:var(--bg2); color:var(--text1); font-size:var(--font-size-16); }
        /* FAB/font-lg clearance (Sprint 8 final cleanup, 2026-08-28) —
           same mechanism as .knowledge-toolbar above: Systems Marketplace's
           Installed Systems cards are the tallest, most variable-count
           contributor above the category filter chips (.gpill); with
           several systems installed and font-lg on, this list alone can
           push the chip row down into #mainFab's fixed band. Bounding it
           with internal scroll (rather than the shared gridOpen markup the
           Explore grids below still use unbounded) reclaims that height
           without hiding any installed system — just requires a scroll
           within its own list once several are installed. */
        @media (min-width:900px) {
            body.font-lg .sysmkt-installed-grid { max-height:130px; overflow-y:auto; }
        }
        /* FAB/font-lg clearance (Sprint 8 final cleanup, 2026-08-28) — the
           category chip row itself (.gpill) is what the original finding
           named directly: under font-lg the chips are wide enough that
           wrapping (the row's normal u-flex-wrap-gap-6 behavior) grows it
           to 3-4 rows, and depending on how much precedes it (hero +
           installed list, capped above but still variable), that tall
           wrapped block can itself land across #mainFab's band. A
           horizontal-scroll row (nowrap) is the standard pattern for a
           chip/filter list — collapses it to one ~50px row instead of
           several, which is both a smaller, more predictable footprint and
           arguably a better UX for this control than multi-row wrapping. */
        @media (min-width:900px) {
            body.font-lg .sysmkt-category-pills { flex-wrap:nowrap; overflow-x:auto; padding-bottom:var(--space-4); }
        }
        .knowledge-toolbar input[type="text"] { flex:1; min-width:160px; }
        .knowledge-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(220px,1fr)); gap:var(--space-12); }
        .knowledge-card { border:var(--border-hairline) solid var(--border); border-radius:var(--radius); padding:var(--space-12); background:var(--bg2); cursor:pointer; transition:transform var(--dur-instant) var(--ease-standard), border-color var(--dur-instant) var(--ease-standard); }
        .knowledge-card:hover { transform:translateY(-2px); border-color:var(--accent); }
        .knowledge-card-cat { font-size:var(--fs-label); font-weight:600; display:flex; align-items:center; gap:var(--space-4); margin-bottom:var(--space-6); color:var(--cat-color); }
        .knowledge-card-title { font-size:var(--fs-heading-sm); font-weight:600; color:var(--text1); margin-bottom:var(--space-6); }
        .knowledge-card-desc { font-size:var(--font-size-12); color:var(--text2); line-height:1.5; margin-bottom:var(--space-8); }
        .knowledge-card-footer { display:flex; align-items:center; justify-content:space-between; gap:var(--space-6); margin-bottom:var(--space-6); }
        .knowledge-card-badges { display:flex; align-items:center; gap:var(--space-6); }
        .knowledge-card-badges span { display:inline-flex; align-items:center; gap:var(--space-2); font-size:var(--fs-caption); color:var(--text3); }
        .knowledge-card-badges .icon { width:12px; height:12px; }
        .knowledge-card-tags { display:flex; flex-wrap:wrap; gap:var(--space-4); }
        .knowledge-highlight { background:rgba(var(--accent-rgb),0.35); color:inherit; border-radius:var(--radius-xs); padding:0 1px; }
        .knowledge-reader-cat { font-size:var(--font-size-12); font-weight:600; display:flex; align-items:center; gap:var(--space-4); margin:var(--space-4) 0 10px; color:var(--cat-color); }
        .knowledge-reader-tags { display:flex; flex-wrap:wrap; gap:var(--space-4); margin:var(--space-8) 0; }
        .knowledge-reader-section { margin-top:var(--space-14); padding-top:var(--space-10); border-top:var(--border-hairline) solid var(--border); }
        .knowledge-reader-section h4 { font-size:var(--font-size-12); color:var(--text3); margin:0 0 8px; }
        .knowledge-reader-source { font-size:var(--font-size-12); color:var(--text3); margin:var(--space-2) 0 8px; }
        .knowledge-resource-row { display:flex; align-items:center; justify-content:space-between; gap:var(--space-6); padding:var(--space-4) 0; }
        .knowledge-resource-row a { display:flex; align-items:center; gap:var(--space-6); font-size:var(--fs-body); color:var(--accent); text-decoration:none; }
        .knowledge-resource-note { color:var(--text3); font-size:var(--fs-label); }
        .knowledge-resource-remove { cursor:pointer; color:var(--text3); font-size:var(--fs-body); padding:var(--space-2) 6px; }
        .knowledge-resource-remove:hover { color:var(--danger); }
        .knowledge-resource-add { margin-top:var(--space-6); font-size:var(--font-size-12); color:var(--accent); cursor:pointer; }
        .knowledge-related-chip, .knowledge-suggested-chip, .knowledge-link-chip { display:inline-flex; align-items:center; gap:var(--space-4); padding:var(--space-3) 9px; border-radius:20px; font-size:var(--font-size-12); margin:var(--space-2); cursor:pointer; }
        .knowledge-related-chip { background:rgba(var(--accent-rgb),0.12); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.3); color:var(--accent); }
        .knowledge-suggested-chip { background:var(--bg2); border:var(--border-hairline) dashed var(--border); color:var(--text2); }
        .knowledge-link-chip { background:var(--bg2); border:var(--border-hairline) solid var(--border); color:var(--text2); cursor:pointer; }
        .knowledge-suggested-label { font-size:var(--fs-label); color:var(--text3); margin:var(--space-6) 0 4px; }
        /* Domain Evolution (2026-07-31) — health-signal row + grouped links */
        .knowledge-health-row { display:flex; align-items:center; flex-wrap:wrap; gap:var(--space-6); margin:var(--space-6) 0 10px; }
        .knowledge-health-row .tag-pill { font-size:var(--fs-caption); }
        .knowledge-links-group { margin-bottom:var(--space-8); }
        .knowledge-links-group:last-child { margin-bottom:0; }
        /* Reader restructure (2026-07-27) — Summary/Main Content/Highlights,
           richer content rendering, Reading Mode. */
        .knowledge-reader-summary { font-size:var(--fs-body); font-weight:600; color:var(--text1); background:rgba(var(--accent-rgb),0.08); border-right:var(--border-medium) solid var(--accent); border-radius:var(--radius-sm); padding:var(--space-8) 12px; margin:var(--space-6) 0 12px; }
        .knowledge-reader-content { font-size:var(--fs-body); color:var(--text2); line-height:1.7; }
        .knowledge-reader-content p { margin:0 0 8px; }
        .knowledge-reader-content h3, .knowledge-reader-content h4, .knowledge-reader-content h5 { color:var(--text1); margin:var(--space-12) 0 6px; }
        .knowledge-reader-content ul, .knowledge-reader-content ol { margin:0 0 8px; padding-inline-start:20px; }
        .knowledge-reader-content blockquote.knowledge-md-quote { border-inline-start:3px solid var(--border); margin:var(--space-8) 0; padding:var(--space-2) 12px; color:var(--text3); font-style:italic; }
        .knowledge-reader-content pre.knowledge-code-block { background:var(--bg2); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-sm); padding:var(--space-8) 10px; overflow-x:auto; font-family:monospace; font-size:var(--font-size-12); direction:ltr; text-align:start; }
        .knowledge-highlight-item { background:rgba(245,158,11,0.1); border-right:var(--border-medium) solid #f59e0b; border-radius:var(--radius-sm); padding:var(--space-6) 10px; margin-bottom:var(--space-6); font-size:var(--fs-body); font-style:italic; display:flex; justify-content:space-between; gap:var(--space-6); align-items:flex-start; }
        .knowledge-highlight-remove { cursor:pointer; color:var(--text3); flex-shrink:0; }
        .knowledge-reading-mode .knowledge-reader-cat,
        .knowledge-reading-mode .knowledge-reader-source,
        .knowledge-reading-mode .knowledge-reader-tags,
        .knowledge-reading-mode .knowledge-reader-section,
        .knowledge-reading-mode .knowledge-reader-lineage,
        .knowledge-reading-mode .modal-actions { display:none; }
        .knowledge-reading-mode .knowledge-reader-summary,
        .knowledge-reading-mode .knowledge-reader-content { max-width:640px; margin-inline:auto; font-size:var(--font-size-16); line-height:1.9; }
        .knowledge-reader-lineage { font-size:var(--font-size-12); color:var(--text3); margin-top:var(--space-12); }
        .knowledge-reader-lineage a { color:var(--accent); cursor:pointer; }
        .knowledge-cat-row { display:flex; align-items:center; gap:var(--space-10); padding:var(--space-7) 10px; border:var(--border-hairline) solid var(--border); border-inline-start:3px solid var(--border); border-radius:var(--radius-sm); margin-bottom:var(--space-6); background:var(--bg2); }
        .knowledge-cat-row.has-cat-color { border-inline-start-color:var(--cat-color); }
        .knowledge-cat-row-icon { width:26px; height:26px; border-radius:50%; display:flex; align-items:center; justify-content:center; flex-shrink:0; }
        .knowledge-cat-row-icon.has-cat-color { background:color-mix(in srgb, var(--cat-color) 13%, transparent); color:var(--cat-color); }
        /* Fixes a pre-existing bug: the inline style this replaced was
           background:var(--accent-rgb,13,110,110,0.13) — since --accent-rgb
           IS defined, var()'s fallback is ignored and this resolved to the
           invalid declaration background:13,110,110 (confirmed via
           getComputedStyle: fully transparent, never rendered the intended
           tint). Same color-mix idiom as .has-cat-color above, fixed to a
           real color instead of the broken var() composition. */
        .knowledge-cat-row-icon.accent-tinted { background:color-mix(in srgb, var(--accent) 13%, transparent); color:var(--accent); }
        .knowledge-cat-row-icon .icon { width:14px; height:14px; }
        .knowledge-cat-row-name { flex:1; font-size:var(--fs-body); font-weight:600; color:var(--text1); }
        .knowledge-cat-row-default { font-size:var(--fs-label); color:var(--text3); }

        /* Hero sections */
        .fin-hero { border-radius:16px; padding:var(--space-20); margin-bottom:var(--space-16); color:var(--text-on-accent); position:relative; overflow:hidden; }
        .fin-hero::before { content:''; position:absolute; top:-30px; left:-30px; width:160px; height:160px; background:rgba(255,255,255,0.06); border-radius:var(--radius-full); }
        .fin-hero::after { content:''; position:absolute; bottom:-40px; right:-20px; width:200px; height:200px; background:rgba(255,255,255,0.04); border-radius:var(--radius-full); }
        .fin-hero-wallet { background:linear-gradient(135deg,var(--accent) 0%,var(--fin-accent-dark) 100%); }
        .fin-hero-teal   { background:linear-gradient(135deg,var(--accent) 0%,var(--fin-hero-teal-end) 100%); }
        .fin-hero-dark   { background:linear-gradient(135deg,var(--fin-hero-dark-start) 0%,var(--fin-hero-dark-end) 100%); }
        .fin-hero-purple { background:linear-gradient(135deg,var(--fin-hero-purple-start) 0%,var(--fin-hero-purple-end) 100%); }
        .fin-hero-green  { background:linear-gradient(135deg,var(--fin-hero-green-start) 0%,var(--fin-hero-green-end) 100%); }
        .fin-hero-amber  { background:linear-gradient(135deg,var(--fin-hero-amber-start) 0%,var(--fin-hero-amber-end) 100%); }
        .fin-hero-label { font-size:var(--font-size-12); opacity:0.8; font-weight:400; letter-spacing:0.3px; position:relative; }
        /* Fluid hero typography - see .streak-big's comment above for the
           320-430px calibration rationale (Sprint 8 Phase 2 Batch 4, item 4). */
        .fin-hero-amount { font-size:clamp(var(--font-size-20), calc(10.9vw - 14.9px), var(--fs-display-lg)); font-weight:700; margin:var(--space-4) 0 0; letter-spacing:-0.5px; position:relative; }
        .fin-hero-sub { font-size:var(--font-size-12); opacity:0.7; margin-top:var(--space-2); position:relative; }
        .fin-hero-stats { display:flex; align-items:center; gap:0; position:relative; }
        .fin-hero-stat { flex:1; text-align:center; }
        .fin-hero-stat-div { width:1px; height:32px; background:rgba(255,255,255,0.2); }
        .fin-hero-stat-label { font-size:var(--fs-caption); opacity:0.75; margin-bottom:var(--space-3); }
        .fin-hero-stat-val { font-size:var(--font-size-15); font-weight:700; }
        .circ-progress { position:relative; display:inline-flex; align-items:center; justify-content:center; flex-shrink:0; width:64px; height:64px; }
        .circ-progress-sm { width:40px; height:40px; }
        .circ-progress-lg { width:96px; height:96px; }
        .circ-progress-track { stroke:var(--border); }
        .circ-progress-fill { stroke:var(--accent); }
        .circ-progress.status-critical .circ-progress-fill { stroke:var(--danger); }
        .circ-progress.status-warning .circ-progress-fill { stroke:var(--warning); }
        .circ-progress.status-healthy .circ-progress-fill { stroke:var(--success); }
        .circ-progress.on-dark .circ-progress-track { stroke:rgba(255,255,255,0.25); }
        .circ-progress.on-dark .circ-progress-fill { stroke:var(--text-on-accent); }
        .circ-progress-label { position:absolute; font-weight:700; font-size:var(--fs-body); color:var(--text1); }
        .circ-progress-label.on-dark { color:var(--text-on-accent); }
        .circ-progress-animate .circ-progress-fill { transition:stroke-dashoffset var(--dur-slow) var(--ease-standard); }
        .heatmap-cell { border-radius:var(--radius-xs); box-sizing:border-box; display:flex; align-items:center; justify-content:center; border:1px solid transparent; opacity:1; font-weight:400; }
        .heatmap-cell.heat-none { background:var(--bg3,#eee); color:var(--heat-text-off); }
        .heatmap-cell.heat-poor { background:var(--heat-scale-poor); color:var(--heat-text-on); }
        .heatmap-cell.heat-low { background:var(--heat-scale-low); color:var(--heat-text-on); }
        .heatmap-cell.heat-avg { background:var(--heat-scale-avg); color:var(--heat-text-off); }
        .heatmap-cell.heat-verygood { background:var(--heat-scale-verygood); color:var(--heat-text-on); }
        .heatmap-cell.heat-excellent { background:var(--heat-scale-excellent); color:var(--heat-text-on); }
        .heatmap-cell.is-today { border:2px solid var(--accent); font-weight:700; }
        .heatmap-legend { display:flex; gap:var(--space-9); flex-wrap:wrap; align-items:center; font-size:var(--fs-micro); color:var(--text3); margin-top:var(--space-6); }
        .heatmap-legend-item { display:flex; align-items:center; gap:var(--space-3); }
        .heatmap-legend-swatch { width:9px; height:9px; border-radius:var(--radius-xs); display:inline-block; flex-shrink:0; }
        .heatmap-legend-swatch.heat-none { background:var(--bg3,#eee); }
        .heatmap-legend-swatch.heat-poor { background:var(--heat-scale-poor); }
        .heatmap-legend-swatch.heat-low { background:var(--heat-scale-low); }
        .heatmap-legend-swatch.heat-avg { background:var(--heat-scale-avg); }
        .heatmap-legend-swatch.heat-verygood { background:var(--heat-scale-verygood); }
        .heatmap-legend-swatch.heat-excellent { background:var(--heat-scale-excellent); }
        .heatmap-cell.is-future { border:1px dashed var(--border); opacity:0.55; }

        /* Hero budget progress */

        /* Color helpers */
        .fin-green { color:#4ecf7a; }
        .fin-red   { color:#ff6b6b; }
        .fin-amber { color:#ffd166; }

        /* Quick Actions */
        /* fin-quick-actions + expense/income/transfer variants اتشالوا مع
           أزرار الداشبورد الأربعة (Finance UX Redesign 2026-07-17) —
           fin-quick-btn/fin-quick-account لسه مستخدمين لأزرار "+ حساب/موازنة/هدف/فاتورة". */
        .fin-quick-btn { display:flex; flex-direction:column; align-items:center; gap:var(--space-4); padding:var(--space-10) 6px; border:none; border-radius:var(--radius); font-family:inherit; font-size:var(--fs-label); font-weight:600; cursor:pointer; transition:transform var(--dur-instant) var(--ease-standard),box-shadow var(--dur-instant) var(--ease-standard); }
        .fin-quick-btn:active { transform:scale(0.95); }
        .fin-quick-account  { background:rgba(var(--accent-rgb),0.1); color:var(--accent); }
        body.dark .fin-quick-account  { background:rgba(var(--accent-rgb),0.18); }

        /* Section headers */
        .fin-section-header { display:flex; justify-content:space-between; align-items:center; margin-bottom:var(--space-10); }
        .fin-section-title { font-size:var(--fs-heading-sm); font-weight:700; color:var(--text1); }
        .fin-section-link { border:none; background:none; color:var(--accent); font-size:var(--font-size-12); font-family:inherit; cursor:pointer; padding:0; }

        /* Transaction list */
        .fin-tx-list { display:flex; flex-direction:column; gap:var(--space-6); }
        .fin-tx-card { display:flex; align-items:center; gap:var(--space-10); background:var(--bg2); border-radius:var(--radius); padding:var(--space-10) 12px; border:var(--border-hairline) solid var(--border); transition:transform var(--dur-instant) var(--ease-standard); }
        .fin-tx-card:active { transform:scale(0.98); }
        .fin-tx-icon { width:38px; height:38px; border-radius:var(--radius-md); display:flex; align-items:center; justify-content:center; font-size:var(--font-size-16); flex-shrink:0; }
        .fin-tx-icon-expense  { background:rgba(var(--danger-rgb),0.12); color:var(--danger); }
        .fin-tx-icon-income   { background:rgba(45,122,74,0.12); color:var(--success); }
        .fin-tx-icon-transfer { background:rgba(90,62,138,0.12); color:var(--color-transfer); }
        /* تمييز فوري بين مصروف/دخل/تحويل في نفس القائمة — بوردر جانبي ملوّن +
           تينت خفيف + كلمة النوع، لأن اتجاه الفلوس أهم من شكل الكارد نفسه. */
        .fin-tx-card.fin-tx-card-expense  { border-inline-start:3px solid var(--danger); background:linear-gradient(to left, rgba(var(--danger-rgb),0.045), var(--bg2) 45%); }
        .fin-tx-card.fin-tx-card-income   { border-inline-start:3px solid var(--success); background:linear-gradient(to left, rgba(45,122,74,0.045), var(--bg2) 45%); }
        .fin-tx-card.fin-tx-card-transfer { border-inline-start:3px solid var(--color-transfer); background:linear-gradient(to left, rgba(90,62,138,0.045), var(--bg2) 45%); }
        .fin-tx-type-word { font-weight:700; }
        .fin-tx-card-expense  .fin-tx-type-word { color:var(--danger); }
        .fin-tx-card-income   .fin-tx-type-word { color:var(--success); }
        .fin-tx-card-transfer .fin-tx-type-word { color:var(--color-transfer); }
        .fin-tx-info { flex:1; min-width:0; }
        .fin-tx-desc { font-size:var(--fs-body); font-weight:600; color:var(--text1); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
        .fin-tx-meta { font-size:var(--fs-label); color:var(--text3); margin-top:var(--space-1); }
        .fin-tx-amount { font-size:var(--font-size-15); font-weight:700; flex-shrink:0; }
        .fin-tx-amount-expense  { color:var(--danger); }
        .fin-tx-amount-income   { color:var(--success); }
        .fin-tx-amount-transfer { color:var(--color-transfer); }
        .fin-tx-delete { border:none; background:none; color:var(--text3); cursor:pointer; font-size:var(--fs-heading-sm); padding:var(--space-4); opacity:0.5; transition:opacity var(--dur-fast) var(--ease-standard); }
        .fin-tx-delete:hover { opacity:1; color:var(--danger); }

        /* Filter tabs */
        .fin-filter-tabs { display:flex; gap:var(--space-6); margin-bottom:var(--space-12); overflow-x:auto; scrollbar-width:none; position:sticky; top:var(--sticky-top); background:var(--bg); z-index:5; padding:var(--space-6) 0; }
        .fin-filter-tabs::-webkit-scrollbar { display:none; }
        /* Wrapping variant for a static "pick one" button row (e.g. What-If
           scenario-type picker) that isn't a scrolling filter bar — same
           .fin-filter-tab pill buttons, but wraps to further lines instead
           of overflowing/scrolling past the frame. Kept a separate class
           rather than changing .fin-filter-tabs itself, which real filter
           bars (Transactions/Bills) rely on staying a sticky horizontal
           scroller. */
        .fin-filter-tabs-wrap { display:flex; gap:var(--space-6); margin-bottom:var(--space-12); flex-wrap:wrap; }
        .fin-filter-tab { padding:var(--space-5) 12px; border:var(--border-hairline) solid var(--border); border-radius:20px; font-size:var(--font-size-12); font-family:inherit; background:var(--bg2); color:var(--text2); cursor:pointer; white-space:nowrap; transition:all var(--dur-fast) var(--ease-standard); }
        .fin-filter-tab.active { background:var(--accent); color:var(--text-on-accent); border-color:var(--accent); }

        /* Accounts grid */
        .fin-accounts-grid { display:grid; gap:var(--space-8); }
        .fin-acc-card { background:var(--bg2); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-lg); padding:var(--space-14); display:flex; align-items:center; gap:var(--space-12); transition:transform var(--dur-instant) var(--ease-standard), box-shadow var(--dur-fast) var(--ease-standard); box-shadow:var(--shadow-card); }
        .fin-acc-card:active { transform:scale(0.98); }
        .fin-acc-card:hover { box-shadow:var(--shadow-card-hover); }
        .fin-acc-icon { width:44px; height:44px; background:linear-gradient(135deg,var(--accent),var(--fin-accent-dark)); border-radius:var(--radius); display:flex; align-items:center; justify-content:center; font-size:var(--font-size-20); flex-shrink:0; }
        .fin-acc-info { flex:1; }
        .fin-acc-name { font-size:var(--fs-heading-sm); font-weight:700; color:var(--text1); }
        .fin-acc-type { font-size:var(--fs-label); color:var(--text3); margin-top:var(--space-2); }
        .fin-acc-balance { font-size:var(--fs-heading-md); font-weight:700; color:var(--accent); flex-shrink:0; text-align:left; }
        .fin-acc-balance.negative { color:var(--danger); }

        /* Accounts scroll (dashboard) */
        .fin-accounts-scroll { display:flex; gap:var(--space-10); overflow-x:auto; scrollbar-width:none; padding-bottom:var(--space-4); }
        .fin-accounts-scroll::-webkit-scrollbar { display:none; }
        .fin-acc-mini { min-width:140px; background:var(--bg2); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-lg); padding:var(--space-12); flex-shrink:0; }
        .fin-acc-mini-name { font-size:var(--font-size-12); color:var(--text3); }
        .fin-acc-mini-balance { font-size:var(--fs-heading-md); font-weight:700; color:var(--text1); margin-top:var(--space-4); }
        .fin-acc-mini-type { font-size:var(--fs-caption); color:var(--text3); margin-top:var(--space-2); }

        /* Budget list */
        .fin-budgets-list { display:flex; flex-direction:column; gap:var(--space-8); }
        .fin-budget-card { background:var(--bg2); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-lg); padding:var(--space-14); box-shadow:var(--shadow-card); transition:box-shadow var(--dur-fast) var(--ease-standard); }
        .fin-budget-card:hover { box-shadow:var(--shadow-card-hover); }
        .fin-budget-card-top { display:flex; justify-content:space-between; align-items:center; margin-bottom:var(--space-10); }
        .fin-budget-name { font-size:var(--fs-heading-sm); font-weight:700; color:var(--text1); }
        .fin-budget-pct { font-size:var(--fs-heading-md); font-weight:700; }
        .fin-budget-pct.is-over { color:var(--danger); }
        .fin-budget-pct.is-under { color:var(--accent); }
        .fin-budget-bar-track { height:8px; background:rgba(var(--accent-rgb),0.1); border-radius:var(--radius-sm); overflow:hidden; }
        .fin-budget-bar-fill { height:100%; border-radius:var(--radius-sm); transition:width var(--dur-base) var(--ease-standard); }
        .fin-budget-bar-fill.status-critical, .fin-budget-bar-fill.is-over { background:var(--danger); }
        .fin-budget-bar-fill.status-warning { background:var(--warning); }
        .fin-budget-bar-fill.status-healthy { background:var(--success); }
        .fin-budget-bar-fill.is-under { background:var(--accent); }
        .fin-budget-footer { display:flex; justify-content:space-between; font-size:var(--fs-label); color:var(--text3); margin-top:var(--space-6); }

        /* Goals list */
        .fin-goals-list { display:flex; flex-direction:column; gap:var(--space-8); }
        .fin-goal-card { background:var(--bg2); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-lg); padding:var(--space-14); box-shadow:var(--shadow-card); transition:box-shadow var(--dur-fast) var(--ease-standard); }
        .fin-goal-card:hover { box-shadow:var(--shadow-card-hover); }
        .fin-goal-card-top { display:flex; align-items:center; gap:var(--space-10); margin-bottom:var(--space-10); }
        .fin-goal-icon { width:44px; height:44px; border-radius:var(--radius); display:flex; align-items:center; justify-content:center; font-size:var(--font-size-22); flex-shrink:0; background:rgba(var(--accent-rgb),0.1); }
        .fin-goal-info { flex:1; }
        .fin-goal-name { font-size:var(--fs-heading-sm); font-weight:700; color:var(--text1); }
        .fin-goal-amounts { font-size:var(--fs-label); color:var(--text3); margin-top:var(--space-2); }
        .fin-goal-pct { font-size:var(--font-size-16); font-weight:700; color:var(--accent); flex-shrink:0; }
        .fin-goal-bar-track { height:6px; background:rgba(var(--accent-rgb),0.1); border-radius:var(--radius-sm); overflow:hidden; }
        .fin-goal-bar-fill { height:100%; border-radius:var(--radius-sm); background:linear-gradient(90deg,var(--accent),var(--success)); transition:width var(--dur-base) var(--ease-standard); }
        .fin-goal-footer { display:flex; justify-content:space-between; font-size:var(--fs-label); color:var(--text3); margin-top:var(--space-6); }

        /* Debts list ([T-202]) — reuses .fin-goal-card's layout + progress bar; only the direction stripe
           (same start-edge pattern as .fin-bill-card.overdue), the settled dim, the action row and the
           inline repayment history are new. */
        .fin-debt-card.lent   { border-right:var(--border-medium) solid var(--success); }
        .fin-debt-card.owed   { border-right:var(--border-medium) solid var(--warning); }
        .fin-debt-card.settled { opacity:0.72; }
        .fin-debt-badges { display:flex; flex-wrap:wrap; gap:var(--space-4); margin-top:var(--space-4); }
        .fin-debt-notes { font-size:var(--fs-label); color:var(--text3); margin-top:var(--space-6); }
        .fin-debt-actions { display:flex; align-items:center; flex-wrap:wrap; gap:var(--space-6); margin-top:var(--space-10); }
        .fin-debt-actions .fin-debt-spacer { flex:1; }
        .fin-debt-history { margin-top:var(--space-10); padding-top:var(--space-8); border-top:var(--border-hairline) solid var(--border); }
        .fin-debt-history-row { display:flex; justify-content:space-between; align-items:baseline; gap:var(--space-8); padding:var(--space-4) 0; font-size:var(--fs-label); color:var(--text2); }
        .fin-debt-history-row .fin-debt-history-date { color:var(--text3); }
        .fin-filter-tab-gap { margin-inline-start:var(--space-8); }

        /* Bills list */
        .fin-bills-list { display:flex; flex-direction:column; gap:var(--space-8); }
        .fin-bill-card { background:var(--bg2); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-lg); padding:var(--space-14); box-shadow:var(--shadow-card); transition:box-shadow var(--dur-fast) var(--ease-standard); }
        .fin-bill-card:hover { box-shadow:var(--shadow-card-hover); }
        .fin-bill-card.overdue  { border-right:var(--border-medium) solid var(--danger); }
        .fin-bill-card.upcoming { border-right:var(--border-medium) solid var(--warning); }
        .fin-bill-card-top { display:flex; align-items:flex-start; gap:var(--space-10); }
        .fin-bill-icon { width:40px; height:40px; background:rgba(var(--accent-rgb),0.1); border-radius:var(--radius-md); display:flex; align-items:center; justify-content:center; font-size:var(--fs-heading-md); flex-shrink:0; }
        .fin-bill-info { flex:1; }
        .fin-bill-name { font-size:var(--fs-heading-sm); font-weight:700; color:var(--text1); }
        .fin-bill-meta { font-size:var(--fs-label); color:var(--text3); margin-top:var(--space-2); }
        .fin-bill-amount { font-size:var(--font-size-16); font-weight:700; color:var(--text1); flex-shrink:0; text-align:left; }
        .fin-bill-status { display:inline-flex; align-items:center; gap:var(--space-4); padding:var(--space-2) 8px; border-radius:var(--radius-md); font-size:var(--fs-label); font-weight:600; margin-top:var(--space-4); }
        .fin-bill-status.overdue  { background:rgba(var(--danger-rgb),0.12); color:var(--danger); }
        .fin-bill-status.upcoming { background:rgba(var(--warning-rgb),0.12); color:var(--warning); }
        .fin-bill-status.ok       { background:rgba(45,122,74,0.12); color:var(--success); }
        .fin-bill-actions { display:flex; gap:var(--space-6); margin-top:var(--space-10); }
        .fin-bill-pay { flex:1; padding:var(--space-7); background:var(--accent); color:var(--text-on-accent); border:none; border-radius:var(--radius-sm); font-family:inherit; font-size:var(--font-size-12); font-weight:600; cursor:pointer; transition:background var(--dur-fast) var(--ease-standard); }
        .fin-bill-pay:hover { background:var(--fin-accent-dark); }


        /* Bills alert banner */
        .fin-alert-banner { background:rgba(192,57,43,0.08); border:var(--border-hairline) solid rgba(192,57,43,0.2); border-radius:var(--radius); padding:var(--space-10) 14px; display:flex; align-items:center; gap:var(--space-10); }
        .fin-alert-banner-icon { font-size:var(--icon-glyph-20); flex-shrink:0; }
        .fin-alert-banner-text { font-size:var(--font-size-12); color:var(--danger); font-weight:600; }
        .fin-alert-banner.urgent { background:rgba(var(--color-bill-urgent-rgb),0.08); border-color:rgba(var(--color-bill-urgent-rgb),0.2); }
        .fin-alert-banner-text.urgent-text { color:var(--warning); }

        /* Dark mode overrides */
        body.dark .fin-subnav { background:var(--bg2); }
        body.dark .fin-tx-card,
        body.dark .fin-acc-card,
        body.dark .fin-acc-mini,
        body.dark .fin-budget-card,
        body.dark .fin-goal-card { background:var(--bg2); border-color:var(--border); }
        /* Same-specificity trap (design-tokens skill's Track C, trap #2) —
           the rule above resets border-color for every .fin-tx-card in dark
           mode at a higher tier (body+.dark+.fin-tx-card) than the plain
           two-class .fin-tx-card.fin-tx-card-{expense,income,transfer}
           modifiers below can reach on their own; re-assert the type color
           at the matching higher tier so it survives dark mode too. */
        body.dark .fin-tx-card.fin-tx-card-expense  { border-inline-start-color:var(--danger); }
        body.dark .fin-tx-card.fin-tx-card-income   { border-inline-start-color:var(--success); }
        body.dark .fin-tx-card.fin-tx-card-transfer { border-inline-start-color:var(--color-transfer); }
        /* .fin-bill-card excluded (2026-07-31 Phase 6 fix) — this shorthand
           border-color reset was silently overriding .fin-bill-card.overdue/
           .upcoming's status border-right, and is redundant anyway since
           the base .fin-bill-card rule's border already resolves through
           var(--border) without a dark-mode-specific override. */
        body.dark .fin-bill-card { background:var(--bg2); }
        /* ===== UTILITY CLASSES (Track A, Batch 1 — 2026-08-27) =====
           Atomic single-purpose classes replacing repeated inline style=""
           declarations. Each class does exactly one thing and composes with
           the others on the same element (e.g. class="u-flex-1 u-mb-8").
           Not for one-off/rare declarations — only values already repeated
           across many inline style="" sites qualify here. See
           docs/DESIGN_SYSTEM.md for the full pattern-reference entry.
           Placed LAST in this <style> block deliberately — an inline
           style="" (what these replace) always wins the cascade regardless
           of source order, so these must also win any same-specificity
           single-class rule defined earlier (e.g. .tag-pill's own
           font-size/cursor) to stay a zero-behavior-change swap. A
           same-or-higher-specificity multi-class/compound rule can still
           beat these — checked per-site during this batch, not assumed. */
        .u-hidden { display:none; }
        .btn-inline.u-hidden, .u-flex-gap-8.u-hidden { display:none; } /* these two have their own display rule later in the file */
        .u-w-0 { width:0%; }
        .u-contents { display:contents; }
        .u-text-left { text-align:left; }
        .u-relative { position:relative; }
        .u-text-center { text-align:center; }
        .u-ms-auto { margin-inline-start:auto; }
        .u-cursor-pointer { cursor:pointer; }
        .u-w-full { width:100%; }
        .u-flex-1 { flex:1; }
        .u-flex-2 { flex:2; }
        .u-flex-none { flex:none; }
        .u-flex-shrink-0 { flex-shrink:0; }
        .u-min-w-0 { min-width:0; }
        .u-text-muted { color:var(--text3); }
        .u-text-danger { color:var(--danger); }
        .u-text-success { color:var(--success); }
        .u-text-warning { color:var(--warning); }
        .u-text-accent { color:var(--accent); }
        .u-text-gold { color:var(--gold); }
        .u-bg-muted { background:var(--text3); }
        .u-bg-warning { background:var(--warning); }
        .u-bg-success { background:var(--success); }
        .u-text-secondary { color:var(--text2); }
        .u-text-cat-habit { color:var(--color-cat-habit); }
        .u-text-cat-project { color:var(--color-cat-project); }
        .u-text-cat-account { color:var(--color-cat-account); }
        .u-text-cat-idea { color:var(--color-cat-idea); }
        .u-text-cat-knowledge { color:var(--color-cat-knowledge); }
        .u-text-cat-system { color:var(--color-cat-system); }
        .u-text-ambition-draft { color:var(--color-ambition-draft); }
        .u-text-ambition-active { color:var(--color-ambition-active); }
        .u-text-ambition-abandoned { color:var(--color-ambition-abandoned); }
        .u-bg-border { background:var(--border); }
        .u-bg-idea-raw { background:var(--color-idea-raw); }
        .u-bg-idea-exploring { background:var(--color-idea-exploring); }
        .u-bg-idea-converted { background:var(--color-idea-converted); }
        .u-bg-idea-archived { background:var(--color-idea-archived); }
        .u-bg-danger { background:var(--danger); }
        .u-bg-relation-extends { background:var(--color-relation-extends); }
        .u-bg-relation-related { background:var(--color-relation-related); }
        .u-bg-relation-similar { background:var(--color-relation-similar); }
        .u-bg-relation-conflicts { background:var(--color-relation-conflicts); }
        /* Inline-style cleanup, Part B (2026-09-09) — component classes replacing
           JS-built inline style="" attributes that already referenced tokens;
           pure organizational move, no rendered value changes. */
        .input-dialog-color-field { width:100%; height:36px; padding:var(--space-2); margin-bottom:var(--space-8); }
        /* Counter circles share the title's row ([T-238]): the title truncates, the circle group wraps inside a capped width so it can never push the card wider. Logical props only (RTL). */
        .tl-task-name-row { display:flex; align-items:flex-start; gap:var(--space-2); min-width:0; }
        .tl-task-name-row > .tl-task-name { flex:1 1 0; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
        .tl-habit-count-circle { cursor:pointer; font-size:var(--fs-heading-sm); display:inline-flex; align-items:center; justify-content:center; min-inline-size:24px; min-block-size:24px; }
        .tl-habit-count-row { display:flex; align-items:center; justify-content:flex-end; flex-wrap:wrap; flex:0 1 auto; max-inline-size:70%; gap:0; }
        .mood-picker-btn { font-size:var(--fs-heading-md); padding:var(--space-6) 10px; }
        .dash-empty.tight { padding:var(--space-4) 0; }
        .tm-stats-row { display:flex; gap:var(--space-10); flex-wrap:wrap; font-size:var(--fs-label); color:var(--text3); margin-bottom:var(--space-6); }
        .tm-suggestion-row { display:flex; justify-content:space-between; align-items:center; gap:var(--space-8); flex-wrap:wrap; }
        .tm-bulk-bar { display:flex; justify-content:space-between; align-items:center; background:var(--bg3); border-radius:var(--radius-sm); padding:var(--space-6) 10px; margin-bottom:var(--space-6); font-size:var(--fs-label); }
        .sm-stage-item { flex-direction:column; align-items:flex-start; gap:var(--space-6); }
        .sm-stage-order { font-size:var(--fs-label); color:var(--text3); min-width:20px; }
        .sm-stage-name-input { border:none; background:transparent; font-weight:600; font-size:var(--font-size-16); color:var(--text1); padding:var(--space-2) 4px; border-radius:var(--radius-xs); width:140px; }
        .ws-suggestion-card { background:var(--bg2); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-md); padding:var(--space-10) 12px; margin-bottom:var(--space-10); }
        .ws-suggestion-btn { flex:1; padding:var(--space-6); font-size:var(--font-size-12); }
        /* Inline-style cleanup, Part B batch 2 (2026-09-09) — ui-settings-pillars,
           ui-task, ui-undo-redo. */
        .pm-health-warning-block { margin-bottom:var(--space-8); border-color:var(--warning); }
        .pm-health-issues-title { font-weight:600; margin-bottom:var(--space-4); }
        .dash-empty.roomy { padding:var(--space-24); }
        .pm-ambition-status-dot { font-size:var(--fs-caption); }
        .task-day-label { font-size:var(--fs-label); color:var(--text2); }
        .selected-tag-chip { font-size:var(--fs-label); padding:var(--space-2) 6px; }
        .hier-sep-tasklist { margin-top:var(--space-2); padding-top:var(--space-6); }
        .hier-task-list-scroll { display:flex; flex-direction:column; gap:var(--space-3); max-height:120px; overflow-y:auto; }
        .hier-sep-depchips { display:flex; flex-wrap:wrap; gap:var(--space-4); margin-top:var(--space-8); padding-top:var(--space-6); }
        .dep-chip-selected { font-size:var(--fs-caption); padding:var(--space-2) 8px; cursor:pointer; }
        .add-custom-date-btn { padding:var(--space-4) 8px; border:var(--border-hairline) solid var(--border); border-radius:var(--radius-xs); background:var(--bg3); cursor:pointer; }
        .undo-empty-note { padding:var(--space-16) 0; }
        .undo-empty-note-sub { font-size:var(--fs-label); margin-top:var(--space-4); }
        .undo-restore-label { display:inline-flex; align-items:center; justify-content:center; gap:var(--space-6); width:100%; }
        .undo-history-entry { flex-direction:column; align-items:flex-start; gap:var(--space-4); border-right:var(--border-medium) solid var(--op-color); }
        .undo-entry-header-row { display:flex; justify-content:space-between; width:100%; align-items:center; gap:var(--space-6); }
        .undo-entry-title-row { display:flex; align-items:center; gap:var(--space-6); min-width:0; flex:1; }
        .undo-entry-affected-name { font-weight:700; font-size:var(--fs-body); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
        .undo-restore-btn { width:100%; margin-top:var(--space-4); padding:var(--space-8); font-weight:700; }
        /* Inline-style cleanup, Part B batch 3 (2026-09-09) — ui-backlog,
           ui-calendar-devtools, ui-settings. */
        .backlog-show-more-btn { width:100%; margin-top:var(--space-6); margin-bottom:var(--space-220); font-size:var(--font-size-12); padding:var(--space-6) 10px; }
        .bulk-bar-header { display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-6); position:sticky; top:var(--sticky-top); z-index:2; background:var(--bg2); }
        .bulk-selected-count-label { font-size:var(--font-size-12); font-weight:600; flex-basis:100%; }
        .inbox-zero-emoji { font-size:var(--font-size-28); margin-bottom:var(--space-4); }
        .inbox-zero-title { font-weight:600; margin-bottom:var(--space-4); }
        .inbox-zero-close-btn { background:none; border:none; color:var(--text3); cursor:pointer; font-size:var(--fs-heading-sm); padding:0; }
        .inbox-zero-task-text { font-size:var(--font-size-15); font-weight:600; margin-bottom:var(--space-12); }
        .hier-group-subtrack { font-size:var(--fs-label); color:var(--text3); padding-right:var(--space-20); }
        .hier-group-project { font-size:var(--fs-label); color:var(--text2); padding-right:var(--space-30); cursor:pointer; }
        .backlog-item-actions { display:flex; gap:var(--space-3); flex-shrink:0; }
        .backlog-badges-row { margin-top:var(--space-3); }
        .cal-day-bill-marker { font-size:var(--font-size-7); color:var(--color-bills); display:block; line-height:1; }
        .cal-day-bills-title { font-size:var(--font-size-12); font-weight:600; color:var(--color-bills); margin-top:var(--space-6); }
        .cal-day-periodic-badge { font-size:var(--fs-micro); color:var(--text3); margin-right:var(--space-4); }
        .cal-day-ungrouped-title { font-size:var(--fs-label); color:var(--text3); margin-top:var(--space-8); margin-bottom:var(--space-3); }
        .dh-cleanup-preview-text { margin:var(--space-2) 0 6px; padding-right:var(--space-8); font-size:var(--fs-label); color:var(--text2); }
        .dh-section-title { font-size:var(--fs-label); font-weight:600; color:var(--text3); margin-bottom:var(--space-4); }
        .dh-check-now-btn { width:100%; margin:var(--space-6) 0; }
        .dh-issue-preview-block { margin:var(--space-2) 0 6px; padding-right:var(--space-8); }
        .dh-issue-item-row { display:flex; justify-content:space-between; align-items:center; gap:var(--space-6); font-size:var(--fs-label); color:var(--text2); padding:var(--space-2) 0; }
        .dh-all-clean-msg { font-size:var(--font-size-12); color:var(--success); }
        .dh-cleanup-title { font-size:var(--fs-label); font-weight:600; color:var(--text3); margin:var(--space-12) 0 4px; }
        .lm-manual-default-label { margin-inline-start:var(--space-4); }
        .backlog-item-row-flex { display:flex; justify-content:space-between; align-items:center; gap:var(--space-8); }
        .lm-arrow-sep { color:var(--text3); font-weight:400; }
        .lm-status-caption { font-size:var(--fs-caption); }
        .lm-empty-state { text-align:center; padding:var(--space-18) 12px; color:var(--text3); font-size:var(--font-size-12); }
        .focus-duration-suggestion { font-size:var(--fs-label); color:var(--text3); display:flex; align-items:center; gap:var(--space-6); margin:-4px 0 var(--space-6); }
        .about-version-card { text-align:center; padding:var(--space-18) 12px; }
        .about-version-label { font-size:var(--fs-label); color:var(--text3); font-weight:600; margin-bottom:var(--space-4); }
        .about-version-number { font-size:var(--font-size-20); font-weight:700; color:var(--text1); }
        .about-info-text { color:var(--text2); font-size:var(--font-size-12); }
        /* Cross-Device Sync Phase 5, Step 5.3 — the Redirect URI the user
           copies into their own Google Cloud OAuth Client config. */
        .sync-redirect-uri-row { display:flex; align-items:center; gap:var(--space-8); flex-wrap:wrap; }
        .sync-redirect-uri-row code { background:var(--bg3); border-radius:var(--radius-sm); padding:2px 6px; font-size:var(--font-size-12); word-break:break-all; }
        /* Inline-style cleanup, Part B batch 4 (2026-09-09) — ui-knowledge.
           NOTE: assets/js/thinking/ui-knowledge.js:1261's
           background:var(--accent-rgb,13,110,110,0.13) is a pre-existing bug
           (invalid CSS — computes to fully transparent, confirmed via
           getComputedStyle), left untouched pending a decision on the fix. */
        .knowledge-hero-headline { font-size:var(--font-size-17); line-height:1.4; }
        .knowledge-discovery-row { margin-bottom:var(--space-10); display:flex; align-items:center; justify-content:space-between; gap:var(--space-8); flex-wrap:wrap; }
        .knowledge-new-item-btn { width:100%; margin-bottom:var(--space-14); }
        .knowledge-graph-clear-highlight { padding:var(--space-4) 0; font-size:var(--fs-label); color:var(--accent,#0D6E6E); cursor:pointer; }
        .knowledge-graph-line-row { display:flex; align-items:center; justify-content:space-between; gap:var(--space-6); padding:var(--space-4) 0; font-size:var(--font-size-12); }
        .knowledge-graph-line-action { cursor:pointer; color:var(--accent,#0D6E6E); white-space:nowrap; font-size:var(--fs-label); }
        .knowledge-reader-title-row { display:flex; align-items:flex-start; justify-content:space-between; gap:var(--space-8); }
        .knowledge-linked-section { margin-top:var(--space-10); padding-top:var(--space-8); border-top:var(--border-hairline) solid var(--border); }
        .knowledge-linked-section-title { font-size:var(--fs-caption); color:var(--text3); text-transform:uppercase; letter-spacing:0.04em; margin-bottom:var(--space-4); }
        .knowledge-cat-row-count { color:var(--text3); font-weight:400; }
        .knowledge-mgr-add-btn { width:100%; margin-top:var(--space-10); }
        /* Inline-style cleanup, Part B batch 5 (2026-09-09) — ui-habit. */
        .neg-habit-item { flex-direction:column; align-items:flex-start; gap:var(--space-8); }
        .neg-habit-streak { font-size:var(--font-size-12); margin-right:var(--space-6); }
        .neg-habit-actions { display:flex; gap:var(--space-4); align-items:center; }
        .habit-risk-icon { color:var(--warning); }
        .habit-trend-up { font-size:var(--fs-caption); color:var(--success); }
        .habit-row-actions-single { display:flex; align-items:center; gap:var(--space-6); }
        .habit-row-actions-multi { display:flex; align-items:center; gap:var(--space-4); }
        .habit-stat-card { background:var(--bg2); border-radius:var(--radius-sm); padding:var(--space-8) 10px; }
        .habit-stat-card-label { font-size:var(--fs-caption); color:var(--text3); margin-bottom:var(--space-2); }
        .habit-stat-card-value { font-size:var(--font-size-15); font-weight:600; }
        .habit-multi-time-row { display:flex; align-items:center; gap:var(--space-6); margin-bottom:var(--space-4); }
        .habit-multi-time-label { font-size:var(--fs-label); color:var(--text3); }
        /* Inline-style cleanup, Part B batch 6 (2026-09-09) — engines-navigation.
           NOTE: assets/js/engines-navigation.js:1592 (the 44px palette-swatch
           tap target) deliberately left inline per its own code comment
           ("Set here, NOT in CSS") -- not converted. */
        .nav-gate-desc { margin:calc(-1 * var(--space-4)) 0 var(--space-8) var(--space-2); }
        .fab-speed-dial-btn { width:100%; padding:var(--space-14) 16px; margin-bottom:var(--space-8); background:var(--bg2); color:var(--text1); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-md); font-family:inherit; font-size:var(--fs-heading-sm); font-weight:600; cursor:pointer; display:flex; align-items:center; gap:var(--space-10); }
        .fab-speed-dial-icon { font-size:var(--icon-glyph-20); }
        .nav-favorites-empty { font-size:var(--fs-label); padding:var(--space-4) 0; }
        .nav-item-clickable-row { display:flex; align-items:center; gap:var(--space-10); flex:1; min-width:0; cursor:pointer; }
        .nav-recent-empty { font-size:var(--font-size-12); padding:var(--space-14) 4px; text-align:center; }
        .nav-recent-empty-sub { font-size:var(--fs-label); color:var(--text3); margin-top:var(--space-4); }
        .nav-recent-group-title { font-size:var(--fs-caption); color:var(--text3); font-weight:700; margin:var(--space-8) 0 4px; display:flex; align-items:center; gap:var(--space-4); }
        .hier-crumb-clickable { cursor:pointer; color:var(--text1); font-weight:600; }
        .hier-crumb-static { color:var(--text1); font-weight:600; }
        .theme-palette-swatch-check { color:var(--text-on-accent); display:flex; }
        /* Inline-style cleanup, Part B+C batch 7 (2026-09-09) — ui-export-import
           (Master Excel Import preview). Also fixes 2 real Part C literals:
           the "estimated total" banner used a raw rgba(21,101,192,...) instead
           of the existing --color-import-info token this exact panel is
           documented as backing; the warning banner used a raw
           rgba(230,81,0,...) instead of the --warning-rgb composite already
           established for this identical background+text pattern elsewhere
           (.status-badge.is-warning, .fin-bill-status.upcoming). */
        .excel-preview-section { background:rgba(var(--accent-rgb),0.07); border-radius:var(--radius-sm); padding:var(--space-12); margin-bottom:var(--space-12); }
        .excel-preview-section-title { font-weight:700; color:var(--accent); margin-bottom:var(--space-8); font-size:var(--fs-heading-sm); }
        .excel-preview-table { width:100%; border-collapse:collapse; font-size:var(--font-size-12); }
        .excel-preview-strong { font-weight:600; color:var(--color-import-strong); }
        .excel-preview-warning-cell { font-weight:600; color:var(--warning); }
        .excel-preview-success-cell { font-weight:600; color:var(--success); }
        .excel-preview-info-cell { font-weight:600; color:var(--color-import-info); }
        .excel-preview-neutral-cell { font-weight:600; color:var(--color-import-neutral); }
        .excel-preview-total-banner { background:color-mix(in srgb, var(--color-import-info) 8%, transparent); border-radius:var(--radius-sm); padding:var(--space-10); margin-bottom:var(--space-12); text-align:center; font-size:var(--fs-body); font-weight:700; color:var(--color-import-info); }
        .excel-preview-warning-banner { background:rgba(var(--warning-rgb),0.08); border:var(--border-hairline) solid rgba(var(--warning-rgb),0.25); border-radius:var(--radius-sm); padding:var(--space-10); font-size:var(--fs-label); color:var(--warning); margin-bottom:var(--space-8); }
        /* Inline-style cleanup, Part B batch 8 (2026-09-09) — ui-notifications-reflection. */
        .notif-dnd-title { font-size:var(--fs-label); color:var(--text3); margin:var(--space-10) 0 4px; }
        .notif-dnd-desc { font-size:var(--fs-caption); color:var(--text3); margin-top:var(--space-4); }
        .notif-center-empty { padding:var(--space-20) 0; text-align:center; }
        .notif-center-empty-sub { font-size:var(--fs-label); color:var(--text3); margin-top:var(--space-4); }
        .notif-center-row { flex-direction:column; align-items:flex-start; gap:var(--space-3); cursor:pointer; }
        .notif-center-row-top { display:flex; justify-content:space-between; width:100%; align-items:center; gap:var(--space-6); }
        .notif-center-row-title-wrap { display:flex; align-items:center; gap:var(--space-6); min-width:0; flex:1; }
        .notif-center-title-text { font-size:var(--fs-body); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
        .notif-unread-dot { width:7px; height:7px; border-radius:50%; background:var(--accent); flex-shrink:0; }
        .notif-center-row-body { font-size:var(--fs-label); color:var(--text2); }
        .notif-center-row-footer { display:flex; justify-content:space-between; width:100%; font-size:var(--fs-caption); color:var(--text3); }
        .refl-section-title { font-size:var(--fs-label); font-weight:600; color:var(--text3); margin-bottom:var(--space-8); }
        .refl-summary-row { display:flex; justify-content:space-between; align-items:center; margin-bottom:var(--space-6); gap:var(--space-8); }
        .refl-summary-input { width:90px; text-align:center; padding:var(--space-3) 6px; border-radius:var(--radius-sm); border:var(--border-hairline) solid var(--border); background:var(--bg3); color:var(--text1); font-family:inherit; font-size:var(--font-size-16); }
        .refl-unfinished-row { display:flex; justify-content:space-between; align-items:center; padding:var(--space-6) 8px; margin-bottom:var(--space-4); gap:var(--space-6); }
        .refl-captured-row { display:flex; justify-content:space-between; align-items:flex-start; padding:var(--space-6) 8px; margin-bottom:var(--space-4); gap:var(--space-6); }
        .refl-captured-time { font-size:var(--fs-caption); color:var(--text3); white-space:nowrap; }
        /* Inline-style cleanup, Part B batch 9 (2026-09-09) — ui-khawatiri.
           NOTE: khawatiriModeGrid_N's display:none stays inline (not moved to
           this class) -- khawatiriModeToggleReveal() reads grid.style.display
           directly (the inline property, not computed style); moving it to a
           class would make grid.style.display read '' initially instead of
           'none', breaking the toggle's first click. Found while converting,
           reverted before committing -- same class of finding as batch 1's
           #moodPicker specificity trap. Confirmed 5 other sites in this
           codebase share the same .style.display-read pattern
           (ui-misc.js:610, ui-reports.js:391, ui-smartcapture.js:531,
           ui-thinkingspace.js:3705/4351) -- none touched by this round yet;
           grep for the element's own .style.display read before converting
           any display:none/block site anywhere in the remaining sweep. */
        .khawatiri-search-input { width:100%; margin-bottom:var(--space-10); padding:var(--space-7) 10px; border-radius:var(--radius-sm); border:var(--border-hairline) solid var(--border); background:var(--bg3); color:var(--text1); font-family:inherit; box-sizing:border-box; }
        .khawatiri-mode-meta-row { font-size:var(--fs-label); color:var(--text3); margin-top:var(--space-6); display:flex; align-items:center; gap:var(--space-6); }
        .khawatiri-mode-change-link { cursor:pointer; text-decoration:underline; }
        .khawatiri-mode-set-prompt { font-size:var(--fs-label); color:var(--text3); margin-top:var(--space-6); cursor:pointer; text-decoration:underline; }
        .khawatiri-session-card { margin-bottom:var(--space-10); padding:var(--space-8); background:var(--bg3); border-radius:var(--radius-sm); border:var(--border-hairline) solid var(--border); }
        .khawatiri-uppercase-label { font-size:var(--fs-caption); color:var(--text3); text-transform:uppercase; letter-spacing:0.04em; margin-bottom:var(--space-4); }
        .khawatiri-session-rawtext { font-size:var(--fs-heading-sm); color:var(--text2); white-space:pre-wrap; }
        .khawatiri-session-summary { font-size:var(--fs-label); color:var(--text2); margin-top:var(--space-4); }
        .khawatiri-mode-grid { gap:var(--space-6); flex-wrap:wrap; margin-top:var(--space-6); }
        .khawatiri-section-heading { font-size:var(--fs-label); color:var(--text3); text-transform:uppercase; letter-spacing:0.04em; margin-bottom:var(--space-6); }
        .khawatiri-section-heading-spaced { font-size:var(--fs-label); color:var(--text3); text-transform:uppercase; letter-spacing:0.04em; margin:var(--space-14) 0 var(--space-6); }
        .khawatiri-continue-btn { width:100%; margin:var(--space-4) 0 var(--space-10); }
        .khawatiri-link-btn { width:100%; margin-top:var(--space-10); }
        .khawatiri-space-link-btn { width:100%; margin-top:var(--space-6); }
        .khawatiri-derived-row { display:flex; align-items:center; gap:var(--space-6); padding:var(--space-6) 8px; border-radius:var(--radius-sm); cursor:pointer; }
        .khawatiri-related-row { display:flex; align-items:center; justify-content:space-between; gap:var(--space-6); padding:var(--space-6) 8px; border-radius:var(--radius-sm); cursor:pointer; }
        .khawatiri-related-row-label { display:flex; align-items:center; gap:var(--space-6); }
        /* Inline-style cleanup, Part B batch 10 (2026-09-09) — ui-project.
           #projWizardTrackRow/#projWizardSubtrackRow use ID selectors, not
           classes: hierPickerRenderTracks()/hierPickerRenderSubtracks()
           (ui-modal-dialog.js) fully overwrite these rows' className on every
           render (tRow.className = '...'), which would silently wipe any
           class-based margin-bottom the moment the row is first shown. An
           ID-scoped rule survives that reassignment; a plain class would not. */
        #projWizardTrackRow { display:none; margin-bottom:var(--space-4); }
        #projWizardSubtrackRow { display:none; margin-bottom:var(--space-8); }
        .proj-detail-hierarchy-row { display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-4); font-size:var(--fs-label); color:var(--text3); margin-bottom:var(--space-8); }
        .proj-detail-hierarchy-current { font-weight:600; color:var(--accent); }
        .proj-detail-actions-row { display:flex; align-items:center; gap:var(--space-6); margin-bottom:var(--space-10); flex-wrap:wrap; }
        .proj-hero-mark-complete-link { color:var(--accent); cursor:pointer; text-decoration:underline; font-weight:600; }
        .proj-tasks-count-title { font-size:var(--font-size-12); font-weight:600; color:var(--text2); margin-bottom:var(--space-6); }
        .proj-tasks-section-title { font-size:var(--fs-label); font-weight:600; color:var(--text3); margin:var(--space-8) 0 var(--space-6); }
        .proj-completed-readonly-row { margin-top:var(--space-8); gap:var(--space-6); }
        .proj-quick-add-row { display:flex; gap:var(--space-6); align-items:center; margin-top:var(--space-6); }
        .proj-history-toggle-row { cursor:pointer; font-size:var(--fs-label); font-weight:600; color:var(--text3); }
        .proj-history-hint { font-size:var(--fs-label); color:var(--text3); margin:var(--space-4) 8px; }
        .proj-history-item-row { padding:var(--space-4) 8px; }
        .proj-add-notes-link { color:var(--accent); cursor:pointer; text-decoration:underline; }
        .proj-notes-text { font-size:var(--fs-body); color:var(--text1); white-space:pre-wrap; line-height:1.6; }
        .proj-edit-notes-btn { margin-top:var(--space-10); }
        .qt-row { display:flex; gap:var(--space-6); align-items:center; margin-bottom:var(--space-6); }
        .qt-row-delete-btn { color:var(--danger); }
        .proj-preview-desc { font-size:var(--font-size-12); color:var(--text2); background:var(--bg2); border-radius:var(--radius-sm); padding:var(--space-8) 10px; margin-bottom:var(--space-8); }
        .proj-preview-upcoming-title { font-size:var(--fs-label); font-weight:600; color:var(--text3); margin-top:var(--space-8); margin-bottom:var(--space-4); }
        .pmgr-sort-label { font-size:var(--fs-label); color:var(--text3); align-self:center; margin-left:var(--space-4); }
        .pmgr-bulk-bar { display:flex; justify-content:space-between; align-items:center; background:var(--bg3); border-radius:var(--radius-sm); padding:var(--space-6) 10px; margin-bottom:var(--space-6); font-size:var(--fs-label); flex-wrap:wrap; gap:var(--space-6); }
        .pmgr-row-title-wrap { display:flex; align-items:center; gap:var(--space-6); min-width:0; flex:1; }
        .pmgr-progress-wrap { margin-top:var(--space-4); }
        /* Inline-style cleanup, Part B+C batch 11 (2026-09-09) — ui-finance. */
        .fin-cat-row { display:flex; align-items:center; justify-content:space-between; gap:var(--space-8); padding:var(--space-8) 10px; border:var(--border-hairline) solid var(--border); border-radius:var(--radius-sm); margin-bottom:var(--space-6); background:var(--bg2); }
        .fin-cat-delete-btn { color:var(--danger); }
        .fin-cat-add-btn { width:100%; margin-top:var(--space-10); }
        .bill-date-chip { font-size:var(--fs-caption); padding:var(--space-2) 8px; cursor:pointer; }
        .fin-budget-bar-row { display:flex; align-items:center; gap:var(--space-12); }
        .fin-budget-bar-label { font-size:var(--font-size-12); opacity:0.85; }
        .fin-budget-bar-sublabel { font-size:var(--fs-label); opacity:0.7; margin-top:var(--space-2); }
        .fin-acc-mini-icon { font-size:var(--icon-glyph-20); margin-bottom:var(--space-4); }
        .fin-acc-last-activity { font-size:var(--fs-caption); color:var(--text3); margin-top:var(--space-2); }
        .fin-acc-row-actions { display:flex; justify-content:flex-end; gap:var(--space-4); margin-top:var(--space-4); }
        .fin-insight-row { background:rgba(var(--accent-rgb),0.05); border-radius:var(--radius-sm); padding:var(--space-8) 10px; margin-bottom:var(--space-6); }
        .fin-budget-scope-label { font-size:var(--fs-label); color:var(--text3); margin-top:var(--space-2); }
        .fin-budget-pct-wrap { display:flex; flex-direction:column; align-items:flex-end; gap:var(--space-3); }
        .fin-budget-row-actions { display:flex; justify-content:flex-end; gap:var(--space-6); margin-top:var(--space-8); }
        .fin-goal-mode-tag { font-size:var(--fs-caption); color:var(--text2); margin-top:var(--space-2); }
        .fin-goal-stat-card { background:var(--bg2); border-radius:var(--radius-md); padding:var(--space-8) 10px; }
        .fin-goal-stat-value { font-size:var(--fs-heading-sm); font-weight:700; color:var(--text1); }
        .fin-contrib-amount { font-weight:600; color:var(--text1); }
        .fin-contrib-note { font-size:var(--fs-label); color:var(--text3); margin-top:var(--space-2); }
        .fin-contrib-running-total { font-size:var(--fs-caption); color:var(--text3); margin-top:var(--space-2); }
        /* Inline-style cleanup, Part B batch 12 (2026-09-09) — ui-automation. */
        .am-dashboard-row { display:flex; gap:var(--space-10); flex-wrap:wrap; font-size:var(--fs-label); color:var(--text3); margin-bottom:var(--space-8); }
        .am-search-input { width:100%; margin-bottom:var(--space-6); padding:var(--space-7) 10px; border-radius:var(--radius-sm); border:var(--border-hairline) solid var(--border); background:var(--bg3); color:var(--text1); font-family:inherit; font-size:var(--font-size-16); box-sizing:border-box; }
        .am-rule-card { flex-direction:column; align-items:stretch; gap:var(--space-6); }
        .am-rule-card-top { display:flex; justify-content:space-between; align-items:flex-start; gap:var(--space-6); }
        .am-rule-card-title-wrap { min-width:0; display:flex; gap:var(--space-6); align-items:flex-start; }
        .am-rule-name { font-weight:600; font-size:var(--fs-body); }
        .am-rule-natural-lang { font-size:var(--fs-label); color:var(--text3); margin-top:var(--space-2); }
        .am-rule-exec-stats { font-size:var(--fs-caption); color:var(--text3); margin-top:var(--space-2); }
        .am-staged-action-row { justify-content:space-between; padding:var(--space-4) 8px; }
        .am-advanced-form-box { margin-top:var(--space-10); padding:var(--space-10); background:var(--bg3); border-radius:var(--radius-sm); border:var(--border-hairline) solid var(--border); }
        .am-advanced-form-title { font-size:var(--font-size-12); font-weight:600; margin-bottom:var(--space-8); color:var(--text2); }
        .am-add-to-chain-btn { width:100%; padding:var(--space-6); margin-bottom:var(--space-10); }
        .am-save-rule-btn { width:100%; padding:var(--space-7); }
        .am-library-card { justify-content:space-between; align-items:flex-start; gap:var(--space-8); }
        .am-library-card-icon-wrap { display:flex; gap:var(--space-8); align-items:flex-start; }
        .am-library-cards-col { display:flex; flex-direction:column; gap:var(--space-6); margin-bottom:var(--space-14); }
        /* Inline-style cleanup, Part B+C batch 13 (2026-09-09) — ui-thinkingspace.
           NOTE: lines 2547/2550 (alignment-guide divs, per-drag-frame position
           + zoom-compensated border-width) deliberately left fully inline --
           almost every value is dynamic per the existing design-tokens skill
           guidance that a continuous per-instance computed value has no class
           consumer worth bridging. NOTE: .ts-box-select-rect's
           background:rgba(31,111,92,0.1) is NOT converted to --color-cat-knowledge
           despite the identical hex (#1F6F5C) -- a box-select drag rectangle
           and a Knowledge category tint are unrelated semantics, matching hex
           is not evidence of matching meaning (this file's own established
           rule). Left as a literal, used only once. */
        .ts-status-stepper { display:flex; align-items:center; gap:var(--space-4); margin-bottom:var(--space-8); }
        .ts-most-recent-pill { background:rgba(var(--accent-rgb),0.14); color:var(--accent); }
        body.dark .tag-pill.ts-most-recent-pill { background:rgba(var(--accent-rgb),0.14); color:var(--accent); }
        .ts-space-row { cursor:pointer; margin-bottom:var(--space-8); }
        .ts-archive-toggle { text-align:center; margin:var(--space-10) 0; }
        .ts-type-cards-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(140px,1fr)); gap:var(--space-8); margin-bottom:var(--space-14); }
        .ts-link-badge-row { padding:var(--space-4) 8px; font-size:var(--fs-label); color:var(--text3); border-bottom:var(--border-hairline) solid var(--border); display:flex; align-items:center; gap:var(--space-4); }
        .ts-link-badge-link { cursor:pointer; color:var(--accent,#0D6E6E); text-decoration:underline; }
        .dash-card.ts-hero-card { margin:0 var(--space-8) var(--space-8); padding:var(--space-8) 10px; border-inline-start:var(--border-medium) solid var(--space-accent); }
        body.dark .dash-card.ts-hero-card { border-inline-start-color:var(--space-accent); }
        .ts-hero-icon { color:var(--space-accent); }
        .ts-decision-support-card { margin:0 var(--space-8) var(--space-8); padding:var(--space-8) 10px; }
        .ts-decision-support-title { font-size:var(--fs-label); font-weight:600; color:var(--text3); margin-bottom:var(--space-4); }
        .ts-legend-row { display:flex; flex-wrap:wrap; gap:var(--space-10); padding:var(--space-6) 8px; border-bottom:var(--border-hairline) solid var(--border); font-size:var(--fs-label); color:var(--text3); }
        .ts-legend-item { display:flex; align-items:center; gap:var(--space-4); }
        .ts-link-selected-badge { margin-top:var(--space-8); display:inline-flex; align-items:center; gap:var(--space-4); }
        .ts-project-picker-card { margin-bottom:var(--space-6); }
        .ts-tight-margin { margin:0 0 var(--space-6); }
        .ts-section-title-spaced { margin:var(--space-10) 0 var(--space-6); }
        .ts-pill-row-spaced { display:flex; flex-wrap:wrap; margin-top:var(--space-8); }
        .ts-summary-stat-value { font-size:var(--font-size-16); font-weight:700; }
        .ts-summary-blocks-row { display:flex; margin:0 var(--space-8) var(--space-8); padding:var(--space-8) 4px; background:var(--bg2); border-radius:var(--radius-sm); }
        .ts-canvas-back-row { display:flex; align-items:center; gap:var(--space-8); padding:var(--space-8) 8px 4px; }
        .ts-canvas-title-row { margin:0 var(--space-8) var(--space-6); }
        .ts-search-row { display:flex; align-items:center; gap:var(--space-6); padding:var(--space-6) 8px; border-bottom:var(--border-hairline) solid var(--border); }
        .ts-search-input { flex:1; min-width:0; margin-bottom:0; font-size:var(--font-size-16); padding:var(--space-5) 8px; }
        .ts-search-count { font-size:var(--fs-label); color:var(--text3); white-space:nowrap; }
        .ts-advanced-filters-row { flex-wrap:wrap; gap:var(--space-6); padding:var(--space-6) 8px; border-bottom:var(--border-hairline) solid var(--border); }
        .ts-filter-select { width:auto; margin-bottom:0; font-size:var(--font-size-16); padding:var(--space-5) 8px; }
        .ts-viewport { position:relative; overflow:hidden; height:65vh; background:var(--bg2); }
        .ts-box-select-rect { position:absolute; border:1.5px dashed var(--accent); background:rgba(31,111,92,0.1); pointer-events:none; }
        .ts-zoom-indicator { min-width:38px; text-align:center; font-size:var(--fs-label); color:var(--text3); }
        .ts-canvas-hint { position:absolute; left:50%; transform:translateX(-50%); background:var(--bg2); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-sm); padding:var(--space-4) 10px; font-size:var(--fs-label); color:var(--text3); pointer-events:none; z-index:5; }
        .ts-canvas-hint-top { top:6px; }
        .ts-canvas-hint-bottom { bottom:6px; }
        .ts-matrix-body { padding:0 8px 12px; overflow-x:auto; }
        .ts-matrix-table { width:100%; border-collapse:collapse; font-size:var(--font-size-12); }
        .ts-matrix-row-border { border-bottom:var(--border-hairline) solid var(--border); }
        .ts-matrix-th-option { text-align:start; padding:var(--space-6) 4px; min-width:120px; }
        .ts-matrix-th-criterion { padding:var(--space-6) 4px; min-width:70px; font-weight:600; }
        .ts-matrix-weight-label { font-size:var(--fs-micro); color:var(--text3); font-weight:400; }
        .ts-matrix-th-total { padding:var(--space-6) 4px; min-width:60px; }
        .ts-matrix-th-add { padding:var(--space-6) 4px; }
        .ts-matrix-td-option { padding:var(--space-6) 4px; font-weight:600; }
        .ts-matrix-remove-option { cursor:pointer; color:var(--text3); margin-inline-start:var(--space-6); }
        .ts-matrix-td-score { padding:var(--space-4); text-align:center; }
        .ts-matrix-score-select { width:56px; margin-bottom:0; font-size:var(--font-size-16); padding:var(--space-3); }
        .ts-matrix-td-total { padding:var(--space-6) 4px; text-align:center; font-weight:700; }
        .ts-matrix-add-option-btn { margin-top:var(--space-10); font-size:var(--font-size-12); padding:var(--space-6) 14px; }
        .ts-tree-cell { padding:var(--space-6) 8px; border:var(--border-hairline) solid var(--border); text-align:center; vertical-align:middle; cursor:pointer; }
        .ts-tree-empty-cell { border:var(--border-hairline) solid var(--border); }
        .ts-tree-header-cell { padding:var(--space-6) 8px; border:var(--border-hairline) solid var(--border); text-align:center; vertical-align:middle; font-size:var(--fs-label); color:var(--text3); }
        .ts-tree-section-label { padding:var(--space-6) 8px; border:var(--border-hairline) solid var(--border); font-size:var(--fs-label); color:var(--text3); font-weight:600; }
        .ts-tree-orphan-cell { padding:var(--space-6) 8px; border:var(--border-hairline) solid var(--border); color:var(--text2); cursor:pointer; }
        .ts-tree-crosslink-cell { padding:var(--space-6) 8px; border:var(--border-hairline) solid var(--border); color:var(--text2); }
        .ts-idea-timeline-date { font-size:var(--fs-caption); color:var(--text3); font-weight:600; }
        .ts-danger-popup-item { color:var(--danger); }
        .ts-edge-type-btn { cursor:pointer; display:flex; align-items:center; gap:var(--space-6); text-align:start; }
        /* Inline-style cleanup, Part B+C batch 14 (2026-09-09) — ui-smartcapture.
           Several new classes combine with .tag-pill and set border-color/color
           -- same body.dark .tag-pill specificity trap as prior batches
           (body.dark .tag-pill resets both). Explicit overrides below for
           every combo that sets either property; sc-clarify-btn/sc-why-toggle-pill
           don't touch color and need none. */
        .sc-gold-dashed-btn { cursor:pointer; border:var(--border-hairline) dashed var(--gold); color:var(--gold); }
        body.dark .tag-pill.sc-gold-dashed-btn { border-color:var(--gold); color:var(--gold); }
        .sc-token-input { font-size:var(--font-size-16); padding:var(--space-2) 4px; border-radius:var(--radius-sm); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.3); }
        .sc-token-input-100 { width:100px; }
        /* [T-86] — layout-only wrapper pairing the intent <select> with its
           explicit confirm button. No color/size decision of its own: the
           select keeps .sc-token-input, the button is a plain .btn-inline
           Ghost, and flex-wrap keeps the pair from overflowing a narrow card. */
        .sc-intent-picker-row { display:flex; align-items:center; gap:var(--space-6); flex-wrap:wrap; }
        .sc-item-row { padding:var(--space-8) 0; border-bottom:var(--border-hairline) solid rgba(var(--accent-rgb),0.08); display:flex; align-items:center; gap:var(--space-6); }
        .sc-item-row-plain { padding:var(--space-8) 0; border-bottom:var(--border-hairline) solid rgba(var(--accent-rgb),0.08); }
        .sc-item-row-between { padding:var(--space-8) 0; border-bottom:var(--border-hairline) solid rgba(var(--accent-rgb),0.08); display:flex; align-items:center; justify-content:space-between; gap:var(--space-6); }
        .sc-inline-flex-min0 { display:flex; align-items:center; gap:var(--space-6); min-width:0; }
        .sc-success-icon { color:var(--success); }
        .sc-ellipsis-text { font-size:var(--fs-body); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
        .sc-ellipsis-text-muted { font-size:var(--fs-body); color:var(--text3); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
        .sc-success-caption { font-size:var(--fs-label); color:var(--success); flex-shrink:0; }
        .sc-gold-flex-pill { cursor:pointer; border-color:var(--gold); flex-shrink:0; }
        body.dark .tag-pill.sc-gold-flex-pill { border-color:var(--gold); }
        .sc-understanding-summary-text { font-size:var(--fs-heading-sm); color:var(--text1); margin-bottom:var(--space-8); }
        .sc-develop-heading { font-size:var(--fs-caption); color:var(--text3); text-transform:uppercase; letter-spacing:0.04em; margin:var(--space-8) 0 var(--space-4); }
        .sc-row-gap6-mb6 { display:flex; align-items:center; gap:var(--space-6); margin-bottom:var(--space-6); }
        .sc-fs-label { font-size:var(--fs-label); }
        .sc-gold-pill { cursor:pointer; border-color:var(--gold); }
        body.dark .tag-pill.sc-gold-pill { border-color:var(--gold); }
        .sc-gold-text { color:var(--gold); }
        .sc-why-toggle-pill { cursor:pointer; padding:var(--space-2) var(--space-6); }
        .sc-clean-text-input { width:100%; padding:var(--space-6); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.15); border-radius:var(--radius-sm); font-size:var(--font-size-16); margin-bottom:var(--space-6); box-sizing:border-box; }
        .sc-gold-note { font-size:var(--font-size-16); color:var(--gold); }
        .sc-full-width-16 { width:100%; padding:var(--space-6); font-size:var(--font-size-16); }
        .sc-danger-note { font-size:var(--font-size-16); color:var(--danger); margin-bottom:var(--space-4); }
        .sc-gold-note-mb4 { font-size:var(--font-size-16); color:var(--gold); margin-bottom:var(--space-4); }
        .sc-gold-btn { background:var(--gold); border-color:var(--gold); }
        .sc-why-row { display:flex; justify-content:space-between; gap:var(--space-6); padding:var(--space-2) 0; }
        .sc-why-row-label { color:var(--text3); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
        .sc-why-row-value { text-align:left; flex-shrink:0; }
        .sc-accent-tint-box { background:rgba(var(--accent-rgb),0.05); border-radius:var(--radius-sm); padding:var(--space-6) 8px; margin-bottom:var(--space-6); font-size:var(--font-size-16); }
        .sc-why-summary { font-weight:600; margin-bottom:var(--space-4); }
        .sc-preview-row { display:flex; justify-content:space-between; padding:var(--space-2) 0; }
        .sc-preview-title { font-weight:600; margin-bottom:var(--space-2); }
        .sc-danger-dashed-chip { cursor:pointer; border:var(--border-hairline) dashed var(--danger); color:var(--danger); }
        body.dark .tag-pill.sc-danger-dashed-chip { border-color:var(--danger); color:var(--danger); }
        .sc-clarify-btn { cursor:pointer; margin-inline-start:var(--space-4); }
        .sc-clarify-row { display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-4); margin-bottom:var(--space-6); font-size:var(--fs-label); }
        .sc-accent-dashed-chip { cursor:pointer; border:var(--border-hairline) dashed var(--accent); color:var(--accent); }
        body.dark .tag-pill.sc-accent-dashed-chip { border-color:var(--accent); color:var(--accent); }
        .sc-full-width-12 { width:100%; padding:var(--space-6); font-size:var(--font-size-12); }
        /* Inline-style cleanup, Part B+C batch 15 (2026-09-09) — ui-systems-marketplace.
           .sysmkt-accent-top-card combines with .dash-card and sets border-color
           via border-top -- same body.dark .dash-card specificity trap as prior
           batches, explicit override below. */
        .sysmkt-qa-btn { flex:1; font-size:var(--font-size-12); padding:var(--space-6) 10px; }
        .sysmkt-tint-card { background:var(--bg2); border-radius:var(--radius-sm); margin-bottom:var(--space-10); }
        .sysmkt-meta-row { font-size:var(--fs-caption); color:var(--text3); display:flex; align-items:center; gap:var(--space-4); }
        .sysmkt-fs-caption { font-size:var(--fs-caption); }
        .sysmkt-compact-btn { padding:var(--space-4) 12px; font-size:var(--font-size-12); }
        .sysmkt-check-row { display:flex; align-items:center; gap:var(--space-6); padding:var(--space-4) 0; }
        .sysmkt-check-row-tight { display:flex; align-items:center; gap:var(--space-6); padding:var(--space-3) 0; }
        .sysmkt-border-top-row { padding:var(--space-6) 0; border-top:var(--border-hairline) solid var(--border); }
        .sysmkt-add-btn { width:100%; margin-top:var(--space-8); font-size:var(--font-size-12); padding:var(--space-6) 10px; }
        .sysmkt-section-title-spaced { font-size:var(--fs-label); font-weight:600; color:var(--text3); margin:var(--space-10) 0 var(--space-4); }
        .sysmkt-tint-card-gap { background:var(--bg2); border-radius:var(--radius-sm); margin-bottom:var(--space-10); gap:var(--space-8); }
        /* .modal input/textarea/select (line ~1757) is a generic rule with
           element+class specificity that beats a bare single class here --
           these 4 inputs/textareas all render inside a .modal, so their
           width/padding/margin-bottom/font-size would otherwise silently
           fall back to that generic rule instead of the values their
           inline style="" used to force. Qualified with .modal + element +
           class (2 classes + 1 element) to definitively out-rank it.
           [T-358 P5] That holds for the MARGIN only (the generic margin rule is now (0,1,1)). The generic rule that
           sets width / padding / font-size / border is still (0,3,1) because of its :not() chain, so the width / font-size / padding
           those two rules used to carry never applied; [T-364] deleted them (measured: zero computed-style difference). What stays is
           what is live: margin:0 on the target input, flex:1 on the quick-task input. */
        .modal input.sysmkt-target-input { margin:0; }
        .modal input.sysmkt-quick-task-input { flex:1; }
        .modal textarea.sysmkt-longtext-field { min-height:70px; width:100%; }
        .modal textarea.sysmkt-review-textarea { width:100%; min-height:60px; margin-top:var(--space-6); }
        /* Only #sysHomeQuickTaskInput and #sysMktReviewComment's callers had margin-bottom:0 forced by their
           old inline styles. [T-358 P5] The generic .modal form-field rules above are now (0,1,1), so these
           class rules (0,2,1) win by themselves; the id rule is kept as it was. */
        .modal #sysHomeQuickTaskInput { margin-bottom:0; }
        .sysmkt-installed-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(260px,1fr)); gap:var(--space-10); margin-top:var(--space-8); margin-bottom:var(--space-16); }
        .sysmkt-stats-line { font-size:var(--fs-caption); color:var(--text3); margin-top:var(--space-2); }
        .sysmkt-row-between { display:flex; align-items:center; justify-content:space-between; gap:var(--space-6); }
        .sysmkt-check-label { font-size:var(--fs-label); color:var(--text2); }
        .sysmkt-home-tab-btn { font-size:var(--fs-label); padding:var(--space-4) 10px; }
        .sysmkt-stat-col { cursor:pointer; flex-direction:column; align-items:stretch; gap:var(--space-2); }
        .sysmkt-stat-col-plain { flex-direction:column; align-items:stretch; gap:var(--space-2); }
        .sysmkt-rest-timer-title { font-size:var(--font-size-12); color:var(--text2); display:flex; align-items:center; gap:var(--space-6); }
        .sysmkt-rest-timer-value { font-size:var(--font-size-28); font-weight:700; color:var(--text1); }
        .sysmkt-emoji-16 { font-size:var(--font-size-16); }
        .sysmkt-stat-col-start { flex-direction:column; align-items:flex-start; gap:var(--space-2); }
        .sysmkt-kanban-card { background:var(--bg2); border-radius:var(--radius-sm); padding:var(--space-6) 8px; margin-bottom:var(--space-6); }
        .sysmkt-kanban-card-actions { display:flex; gap:var(--space-2); }
        .sysmkt-kanban-col { flex:1; min-width:140px; background:var(--bg3); border-radius:var(--radius-sm); padding:var(--space-6); }
        .sysmkt-kanban-col-title { font-size:var(--fs-label); font-weight:600; color:var(--text3); margin-bottom:var(--space-6); white-space:nowrap; }
        .sysmkt-kanban-board { display:flex; gap:var(--space-8); overflow-x:auto; padding-bottom:var(--space-8); }
        .sysmkt-record-count-header { font-size:var(--fs-label); font-weight:600; color:var(--text3); margin-bottom:var(--space-8); }
        .sysmkt-timeline-chip { display:flex; align-items:center; gap:var(--space-4); flex-shrink:0; padding:var(--space-4) 8px; background:var(--bg2); border-radius:var(--radius-sm); cursor:pointer; white-space:nowrap; font-size:var(--fs-label); }
        .sysmkt-timeline-chip-dot { width:7px; height:7px; border-radius:50%; flex-shrink:0; }
        .sysmkt-timeline-row { display:flex; gap:var(--space-6); overflow-x:auto; padding-bottom:var(--space-8); margin-bottom:var(--space-10); border-bottom:var(--border-hairline) solid var(--border); }
        .sysmkt-saved-routines-title { font-size:var(--fs-label); font-weight:600; color:var(--text3); margin-bottom:var(--space-6); }
        .sysmkt-spacer-14 { height:var(--space-14); }
        .sysmkt-show-more-btn { width:100%; margin-top:var(--space-6); font-size:var(--font-size-12); padding:var(--space-6) 10px; }
        .sysmkt-prompts-box { background:var(--bg2); border-radius:var(--radius-sm); padding:var(--space-8) 10px; margin-bottom:var(--space-10); font-size:var(--font-size-12); color:var(--text2); }
        .sysmkt-prompts-title { font-weight:600; margin-bottom:var(--space-4); }
        .sysmkt-computed-field { margin-bottom:var(--space-10); padding:var(--space-6) 10px; background:var(--bg2); border-radius:var(--radius-sm); color:var(--text2); font-size:var(--fs-body); }
        .sysmkt-checkbox-label { display:flex; align-items:center; gap:var(--space-6); margin-bottom:var(--space-10); }
        .sysmkt-advanced-toggle-btn { margin:var(--space-4) 0 8px; }
        .sysmkt-stat-col-item { text-align:center; flex:1; }
        .sysmkt-stat-col-value { font-size:var(--fs-heading-md); font-weight:700; }
        .sysmkt-stats-row { display:flex; margin:0 0 var(--space-10); padding:var(--space-8) 4px; background:var(--bg2); border-radius:var(--radius-sm); }
        .sysmkt-home-row { background:var(--bg2); }
        .sysmkt-home-row.just-installed { background:rgba(var(--accent-rgb),0.12); border:var(--border-thin) solid var(--accent); box-shadow:var(--shadow-ring-pulse); }
        .sysmkt-included-row { display:flex; align-items:center; gap:var(--space-4); font-size:var(--fs-label); color:var(--text3); }
        .sysmkt-accent-top-card { margin-bottom:0; border-top:var(--border-medium) solid var(--sys-accent); }
        body.dark .dash-card.sysmkt-accent-top-card { border-top-color:var(--sys-accent); }
        .sysmkt-accent-icon-badge { display:inline-flex; align-items:center; justify-content:center; width:var(--icon-box-22); height:var(--icon-box-22); border-radius:50%; background:color-mix(in srgb, var(--sys-accent) 13%, transparent); color:var(--sys-accent); margin-inline-end:var(--space-4); vertical-align:middle; }
        .sysmkt-detail-section-title { margin-top:var(--space-14); }
        .sysmkt-structure-goal { font-size:var(--fs-label); color:var(--text3); margin-inline-start:var(--space-26); }
        .sysmkt-structure-num-badge { display:inline-flex; align-items:center; justify-content:center; width:18px; height:18px; border-radius:50%; background:var(--bg2); font-size:var(--fs-caption); flex-shrink:0; }
        .sysmkt-preview-task-row { display:flex; align-items:center; gap:var(--space-6); padding:var(--space-3) 0; margin-inline-start:var(--space-22); }
        .sysmkt-preview-project-row { display:flex; align-items:center; gap:var(--space-6); padding:var(--space-4) 0; font-weight:600; font-size:var(--fs-body); }
        .sysmkt-star-btn-sm { min-width:32px; min-height:32px; padding:var(--space-2); }
        .sysmkt-stars-row { display:flex; align-items:center; }
        .sysmkt-review-stars-row { display:flex; align-items:center; gap:var(--space-4); }
        .sysmkt-wizard-hint { font-size:var(--fs-caption); color:var(--text3); margin:calc(-1 * var(--space-4)) 0 var(--space-6); }
        .sysmkt-first-step-row { text-align:center; margin-bottom:var(--space-10); }
        .sysmkt-success-icon-row { text-align:center; padding:var(--space-4) 0 8px; color:var(--success); }
        .sysmkt-success-icon { font-size:var(--fs-display-lg); }
        .sysmkt-success-actions-row { display:flex; gap:var(--space-8); margin-top:var(--space-14); }
        /* Inline-style cleanup, Part B+C batch 16 (2026-09-09) — ui-insights. */
        .ih-subsec-title { font-size:var(--fs-label); font-weight:600; color:var(--text3); margin:var(--space-10) 0 4px; }
        .ih-subsec-title-spaced { font-size:var(--fs-label); font-weight:600; color:var(--text3); margin:var(--space-14) 0 4px; }
        .ih-info-row { display:flex; align-items:center; gap:var(--space-8); padding:var(--space-4) 0; }
        .ih-icon-accent { color:var(--accent); }
        .ih-grid-110 { display:grid; grid-template-columns:repeat(auto-fill,minmax(110px,1fr)); gap:var(--space-8); }
        .ih-stat-col-4 { flex-direction:column; align-items:flex-start; gap:var(--space-4); }
        .ih-fs-body-bold { font-size:var(--fs-body); font-weight:700; }
        .ih-caption-mb2 { font-size:var(--fs-caption); color:var(--text3); margin-bottom:var(--space-2); }
        .ih-highlight-row { display:flex; justify-content:space-between; align-items:center; }
        .ih-highlight-success { border-color:var(--success); }
        .ih-highlight-danger { border-color:var(--danger); }
        .ih-stat-col-2 { flex-direction:column; align-items:flex-start; gap:var(--space-2); }
        .ih-fs-body-600 { font-size:var(--fs-body); font-weight:600; }
        .ih-nba-actions-row { display:flex; gap:var(--space-6); margin-top:var(--space-2); }
        .ih-nba-btn { padding:var(--space-3) 10px; font-size:var(--fs-label); }
        .ih-rarity-label { opacity:.7; font-size:var(--fs-caption); }
        .ih-achievement-row { display:flex; align-items:center; gap:var(--space-10); padding:var(--space-6) 0; border-top:var(--border-hairline) solid var(--border); margin-top:var(--space-4); }
        .ih-achievement-emoji { font-size:var(--icon-glyph-22); line-height:1; color:var(--accent); }
        .ih-intel-card { flex-direction:column; align-items:flex-start; gap:var(--space-6); padding-bottom:var(--space-10); border-bottom:var(--border-hairline) dashed rgba(var(--accent-rgb),0.1); }
        body.dark .dash-stat-row.ih-intel-card { border-bottom-color:rgba(var(--accent-rgb),0.1); }
        .ih-intel-header-row { display:flex; align-items:flex-start; gap:var(--space-8); width:100%; }
        .ih-intel-icon { font-size:var(--icon-glyph-16); flex-shrink:0; }
        .ih-intel-meta { font-size:var(--fs-label); color:var(--text3); padding-right:var(--space-24); }
        .ih-intel-actions { display:flex; gap:var(--space-6); padding-right:var(--space-24); }
        .ih-preview-card { flex-direction:column; align-items:flex-start; gap:var(--space-6); margin-bottom:var(--space-8); }
        .ih-kpi-value { font-size:var(--font-size-16); font-weight:700; }
        .ih-grid-150 { display:grid; grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); gap:var(--space-8); }
        .ih-pillar-name-row { display:flex; align-items:center; gap:var(--space-6); font-weight:600; font-size:var(--fs-body); margin-bottom:var(--space-4); }
        .ih-pillar-health-label { font-size:var(--fs-label); font-weight:600; margin-bottom:var(--space-2); }
        .ih-pillar-pct { font-size:var(--fs-heading-md); font-weight:700; }
        .ih-pillar-momentum { font-size:var(--fs-heading-sm); }
        .ih-text-center { text-align:center; }
        .ih-review-hero { text-align:center; padding:var(--space-10) 0 14px; }
        .ih-review-hero-pct { font-size:var(--fs-display-lg); font-weight:800; color:var(--teal,#0D6E6E); }
        .ih-review-hero-sub { font-size:var(--font-size-12); color:var(--text3); margin-top:var(--space-2); }
        .ih-status-card-count { font-size:var(--font-size-20); font-weight:700; margin-bottom:var(--space-4); }
        .ih-grid-120 { display:grid; grid-template-columns:repeat(auto-fill,minmax(120px,1fr)); gap:var(--space-8); }
        .ih-best-hour-caption { font-size:var(--fs-caption); color:var(--text3); margin:var(--space-4) 0 8px; }
        .ih-mt-4 { margin-top:var(--space-4); }
        .ih-heatmap-summary-row { display:flex; gap:var(--space-14); flex-wrap:wrap; font-size:var(--fs-caption); color:var(--text3); margin-bottom:var(--space-5); }
        .ih-stat-col-6 { flex-direction:column; align-items:flex-start; gap:var(--space-6); }
        .ih-fs-15-600 { font-size:var(--font-size-15); font-weight:600; }
        .ih-nba-actions-row-4 { display:flex; gap:var(--space-6); margin-top:var(--space-4); }
        .ih-subsec-title-6 { font-size:var(--fs-label); font-weight:600; color:var(--text3); margin-bottom:var(--space-6); }
        .ih-subsec-title-8 { font-size:var(--fs-label); font-weight:600; color:var(--text3); margin:var(--space-8) 0 4px; }
        .ih-sample-size { font-size:var(--fs-micro); color:var(--text3); font-weight:400; }
        .ih-top-opp-label { font-size:var(--fs-label); font-weight:700; color:var(--teal,#0D6E6E); margin-bottom:var(--space-4); }
        .ih-decision-detail { padding:0 var(--space-8) var(--space-8); }
        .ih-subsec-title-6b { font-size:var(--fs-label); font-weight:600; color:var(--text3); margin:var(--space-6) 0 4px; }
        .ih-whatif-result-card { flex-direction:column; align-items:flex-start; gap:var(--space-4); background:rgba(var(--accent-rgb),0.06); border-radius:var(--radius-sm); padding:var(--space-8); margin-bottom:var(--space-8); }
        .ih-whatif-impact-label { font-size:var(--fs-caption); font-weight:600; color:var(--teal,#0D6E6E); margin-top:var(--space-2); }
        /* Inline-style cleanup, Part B+C batch 17 (2026-09-09) — ui-achievements. */
        .ach-progress-note { font-size:var(--fs-micro); color:var(--text3); margin-top:var(--space-3); }
        .ach-rarity-badge { font-size:var(--font-size-8); text-transform:uppercase; letter-spacing:.5px; margin-top:var(--space-2); }
        .ach-tile-icon { font-size:var(--fs-stat); margin-bottom:var(--space-4); }
        .ach-title-12-600 { font-size:var(--font-size-12); font-weight:600; color:var(--text1); }
        .ach-tile-desc { font-size:var(--fs-caption); color:var(--text3); margin-top:var(--space-2); }
        .ach-unlocked-date { font-size:var(--fs-micro); color:var(--accent); margin-top:var(--space-4); }
        .ach-req-row { display:flex; justify-content:space-between; font-size:var(--fs-label); padding:var(--space-2) 0; }
        .ach-journey-emoji { font-size:var(--fs-display-lg); }
        .ach-journey-title { font-size:var(--font-size-15); font-weight:600; color:var(--text1); margin-top:var(--space-4); }
        .ach-journey-sub { font-size:var(--fs-label); color:var(--text3); margin-top:var(--space-2); }
        .ach-req-block { text-align:right; margin-top:var(--space-10); border-top:var(--border-hairline) solid var(--border); padding-top:var(--space-8); }
        .ach-label-mb4 { font-size:var(--fs-label); color:var(--text2); margin-bottom:var(--space-4); }
        .ach-timeline-row { display:flex; align-items:center; gap:var(--space-10); background:var(--bg3); border-radius:var(--radius-sm); padding:var(--space-8) 10px; }
        .ach-timeline-icon { font-size:var(--icon-glyph-20); }
        .ach-partial-note { text-align:center; font-size:var(--fs-caption); color:var(--text3); padding:var(--space-6); }
        .ach-narrative-line { font-size:var(--fs-label); color:var(--text2); padding:var(--space-2) 0; }
        .ach-season-card { background:var(--bg3); border-radius:var(--radius-md); padding:var(--space-10) 12px; }
        .ach-season-title { font-size:var(--fs-body); font-weight:600; color:var(--text1); }
        .ach-season-progress-track { height:6px; background:var(--border); border-radius:var(--radius-full); margin-top:var(--space-6); overflow:hidden; }
        .ach-season-stats-grid { display:grid; grid-template-columns:1fr 1fr 1fr; gap:var(--space-6); margin-top:var(--space-8); text-align:center; }
        .ach-stat-num { font-size:var(--fs-heading-sm); font-weight:700; color:var(--text1); }
        .ach-micro-muted { font-size:var(--fs-micro); color:var(--text3); }
        .ach-archive-item { background:var(--bg3); border-radius:var(--radius-sm); padding:var(--space-10); }
        .ach-archive-meta { font-size:var(--fs-label); color:var(--text3); margin-top:var(--space-4); }
        .ach-review-row { display:flex; justify-content:space-between; padding:var(--space-5) 0; border-bottom:var(--border-hairline) solid var(--border); font-size:var(--font-size-12); }
        .ach-review-value { color:var(--text1); font-weight:600; }
        .ach-mt-10 { margin-top:var(--space-10); }
        .ach-review-narrative-line { font-size:var(--font-size-12); color:var(--text2); padding:var(--space-3) 0; }
        .ach-milestone-row { display:flex; align-items:center; gap:var(--space-8); background:var(--bg3); border-radius:var(--radius-sm); padding:var(--space-6) 8px; margin-bottom:var(--space-4); }
        .ach-milestone-text { font-size:var(--fs-label); color:var(--text1); flex:1; }
        .ach-compare-row { display:flex; justify-content:space-between; align-items:center; padding:var(--space-6) 0; border-bottom:var(--border-hairline) solid var(--border); font-size:var(--font-size-12); }
        .ach-compare-value { color:var(--text1); }
        .ach-compare-header { display:flex; justify-content:space-between; font-size:var(--fs-label); color:var(--text3); margin-bottom:var(--space-6); }
        .backlog-item.amgr-item { border-right:var(--border-medium) solid var(--status-color); }
        body.dark .backlog-item.amgr-item { border-right-color:var(--status-color); }
        .prog-bar-lg { height:6px; }
        .ach-progress-caption { font-size:var(--fs-label); color:var(--text3); margin:var(--space-2) 0 10px; }
        .ach-linked-section-label { font-size:var(--fs-label); color:var(--text3); text-transform:uppercase; letter-spacing:0.04em; margin:var(--space-6) 0 2px; }
        .ach-linked-section-body { font-size:var(--font-size-12); color:var(--text2); line-height:1.9; }
        .ach-activity-log { font-size:var(--fs-label); color:var(--text3); line-height:2; }
        .ach-empty-note { padding:var(--space-4) 0; font-size:var(--fs-label); }
        .sys-accent-0 { --sys-accent:#4A90D9; }
        .sys-accent-1 { --sys-accent:#E67E22; }
        .sys-accent-2 { --sys-accent:#8E44AD; }
        .sys-accent-3 { --sys-accent:#16A085; }
        .sys-accent-4 { --sys-accent:#D35400; }
        .sys-accent-5 { --sys-accent:#2C7BE5; }
        .sys-accent-6 { --sys-accent:#C0392B; }
        .sys-accent-7 { --sys-accent:#27AE60; }
        .sys-accent-8 { --sys-accent:#7F5AB6; }
        .sys-accent-9 { --sys-accent:#F1C40F; }
        .sys-accent-10 { --sys-accent:#E91E63; }
        .sys-accent-11 { --sys-accent:#00BCD4; }
        .sys-accent-12 { --sys-accent:#795548; }
        .sys-accent-13 { --sys-accent:#607D8B; }
        .sys-accent-14 { --sys-accent:#2ECC71; }
        .branch-color-0 { --card-color:#4A90D9; }
        .branch-color-1 { --card-color:#E67E22; }
        .branch-color-2 { --card-color:#8E44AD; }
        .branch-color-3 { --card-color:#16A085; }
        .branch-color-4 { --card-color:#D35400; }
        .branch-color-5 { --card-color:#2C7BE5; }
        .branch-color-6 { --card-color:#C0392B; }
        .branch-color-7 { --card-color:#27AE60; }
        .branch-color-8 { --card-color:#7F5AB6; }
        .branch-color-9 { --card-color:#B8860B; }
        .branch-color-10 { --card-color:#E91E63; }
        .branch-color-11 { --card-color:#00BCD4; }
        .branch-color-root { --card-color:#546E7A; }
        .branch-color-none { --card-color:#95a5a6; }
        .space-accent-0 { --space-accent:#95a5a6; }
        .space-accent-1 { --space-accent:#3498db; }
        .space-accent-2 { --space-accent:#27ae60; }
        .space-accent-3 { --space-accent:#8e44ad; }
        .space-accent-4 { --space-accent:#7f8c8d; }
        .u-fs-10 { font-size:var(--fs-caption); }
        .u-fs-11 { font-size:var(--fs-label); }
        .u-fs-12 { font-size:var(--font-size-12); }
        .u-fs-13 { font-size:var(--fs-body); }
        .u-mb-0 { margin-bottom:0; }
        .u-mt-0 { margin-top:0; }
        .u-p-0 { padding:0; }
        .u-flex-row-gap-6 { display:flex; align-items:center; gap:var(--space-6); }
        .u-mb-4 { margin-bottom:var(--space-4); }
        .u-mb-6 { margin-bottom:var(--space-6); }
        .u-mb-8 { margin-bottom:var(--space-8); }
        .u-mb-10 { margin-bottom:var(--space-10); }
        .u-mb-12 { margin-bottom:var(--space-12); }
        .u-mt-4 { margin-top:var(--space-4); }
        .u-mt-6 { margin-top:var(--space-6); }
        .u-mt-8 { margin-top:var(--space-8); }
        .u-mt-12 { margin-top:var(--space-12); }
        .u-py-8 { padding:var(--space-8) 0; }
        .u-py-10 { padding:var(--space-10) 0; }
        /* ===== UTILITY CLASSES (Track A, Batch 2 — 2026-08-27) =====
           Combo/role classes: each bundles 2-3 declarations that recur
           together as a unit, replacing that whole group at once (still
           composes with Batch 1 atomics and other Batch 2 combos on the
           same element, e.g. class="u-flex-gap-6 u-mb-8"). Also placed
           last for the same cascade-order reason as Batch 1 above. */
        .u-label-text { color:var(--text2); font-size:var(--font-size-12); }
        .u-flex-gap-4 { display:flex; gap:var(--space-4); }
        .u-flex-gap-6 { display:flex; gap:var(--space-6); }
        .u-flex-gap-8 { display:flex; gap:var(--space-8); }
        .u-flex-between { align-items:center; display:flex; justify-content:space-between; }
        .u-flex-between-top { align-items:flex-start; display:flex; justify-content:space-between; }
        .u-flex-row-gap-8 { align-items:center; display:flex; gap:var(--space-8); }
        .u-flex-wrap-gap-6 { display:flex; flex-wrap:wrap; gap:var(--space-6); }
        .u-flex-wrap-gap-4 { display:flex; flex-wrap:wrap; gap:var(--space-4); }
        .u-scroll-80vh { max-height:80vh; overflow-y:auto; }
        .u-scroll-85vh { max-height:85vh; overflow-y:auto; }
        .u-heading-sm { font-size:var(--font-size-12); font-weight:600; }
        .u-heading-md { font-size:var(--fs-heading-sm); font-weight:700; }
        /* ===== UTILITY CLASSES (Track A, Batch 3 — 2026-08-27) =====
           Component-scoped classes (category C): larger, more specific
           bundles than Batch 1/2 — a full form-control treatment and a
           panel-scoped label style, each still a single fixed value set.
           Placed last for the same cascade-order reason as Batch 1/2. */
        .u-text-input { background:var(--bg3); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-sm); box-sizing:border-box; color:var(--text1); font-family:inherit; font-size:var(--font-size-16); margin-bottom:var(--space-8); padding:var(--space-7) 10px; width:100%; }
        .u-text-input.compact { padding:var(--space-5) 8px; }
        .import-preview-label { color:var(--color-import-neutral); padding:var(--space-4) 8px; }
        .import-preview-value { font-weight:600; }
        /* [T-358] Part 4 — import preview: number columns, a long note keeps its line breaks, the action row wraps on a phone, a destructive action is red */
        .import-preview-num { text-align:center; white-space:nowrap; }
        .import-preview-note { white-space:pre-line; }
        .import-preview-actions { flex-wrap:wrap; }
        .import-preview-actions > button { flex:1 1 140px; min-height:44px; }
        .import-preview-danger-btn { background:var(--danger); border-color:var(--danger); }
        .search-result-category-chip { font-size:var(--fs-caption); background:rgba(120,120,120,0.1); padding:var(--space-1) 6px; border-radius:var(--radius-sm); }
        /* Sprint 14 Remediation Final Cleanup, Part A (I-18) — standard
           visually-hidden pattern for a11y-only heading text: kept in the
           accessibility tree (unlike display:none) but removed from
           visual layout, so it adds no visible chrome. */
        .sr-only { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0; }
        .menu-section-title { font-size:var(--fs-label); color:var(--text3); font-weight:700; margin:var(--space-14) 0 10px; letter-spacing:0.2px; }
        .menu-section-title:first-of-type { margin-top:var(--space-2); }
        /* Sync disclosure content blocks (UI/UX fixes batch, 2026-09-12,
           Part C) — scoped to #syncDisclosureContent only, NOT a change to
           .menu-section-title/.about-info-text themselves (27 usages across
           5 files per grep — a shared Settings-menu convention, out of this
           batch's scope). Reuses .dash-card's own card language (bg2,
           hairline border, radius, shadow-card) plus the same
           colored-icon-on-tint badge idiom already established by
           .habit-hero-icon/.mgr-stat-hero-icon, instead of the plain
           menu-section-title + paragraph text the disclosure modal used
           before. */
        .sync-disclosure-lead { font-size:var(--fs-body); color:var(--text2); line-height:1.6; margin-bottom:var(--space-12); }
        .sync-disclosure-block { display:flex; align-items:flex-start; gap:var(--space-10); background:var(--bg2); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.12); border-radius:var(--radius); padding:var(--space-12) 14px; margin-bottom:var(--space-10); box-shadow:var(--shadow-card); }
        body.dark .sync-disclosure-block { border-color:rgba(var(--accent-rgb),0.2); }
        .sync-disclosure-block.warn { border-color:rgba(200,90,0,0.3); }
        .sync-disclosure-icon { width:36px; height:36px; border-radius:var(--radius-full); display:flex; align-items:center; justify-content:center; flex-shrink:0; background:rgba(var(--accent-rgb),0.14); color:var(--accent); }
        .sync-disclosure-icon.warn { background:rgba(200,90,0,0.14); color:var(--warning); }
        .sync-disclosure-block-body { min-width:0; flex:1; }
        .sync-disclosure-block-title { font-size:var(--fs-heading-sm); font-weight:700; color:var(--text1); margin-bottom:var(--space-4); }
        .sync-disclosure-block-text { font-size:var(--fs-body); color:var(--text2); line-height:1.6; }
        .sync-disclosure-block.warn .sync-disclosure-block-text { color:var(--warning); }
        .sync-passphrase-hint { font-size:var(--fs-label); color:var(--text3); margin:var(--space-4) 2px var(--space-8); }
        .menu-item { display:flex; align-items:center; gap:var(--space-10); width:100%; text-align:right; background:var(--bg3); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-md); padding:var(--space-9) 12px; margin-bottom:var(--space-6); cursor:pointer; font-family:inherit; transition:filter var(--dur-fast) var(--ease-standard), border-color var(--dur-fast) var(--ease-standard), box-shadow var(--dur-fast) var(--ease-standard), transform var(--dur-fast) var(--ease-standard); }
        .menu-item:hover { filter:brightness(0.97); border-color:rgba(var(--accent-rgb),0.4); box-shadow:0 2px 8px rgba(var(--accent-rgb),0.12); transform:translateY(-1px); }
        body.dark .menu-item:hover { filter:brightness(1.15); }
        .menu-item-ic { font-size:var(--font-size-17); width:var(--icon-box-24); text-align:center; flex-shrink:0; }
        .menu-item-text { display:flex; flex-direction:column; gap:var(--space-1); flex:1; min-width:0; }
        .menu-item-title { font-size:var(--fs-body); font-weight:600; color:var(--text1); }
        .menu-item-desc { font-size:var(--fs-label); color:var(--text3); }
        .menu-item-status { font-size:var(--fs-label); color:var(--accent); margin-top:var(--space-1); }
        .menu-item-chevron { color:var(--text3); font-size:var(--fs-body); flex-shrink:0; }
        /* Settings Hub visual hierarchy (2026-07-30) — primary items
           (General/Appearance/Execution) read slightly heavier; secondary
           items (Notifications/Backup/Dev Tools) read slightly quieter.
           Everything unmentioned by the spec keeps today's neutral weight. */
        .menu-item-primary .menu-item-ic { width:30px; font-size:var(--font-size-19); }
        .menu-item-primary .menu-item-title { font-size:var(--fs-heading-sm); font-weight:700; }
        .menu-item-secondary { opacity:0.86; }
        .menu-item-secondary .menu-item-ic { font-size:var(--font-size-15); }
        /* Theme Center — Premium UI Sprint (2026-07-31). .theme-mode-card
           rides on .menu-item's existing hover lift (unchanged) and just
           adds a press state; .theme-palette-swatch adds hover/press/
           selected-ring on top of the swatch's own JS-computed inline
           border/background (untouched — same live-preview logic). */
        .theme-mode-card:active { transform:scale(0.97); }
        .theme-mode-card.is-active { border-color:var(--accent); background:rgba(var(--accent-rgb),0.1); }
        .theme-palette-swatch { transition:transform var(--dur-fast) var(--ease-standard),box-shadow var(--dur-fast) var(--ease-standard); border:var(--border-thin) solid var(--border); }
        .theme-palette-swatch:hover { transform:scale(1.1); }
        .theme-palette-swatch:active { transform:scale(0.92); }
        .theme-palette-swatch.pal-active { box-shadow:var(--shadow-ring-active); animation:themePalPop 0.35s var(--ease-standard); border-color:var(--accent); }
        .theme-palette-swatch.palette-swatch-classic { background:var(--accent); }
        .theme-palette-swatch.palette-swatch-ocean { background:var(--color-palette-ocean); }
        .theme-palette-swatch.palette-swatch-forest { background:var(--color-palette-forest); }
        .theme-palette-swatch.palette-swatch-warm { background:var(--warning); }
        .theme-palette-swatch.palette-swatch-gold { background:var(--gold); }
        @keyframes themePalPop { 0%{transform:scale(0.7)} 60%{transform:scale(1.14)} 100%{transform:scale(1)} }
        /* GLOBAL BREADCRUMB — نفس الشكل لكل الصفحات الـ Hierarchical (Group 2 - Sprint 4/تعميم) */
        .nav-breadcrumb { display:none; align-items:center; gap:var(--space-6); background:none; border:none; cursor:pointer; font-family:inherit; font-size:var(--fs-body); color:var(--text2); padding:var(--space-4) 0; margin-bottom:var(--space-6); width:100%; text-align:right; }
        /* RTL CSS Keystone Fix (2026-08-26) — see body.lang-ltr near line 216. */
        body.lang-ltr .nav-breadcrumb { text-align:left; }
        /* Shared popup open/close animation (CSS duplication audit, item 8) —
           .task-menu-popup and #dpPopup had byte-identical animation triplets;
           extracted once, applied to both via an added class. */
        .popup-anim { visibility:hidden; opacity:0; transform:scale(0.96); transform-origin:top; transition:opacity var(--dur-fast) var(--ease-standard), transform var(--dur-fast) var(--ease-standard), visibility 0s var(--dur-fast); }
        .popup-anim.open { visibility:visible; opacity:1; transform:scale(1); transition:opacity var(--dur-fast) var(--ease-standard), transform var(--dur-fast) var(--ease-standard); }
        .task-menu-popup { position:fixed; z-index:var(--z-popover); background:var(--bg2,#fff); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.2); border-radius:var(--radius-md); padding:var(--space-6); min-width:150px; box-shadow:var(--shadow-overlay); display:flex; flex-direction:column; gap:var(--space-2); }
        body.dark .task-menu-popup { background:var(--bg2); border-color:rgba(var(--accent-rgb),0.35); box-shadow:0 4px 24px rgba(0,0,0,0.4); }
        .dp-popup { position:fixed; z-index:var(--z-popover); background:var(--bg2); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.18); border-radius:var(--radius); padding:var(--space-12); width:260px; box-shadow:0 4px 20px rgba(0,0,0,0.15); }
        .global-search-bar { padding:var(--space-6) 14px; background:var(--bg2); border-bottom:var(--border-hairline) solid var(--border); position:sticky; top:var(--sticky-top); z-index:8; }
        /* 44px tap target (Tap Targets Under 44px sprint, Batch 2) — was
           26x26. Same min-width/min-height + flex-centring idiom as
           .modal-close; every real usage site (33, enumerated) sits beside
           a flex:1 text sibling that just narrows, confirmed collision-free.
           Icon here is icon('menu') -> <svg class="icon">, not a
           <span data-icon>, so it never picks up the global
           [data-icon] margin-inline-end:4px rule — no companion rule
           needed (verified via computed style, not assumed). */
        .task-menu-btn { min-width:44px; min-height:44px; border-radius:var(--radius-sm); border:var(--border-hairline) solid var(--border,rgba(var(--accent-rgb),0.2)); background:var(--bg3,#f0f7f7); color:var(--text3,#6b8a8a); cursor:pointer; display:inline-flex; align-items:center; justify-content:center; font-size:var(--fs-heading-sm); line-height:1; flex-shrink:0; font-family:inherit; transition:background var(--dur-instant) var(--ease-standard); }
        .task-menu-btn:hover { background:var(--bg2,#e8f4f4); color:var(--text,#1a2a2a); border-color:rgba(var(--accent-rgb),0.4); }
        .task-menu-item { display:flex; align-items:center; gap:var(--space-8); padding:var(--space-8) 12px; border:none; background:none; border-radius:var(--radius-sm); cursor:pointer; font-family:inherit; font-size:var(--fs-body); color:var(--text1); width:100%; text-align:right; transition:background var(--dur-instant) var(--ease-standard); }
        /* RTL CSS Keystone Fix (2026-08-26) — see body.lang-ltr near line 216. */
        body.lang-ltr .task-menu-item { text-align:left; }
        .task-menu-item:hover { background:rgba(var(--accent-rgb),0.08); }
        .task-menu-item.del { color:var(--danger); }
        body.dark .task-menu-item { color:#e8f4f4; }
        .task-menu-btn.del { border-color:var(--danger); background:rgba(var(--danger-rgb),0.13); color:var(--danger); }

        /* ===== ORG STRUCTURE MANAGER — 2026-07-16 redesign (drill-down) ===== */
        .pm-list { display:flex; flex-direction:column; gap:var(--space-8); }
        .pm-card, .pm-row { background:var(--bg2); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-md); padding:var(--space-10) 12px; display:flex; align-items:center; justify-content:space-between; cursor:pointer; border-right:var(--border-thick) solid var(--pc,var(--tc,#0D6E6E)); }
        .pm-card.is-active { border-color:var(--accent); }
        tr.is-top-rank { background:rgba(var(--accent-rgb),0.08); }
        .dash-stat-row.rank-row { font-size:var(--font-size-12); }
        .dash-stat-row.rank-row.is-top-rank { font-weight:700; font-size:var(--fs-heading-sm); }
        .pm-card:hover, .pm-row:hover { background:var(--bg3); }
        .pm-card-left { display:flex; align-items:center; gap:var(--space-10); min-width:0; }
        .pm-card-icon { width:34px; height:34px; border-radius:9px; background:color-mix(in srgb, var(--pc) 15%, transparent); color:var(--pc); display:flex; align-items:center; justify-content:center; font-size:var(--font-size-16); flex-shrink:0; }
        .pm-card-name { font-weight:700; font-size:var(--fs-heading-sm); color:var(--text1); }
        .pm-card-right { display:flex; align-items:center; gap:var(--space-6); flex-shrink:0; }
        .pm-row-name { font-size:var(--fs-body); font-weight:500; color:var(--text1); display:flex; align-items:center; gap:var(--space-4); }
        .pm-row-stats { font-size:var(--fs-label); color:var(--text3); margin-top:var(--space-2); }
        /* Project-progress readability (Pillar Manager visual polish,
           2026-07-30) — scoped to the one place a project's own done/total
           % renders (subtrack-level leaf list). Deliberately NOT a change to
           .pm-row-stats itself, which the Pillar/Track counters also use and
           must stay untouched. */
        .pm-project-progress { font-size:var(--fs-body); font-weight:600; color:var(--text2); }
        .pm-row-leaf { border-right-width:3px; padding:var(--space-9) 11px; }
        .pm-chevron { color:var(--text3); font-size:var(--fs-body); }
        .pm-add-btn { width:100%; padding:var(--space-12) 9px; border-radius:9px; border:1.5px dashed rgba(var(--accent-rgb),0.35); color:var(--accent); background:rgba(var(--accent-rgb),0.06); font-size:var(--fs-body); text-align:center; font-weight:600; cursor:pointer; font-family:inherit; margin-top:var(--space-8); }
        /* Unified back-button system (app-wide, 2026-07-25) — one shared
           shape/behavior for every "back" control: Structure Manager back
           nav (.pm-back-btn, 3 sites), Thinking Space canvas back (1),
           Project Detail back (1, previously its own inline style), and the
           Settings sub-modal "رجوع" pattern (.btn-cancel, 18 sub-modals) —
           23 sites total, all previously inconsistent. Per-context color
           only, via the --btn-color custom property (defaults to the theme
           accent when unset) — never a per-context shape/size fork. */
        .back-btn { display:inline-flex; align-items:center; gap:var(--space-5); background:linear-gradient(135deg,var(--btn-color-soft,rgba(var(--accent-rgb),0.85)),var(--btn-color,var(--accent))); border:none; color:var(--text-on-accent); font-size:var(--fs-body); font-weight:700; font-family:inherit; padding:var(--space-7) 16px; border-radius:20px; margin-bottom:var(--space-10); cursor:pointer; box-shadow:0 1px 3px rgba(0,0,0,0.15); transition:filter var(--dur-fast) var(--ease-standard); }
        .back-btn:hover { filter:brightness(1.08); }
        .back-btn .icon { width:15px; height:15px; }
        .pm-detail-header { display:flex; align-items:center; gap:var(--space-8); background:color-mix(in srgb, var(--pc) 10%, transparent); border-right:var(--border-thick) solid var(--pc); border-radius:var(--radius-md); padding:var(--space-10) 12px; margin-bottom:var(--space-10); }
        .pm-detail-icon { width:32px; height:32px; border-radius:var(--radius-sm); background:color-mix(in srgb, var(--pc) 18%, transparent); color:var(--pc); display:flex; align-items:center; justify-content:center; font-size:var(--font-size-15); flex-shrink:0; }
        .pm-detail-name { font-weight:700; font-size:var(--font-size-15); color:var(--pc); flex:1; }
        .pm-detail-actions { display:flex; gap:var(--space-4); flex-shrink:0; }
        .pm-empty { padding:var(--space-10) 0; font-size:var(--font-size-12); color:var(--text3); text-align:center; }
        .pm-section { padding-top:var(--space-10); margin-top:var(--space-10); border-top:var(--border-hairline) solid var(--border); }
        .pm-section-label { font-size:var(--fs-caption); color:var(--text3); text-transform:uppercase; letter-spacing:0.04em; margin-bottom:var(--space-4); display:flex; align-items:center; gap:var(--space-5); }
        .pm-icon-grid { display:flex; flex-wrap:wrap; gap:var(--space-6); margin-bottom:var(--space-8); }
        .pm-icon-choice { width:36px; height:36px; border-radius:var(--radius-sm); border:var(--border-hairline) solid var(--border); background:var(--bg3); color:var(--text2); cursor:pointer; display:flex; align-items:center; justify-content:center; font-size:var(--font-size-15); font-family:inherit; }
        .pm-icon-choice.sel { border-color:var(--accent); background:rgba(var(--accent-rgb),0.15); color:var(--accent); }
        #dpPopup { display:block; }
        body.dark #dpPopup { background:var(--bg2); border-color:rgba(var(--accent-rgb),0.3); }
        .dp-day { border:none;background:none;cursor:pointer;border-radius:var(--radius-sm);padding:var(--space-5) 3px;font-size:var(--font-size-12);color:var(--text1);width:100%;text-align:center;transition:background var(--dur-instant) var(--ease-standard); }
        .dp-day:hover { background:rgba(var(--accent-rgb),0.1); }
        .dp-day.today { background:var(--accent);color:var(--text-on-accent);font-weight:600; }
        .dp-day.other { color:var(--color-dp-day-other); cursor:default; }
        body.dark .dp-day { color:#e8f4f4; }
        body.dark .dp-day.other { color:#3a5a5a; }
        /* ===== UX POLISH — Sprint 11 =====
           New component CSS added once here rather than scattered across the
           825-line legacy style block, so this sprint's additions stay
           reviewable as one unit. Nothing here overrides earlier rules by
           specificity trickery — new classes only. */

        /* --- Icon system: replaces emoji-as-icon + unused Font Awesome --- */
        svg.icon { width:1em; height:1em; display:inline-block; vertical-align:-0.15em; flex-shrink:0; }
        svg.icon.icon-filled polygon, svg.icon.icon-filled path, svg.icon.icon-filled circle { fill:currentColor; }
        /* margin-inline-end (real-usage bug fix): static markup app-wide
           glues these spans directly against following text with zero
           whitespace in the HTML source (e.g. <span data-icon="x"></span>TEXT)
           — CSS structural pseudo-classes like :not(:only-child) can't tell
           "has adjacent text" from "has no siblings" (they ignore text
           nodes), so a real fix has to be an unconditional small gap here
           rather than a selector that would silently never match the bug.
           Harmless on icon-only usages (a trailing margin before nothing is
           invisible). Same fix already applied ad hoc to the toast retry
           button and the Undo History restore button above it. */
        [data-icon] { display:inline-flex; align-items:center; justify-content:center; margin-inline-end:4px; }
        /* Evening Reflection star rating (real-usage request: fill-as-you-go
           stars instead of plain 1-5 number buttons) — reuses the icon-filled
           mechanism above; setReflRating() toggles it on stars 1..n. */
        /* 44px tap target (App-Wide Mobile Input & Control Defects, Batch 4) —
           was 42x41. inline-flex + centring is required because the box is now
           wider than its content; margin-inline-end:0 cancels the global
           [data-icon] 4px trailing margin, which would otherwise push the star
           off-centre inside the enlarged button. */
        .refl-star-btn { background:none; border:none; padding:var(--space-4); cursor:pointer; color:var(--border); transition:transform var(--dur-fast) var(--ease-standard); min-width:44px; min-height:44px; display:inline-flex; align-items:center; justify-content:center; }
        .refl-star-btn:hover { transform:scale(1.15); }
        .refl-star-btn .icon { width:30px; height:30px; }
        .refl-star-btn .icon.icon-filled { color:var(--gold); }
        /* Companion rule cancelling the global [data-icon] 4px trailing
           margin — same idiom as .task-icon-btn's own version (line ~615).
           Selector is [data-icon] itself, NOT .icon: the real markup here
           is <span data-icon="star"> with no class="icon" on the span —
           hydrateIcons() only puts class="icon" on the SVG it injects
           inside the span, so a .icon-based override matches the wrong
           element (confirmed live: the span kept margin-inline-end:4px
           while the SVG got 0px, a silent no-op — see
           docs/07_DECISIONS_ACTIVE.md, ".refl-star-btn .icon" entry).
           Kept as its own rule rather than merged with .task-icon-btn's —
           unrelated controls in different stylesheet regions; same fix
           shape, not the same rule. */
        .refl-star-btn [data-icon] { margin-inline-end:0; }

        /* --- Focus-visible: one consistent ring, keyboard-only --- */
        a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible,
        textarea:focus-visible, [tabindex]:focus-visible, .nav-item:focus-visible,
        .nav-bottom-item:focus-visible, .task-item:focus-visible, .fab:focus-visible {
            outline:2px solid var(--accent); outline-offset:2px; border-radius:var(--radius-xs);
        }
        /* --- Press feedback: generic, applied to interactive elements app-wide --- */
        button:not(:disabled):active, .btn-primary:not(:disabled):active,
        .btn-cancel:not(:disabled):active, .nav-item:active, .nav-bottom-item:active,
        .task-item:active, .fab:active, .filter-btn:active, .tag-pill:active {
            transform:scale(0.97); transition:transform var(--dur-fast) var(--ease-standard);
        }
        /* #mainFab relies on transform for its actual position (left:50% +
           translateX(-50%) centering), not just visual feedback like the
           generic rule above assumes — that rule's transform:scale(0.97)
           was replacing the positioning transform outright, snapping the
           button sideways on press and back on release. An ID selector
           here (specificity beats button:not(:disabled):active) composes
           the same press-feedback scale with the real position instead. */
        #mainFab:active { transform:translateX(-50%) scale(0.97); }
        button:disabled, .btn-primary:disabled { opacity:0.5; cursor:not-allowed; }
        /* RB-13 — prefers-reduced-motion: shortens every CSS animation/
           transition app-wide to near-instant (modal open/close, toast
           keyframes, the :active{transform:scale} press rules above,
           bounce/xpMicroPop, etc.) instead of removing the underlying
           state change — a pressed button still visibly changes, a modal
           still opens, just without the animated motion between states.
           Confetti is a separate, JS/canvas-driven case this can't reach
           — see fireConfetti()'s own matchMedia check. */
        @media (prefers-reduced-motion: reduce) {
            *, *::before, *::after {
                animation-duration: 0.01ms !important;
                animation-iteration-count: 1 !important;
                transition-duration: 0.01ms !important;
                scroll-behavior: auto !important;
            }
        }

        /* --- Toggle switch: visual layer over existing checkbox inputs --- */

        /* --- Spinner (indeterminate) --- */
        .spinner { width:18px; height:18px; border:var(--border-thin) solid var(--border); border-top-color:var(--accent); border-radius:var(--radius-full); animation:spinnerRotate 0.7s linear infinite; display:inline-block; }
        @keyframes spinnerRotate { to { transform:rotate(360deg); } }
        /* Smaller variant sized for setButtonLoading()'s inline trigger-
           button spinner (Button System sprint, Phase 4) — was an inline
           style at its one call site. */
        .spinner.btn-spinner { width:13px; height:13px; border-width:var(--border-thin); vertical-align:-2px; }

        /* --- Mobile safe-area (notched devices) --- */
        .fab { padding-bottom:env(safe-area-inset-bottom,0); }
        .nav-bottom { padding-bottom:env(safe-area-inset-bottom,0); }
        #toastStack { padding-bottom:env(safe-area-inset-bottom,0); }

        /* --- Thinking Space (Sprint 13 Phase 6/8) — see archive/audits/13_THINKING_SPACE_DESIGN_REVIEW.md --- */
        /* Gradient-filled cards (real-usage report, 3rd correction pass) —
           replaces the flat bg2 + border look with a full gradient fill per
           status color, same linear-gradient(135deg, colorcc, color) formula
           gradientPill() already uses everywhere else in the app, driven by
           the --card-color custom property set inline per card. Text/badges
           switch to white/translucent-white since the card itself now
           carries the color instead of just its border. */
        .ts-idea-card { position:absolute; display:flex; flex-direction:column; justify-content:center; align-items:center; text-align:center; width:150px; min-height:64px; --card-color:#95a5a6; --card-color-soft:color-mix(in srgb, var(--card-color) 80%, transparent); background:linear-gradient(135deg,var(--card-color-soft),var(--card-color)); border:none; border-radius:var(--radius-sm); box-shadow:var(--shadow-card); padding:var(--space-8) 10px; cursor:grab; user-select:none; direction:rtl; transition:box-shadow var(--dur-fast) var(--ease-standard),filter var(--dur-fast) var(--ease-standard); }
        .ts-idea-card:hover { filter:brightness(1.08); box-shadow:var(--shadow-card-hover); }
        .ts-idea-card:active { cursor:grabbing; }
        .ts-idea-card.ts-idea-selected { outline:2px solid var(--text-on-accent); outline-offset:2px; }
        .ts-idea-card.is-root { box-shadow:0 0 0 3px var(--space-accent), var(--shadow-card); }
        .ts-quadrant-bg { position:absolute; left:-260px; top:-260px; width:520px; height:520px; border:var(--border-hairline) dashed var(--border); pointer-events:none; }
        .ts-quadrant-bg-vline { position:absolute; left:50%; top:0; bottom:0; width:1px; background:var(--border); }
        .ts-quadrant-bg-hline { position:absolute; top:50%; left:0; right:0; height:1px; background:var(--border); }
        .ts-quadrant-bg-zone { position:absolute; font-size:var(--fs-label); color:var(--text3); font-weight:700; }
        .ts-quadrant-bg-zone.tl { top:8px; left:8px; }
        .ts-quadrant-bg-zone.tr { top:8px; right:8px; }
        .ts-quadrant-bg-zone.bl { bottom:8px; left:8px; }
        .ts-quadrant-bg-zone.br { bottom:8px; right:8px; }
        .ts-quadrant-bg-axis { position:absolute; font-size:var(--fs-caption); color:var(--text3); }
        .ts-quadrant-bg-axis.growth { top:-20px; left:50%; transform:translateX(-50%); }
        .ts-quadrant-bg-axis.share { bottom:-20px; right:0; }
        /* Idea Type shapes (2026-07-27) — 'raw' intentionally matches the
           original plain card exactly (no rule needed, it's the base
           .ts-idea-card look) so pre-existing ideas/spaces render unchanged. */
        .ts-idea-shape-concept { border:var(--border-medium) double rgba(255,255,255,0.8); }
        .ts-idea-shape-decision { border-radius:var(--radius-xs); }
        .ts-idea-shape-question { border-radius:26px; }
        .ts-idea-shape-insight { border:var(--border-thin) dashed rgba(255,255,255,0.8); }
        .ts-idea-type-badge { position:absolute; top:-5px; left:-5px; width:var(--icon-box-16); height:var(--icon-box-16); border-radius:50%; background:#fff; display:flex; align-items:center; justify-content:center; box-shadow:var(--shadow-card); }
        .ts-idea-type-badge .icon { width:10px; height:10px; color:var(--text1); }
        .ts-idea-title { font-size:var(--font-size-12); font-weight:600; color:var(--text-on-accent); word-break:break-word; }
        .ts-idea-desc-preview { font-size:var(--fs-label); color:rgba(255,255,255,0.85); margin-top:var(--space-4); line-height:1.4; word-break:break-word; white-space:pre-wrap; }
        .ts-idea-status-dot { position:absolute; top:-5px; right:-5px; width:10px; height:10px; border-radius:50%; border:var(--border-thin) solid #fff; cursor:default; }
        .ts-idea-badge { font-size:var(--fs-caption); color:var(--text-on-accent); margin-top:var(--space-4); }
        .ts-idea-meta-row { display:flex; align-items:center; flex-wrap:wrap; gap:var(--space-4); margin-top:var(--space-5); font-size:var(--font-size-12); justify-content:center; }
        .ts-idea-meta-row span { display:inline-flex; align-items:center; justify-content:center; width:var(--icon-box-20); height:var(--icon-box-20); border-radius:5px; background:rgba(255,255,255,0.25); color:var(--text-on-accent); }
        .ts-idea-meta-row span.ts-meta-badge-text { width:auto; padding:0 6px; font-size:var(--fs-caption); font-weight:600; }
        .ts-idea-card.ts-idea-dim { opacity:0.2; }
        .ts-idea-card.ts-multi-selected { box-shadow:0 0 0 3px var(--accent); }
        .ts-idea-collapse-btn { position:absolute; bottom:-9px; left:50%; transform:translateX(-50%); width:24px; height:24px; border-radius:50%; background:#fff; border:var(--border-hairline) solid var(--border); display:flex; align-items:center; justify-content:center; cursor:pointer; color:var(--accent); }
        .ts-idea-collapse-btn .icon { width:11px; height:11px; }
        .ts-idea-toolbar-btn { position:absolute; width:44px; height:44px; border-radius:50%; display:flex; align-items:center; justify-content:center; cursor:pointer; color:var(--accent); background:var(--bg2); border:var(--border-hairline) solid var(--border); box-shadow:var(--shadow-card); transition:filter var(--dur-fast) var(--ease-standard); z-index:5; }
        .ts-idea-toolbar-btn:hover { filter:brightness(0.94); }
        .ts-idea-toolbar-btn .icon { width:14px; height:14px; }
        /* Left→left, Right→right, Below→below — spatial position of each
           button matches the direction it adds a new idea in (user's
           explicit ask: "تكامل فكرة وبصري"). The left button reuses the
           same node-insert glyph mirrored horizontally.
           Offsets below were widened when the buttons grew from 24px to
           44px (Sprint 8 Phase 2 Batch 3, items 12+16) -- at the old -32px
           offset the enlarged .ts-toolbar-below would overlap
           .ts-idea-collapse-btn (also enlarged, 18->24px) by 21px,
           confirmed via a live getBoundingClientRect() collision probe
           before implementing, per this project's target-size expansion
           gate. -57px restores a clean 4px gap. Left/right grew by the
           same 20px the buttons themselves grew, to keep each button's
           outer edge at its original visual distance from the card. */
        .ts-idea-toolbar-btn.ts-toolbar-right { top:50%; right:-52px; transform:translateY(-50%); }
        .ts-idea-toolbar-btn.ts-toolbar-left { top:50%; left:-52px; transform:translateY(-50%); }
        .ts-idea-toolbar-btn.ts-toolbar-left .icon { transform:scaleX(-1); }
        .ts-idea-toolbar-btn.ts-toolbar-below { bottom:-57px; left:50%; transform:translateX(-50%); }
        /* Thinking Space Canvas Phase 2 — persistent on-canvas "+" affordance.
           Lives outside #tsCanvasLayer (a sibling, same as #tsEmptyState/
           #tsKeyboardHint) so it stays fixed to the viewport corner
           regardless of pan/zoom, instead of scaling/moving with the world
           content. Reuses .ts-idea-toolbar-btn's full visual identity
           (44px circle, --bg2/--border/--shadow-card) — only position
           differs, same "modifier adds offsets only" pattern as
           .ts-toolbar-right/-left/-below above.
           Corner is `left`, not `right`: on desktop, #tsViewport's own
           right edge sits underneath the app's right sidebar column
           (#navSidebarModules, real overlap confirmed live —
           #tsViewport right:1099.5 vs sidebar left:1045, ~54px), which
           silently swallows clicks/hit-testing on anything anchored to
           `right`. The left corner is confirmed clear via a live
           elementFromPoint hit-test. */
        .ts-canvas-add-btn { bottom:16px; left:16px; z-index:6; }
        /* Thinking Space Canvas Phase 3a, Part A — transient class applied
           only around a programmatic camera move (fit-to-screen, jump-to-
           idea centering, the zoom +/- buttons); see _tsApplyTransformEased().
           Never present during drag/pinch/wheel, which call the plain
           _tsApplyTransform() and must stay instant. */
        .ts-camera-eased { transition:transform var(--dur-base) var(--ease-standard); }
        /* Thinking Space Canvas Phase 3a, Part B — zoom indicator + +/-
           buttons. Lives outside #tsCanvasLayer (fixed to the viewport
           corner, same as #tsCanvasAddBtn/#tsKeyboardHint), top-left so it
           never collides with the bottom-left "+" button or the
           right-sidebar hit-testing dead zone (see .ts-canvas-add-btn). */
        .ts-zoom-controls { position:absolute; top:12px; left:16px; z-index:6; display:flex; align-items:center; gap:var(--space-4); background:var(--bg2); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-pill); padding:var(--space-4); box-shadow:var(--shadow-card); }
        .ts-idea-ghost-card { position:absolute; display:flex; align-items:center; justify-content:center; background:var(--bg2); border:var(--border-thin) dashed var(--accent); border-radius:var(--radius-sm); padding:var(--space-8) 10px; box-sizing:border-box; }
        .ts-idea-ghost-input { border:none; outline:none; background:transparent; text-align:center; width:100%; font:inherit; color:var(--text1); direction:rtl; }
        /* Sprint 8 Phase 2 Batch 2, item 7 (WCAG SC 2.4.7 Focus Visible) --
           :focus, not :focus-visible: contenteditable's :focus-visible
           support is inconsistent across browsers, so :focus-visible alone
           would silently show no ring at all in some of them. */
        .ts-idea-ghost-input:focus { outline:2px solid var(--accent); outline-offset:2px; border-radius:var(--radius-xs); }
        #tsConnectBtn.active, #tsBoxSelectBtn.active, #tsSelectModeBtn.active { background:var(--accent); color:var(--text-on-accent); }
        #tsKeyboardHint { opacity:0; transition:opacity var(--dur-fast) var(--ease-standard); }
        #tsViewport:focus #tsKeyboardHint { opacity:1; }
        .ts-space-row-checkbox { width:18px; height:18px; flex-shrink:0; margin-inline-end:8px; }
        .ts-type-card { display:flex; flex-direction:column; gap:var(--space-3); padding:var(--space-10) 12px; border:none; border-radius:var(--radius-md); background:linear-gradient(135deg,color-mix(in srgb, var(--card-color, var(--accent)) 80%, transparent),var(--card-color, var(--accent))); cursor:pointer; text-align:start; transition:filter var(--dur-fast) var(--ease-standard); }
        .ts-type-card:hover { filter:brightness(1.08); }
        .ts-type-card-icon { color:var(--text-on-accent); }
        .ts-type-card-icon .icon { width:18px; height:18px; }
        .ts-type-card-title { font-size:var(--font-size-12); font-weight:600; color:var(--text-on-accent); }
        .ts-type-card-desc { font-size:var(--fs-label); color:rgba(255,255,255,0.85); }
        .ts-type-card-when { font-size:var(--fs-caption); color:rgba(255,255,255,0.7); opacity:0.9; }
        /* Method structure preview (Thinking Space Refinement Sprint) — sits
           inside the existing .ts-type-card, no new card system. Drawn on
           the card's own gradient, so a translucent white panel + white
           strokes need no theme token and work identically in both themes.
           Direction-sensitive shapes (timeline/chain/fishbone) mirror under
           RTL so their arrows follow the reading direction; the symmetric
           ones are unaffected by the flip. */
        .ts-type-card-preview { margin:var(--space-2) 0 var(--space-1); padding:var(--space-4) var(--space-5); border-radius:var(--radius-sm); background:rgba(255,255,255,0.15); }
        .ts-type-card-preview svg { display:block; width:100%; height:36px; }
        [dir="rtl"] .ts-type-card-preview svg { transform:scaleX(-1); }
        .ts-type-section-title { font-size:var(--fs-label); font-weight:600; color:var(--text3); letter-spacing:0.3px; margin:var(--space-14) 0 8px; }
        .ts-type-section-title:first-child { margin-top:0; }
        #tsWorkspaceBorder { border-style:dashed; border-color:var(--color-workspace-bounds); border-width:4px; opacity:1; border-radius:var(--radius-md); box-shadow:0 0 0 3px rgba(255,34,34,0.18); }
        .ts-space-hero-title { font-size:var(--fs-heading-md); font-weight:700; color:var(--text1); line-height:1.3; word-break:break-word; }
        /* Inline-style cleanup, Part B+C batch 20 (2026-09-09) — masari.html
           lines 1-431 (header, Today tab, Planner tab, Workspace/Habits/
           Finance tab openers). */
        .header-focus-indicator { align-items:center; gap:var(--space-4); background:rgba(255,255,255,0.12); border-radius:var(--radius-lg); padding:var(--space-3) 9px; cursor:pointer; flex-shrink:0; }
        .header-focus-time { font-size:var(--fs-label); color:var(--text-on-accent); font-weight:600; }
        .notif-bell-btn { position:relative; }
        .notif-center-badge { position:absolute; top:-2px; left:-2px; background:var(--red,#c0392b); color:var(--text-on-accent); font-size:var(--fs-micro); min-width:14px; height:14px; border-radius:var(--radius-full); align-items:center; justify-content:center; line-height:1; }
        .global-search-input-row { display:flex; align-items:center; gap:var(--space-8); background:var(--bg3); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-sm); padding:var(--space-6) 10px; }
        .global-search-icon { color:var(--text3); font-size:var(--fs-heading-sm); }
        .global-search-input { flex:1; border:none; background:none; color:var(--text1); font-family:inherit; font-size:var(--font-size-16); outline:none; direction:rtl; }
        .global-search-close-btn { background:none; border:none; color:var(--text3); cursor:pointer; font-size:var(--font-size-16); padding:0; line-height:1; min-width:44px; min-height:44px; display:inline-flex; align-items:center; justify-content:center; }
        .header-context-line { margin-top:var(--space-8); padding:var(--space-6) 16px; font-size:var(--fs-label); color:var(--text-on-accent); font-weight:600; background:linear-gradient(135deg,var(--accent),var(--accent-dark)); }
        .morning-reopen-btn { align-items:center; gap:var(--space-6); background:var(--accent-dark); color:var(--text-on-accent); border:none; padding:var(--space-8) 12px; font-size:var(--font-size-12); margin-bottom:var(--space-12); width:100%; justify-content:center; }
        body.dark .btn-primary.morning-reopen-btn { background:var(--accent-dark); }
        .today-field-label { font-size:var(--fs-label); color:var(--text3); margin-bottom:var(--space-6); font-weight:600; display:block; }
        .sleep-hours-input { width:90px; text-align:center; margin-bottom:0; padding:var(--space-6) 8px; background:var(--bg3); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-sm); color:var(--text1); font-family:inherit; }
        .energy-title-row { display:flex; align-items:center; justify-content:center; gap:var(--space-6); }
        .energy-title-label { font-size:var(--fs-label); color:rgba(255,255,255,0.65); font-weight:600; }
        .dismiss-forever-link { font-size:var(--fs-label); color:var(--text3); cursor:pointer; text-decoration:underline; }
        .day-load-forecast-warn { font-size:var(--fs-label); color:var(--warning); margin:var(--space-2) 0 4px; }
        .cal-month-completion-glance { font-size:var(--fs-label); color:var(--text3); text-align:center; margin-bottom:var(--space-6); }
        .archive-folder-header { background:linear-gradient(135deg,#534AB7cc,var(--color-archive-folder)); margin-top:var(--space-12); }
        .cal-archive-section { margin-top:var(--space-6); }
        .distribute-backlog-btn { width:100%; font-weight:500; margin-bottom:var(--space-8); }
        .reset-backlog-btn { width:100%; padding:var(--space-9); background:linear-gradient(135deg,#7a5c2ecc,var(--color-backlog-reset)); font-size:var(--font-size-12); margin-bottom:var(--space-10); }
        body.dark .btn-primary.reset-backlog-btn { background:linear-gradient(135deg,#7a5c2ecc,var(--color-backlog-reset)); }
        .eis-quadrant-card.do-first { border-right:var(--border-medium) solid var(--color-urgent); }
        .eis-quadrant-card.schedule { border-right:var(--border-medium) solid var(--color-undo-create); }
        .eis-quadrant-card.delegate { border-right:var(--border-medium) solid var(--color-priority-medium); }
        .eis-quadrant-card.eliminate { border-right:var(--border-medium) solid var(--color-eliminate-muted); }
        body.dark .dash-card.eis-quadrant-card.do-first { border-right-color:var(--color-urgent); }
        body.dark .dash-card.eis-quadrant-card.schedule { border-right-color:var(--color-undo-create); }
        body.dark .dash-card.eis-quadrant-card.delegate { border-right-color:var(--color-priority-medium); }
        body.dark .dash-card.eis-quadrant-card.eliminate { border-right-color:var(--color-eliminate-muted); }
        .fin-subnav.align-center { align-items:center; }
        .btn-compact-flex-none { flex:none; padding:var(--space-6) 14px; font-size:var(--font-size-12); }
        .ts-bulk-action-bar { align-items:center; gap:var(--space-8); padding:var(--space-6) 8px; margin-bottom:var(--space-8); background:var(--bg2); border-radius:var(--radius-sm); }
        body.dark .task-icon-btn.u-text-danger { color:var(--danger); }
        .habits-best-worst-body { font-size:var(--font-size-12); display:flex; gap:var(--space-14); flex-wrap:wrap; }
        .hab-heatmap-body { padding:var(--space-4); }
        .u-mt-16 { margin-top:var(--space-16); }
        .u-mt-2 { margin-top:var(--space-2); }
        .fin-quick-btn.compact { padding:var(--space-6) 14px; border-radius:var(--radius-sm); font-size:var(--font-size-12); }
        .fin-tx-hero-trend { margin-top:var(--space-10); font-size:var(--font-size-12); opacity:0.85; }
        .fin-add-income-btn { flex:1; font-size:var(--fs-body); background:var(--color-income); border-color:var(--color-income); }
        .fin-add-transfer-btn { flex:1; font-size:var(--fs-body); background:var(--color-transfer); border-color:var(--color-transfer); }
        body.dark .btn-primary.fin-add-income-btn { background:var(--color-income); }
        body.dark .btn-primary.fin-add-transfer-btn { background:var(--color-transfer); }
        .ins-range-filter-row { display:flex; gap:var(--space-6); flex-wrap:wrap; align-items:center; margin-bottom:var(--space-6); }
        .onboarding-close-btn { font-size:var(--fs-heading-sm); }
        .wrap-gap-6 { flex-wrap:wrap; gap:var(--space-6); }
        .advanced-toggle-tight { margin:var(--space-4) 0 8px; }
        /* .modal input,.modal textarea,.modal select (line ~1773) is a
           generic (0,1,1)-specificity rule; a plain .dur-custom-input class
           (0,1,0) loses to it. #addDurInput anchors on the element's own id to win. */
        .modal #addDurInput { width:100px; padding:var(--space-4) 8px; border-radius:var(--radius-sm); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.2); background:var(--bg3); text-align:center; }
        /* habitTrackRow/projectTrackRow go through hierPickerRenderTracks()
           (ui-modal-dialog.js), which does a full tRow.className = '...'
           overwrite when populated — a class added in the static markup
           would be wiped on first render, same trap as projWizardTrackRow/
           projWizardSubtrackRow (batch 10). ID-selector sidesteps it
           entirely, safe regardless of what className JS sets later. */
        #habitTrackRow, #projectTrackRow { margin-bottom:var(--space-4); }
        #habitSubtrackRow { margin-bottom:var(--space-8); }
        #habitDurInput { width:100px; padding:var(--space-4) 8px; border-radius:var(--radius-sm); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.2); background:var(--bg3); text-align:center; }
        #habitModalCount { width:80px; text-align:center; }
        #projectSubtrackRow { margin-bottom:var(--space-8); }
        .detail-stats-grid { display:grid; grid-template-columns:1fr 1fr; gap:var(--space-8); margin-bottom:var(--space-10); }
        .btn-inline-full-mt6 { width:100%; margin-top:var(--space-6); justify-content:center; }
        .modal-max-85vh { max-height:85vh; }
        .detail-narrative-text { font-size:var(--fs-body); line-height:1.6; color:var(--text1); margin:0 0 10px; }
        .detail-section-header-row { display:flex; justify-content:space-between; align-items:center; margin:var(--space-10) 0 4px; }
        .goal-detail-header-row { display:flex; align-items:center; gap:var(--space-16); margin-bottom:var(--space-12); }
        .contribution-history-title { font-size:var(--font-size-12); font-weight:600; color:var(--text3); margin:var(--space-10) 0 6px; }
        .ts-import-outline-error { color:var(--danger); margin-top:-4px; margin-bottom:var(--space-8); }
        /* ID selectors — same .modal input generic-rule trap as
           #addDurInput/#pmFormName above; their padding/background/border
           genuinely differ from the generic rule's own values. */
        #khawatiriLinkSearchInput, #khawatiriSpaceLinkSearchInput { width:100%; margin-bottom:var(--space-10); padding:var(--space-7) 10px; border-radius:var(--radius-sm); border:var(--border-hairline) solid var(--border); background:var(--bg3); color:var(--text1); font-family:inherit; }
        .knowledge-md-toolbar { display:flex; gap:var(--space-3); flex-wrap:wrap; margin-bottom:var(--space-4); }
        .knowledge-graph-body { overflow:auto; max-height:70vh; }
        .mgr-list-300 { max-height:300px; overflow-y:auto; }
        .u-flex-row-gap-8-mt10 { display:flex; gap:var(--space-8); margin-top:var(--space-10); }
        .focus-post-dialog-modal { max-width:340px; text-align:center; }
        .focus-post-dialog-icon { font-size:var(--font-size-28); margin-bottom:var(--space-8); }
        .focus-post-dialog-duration { font-size:var(--fs-body); color:var(--accent); font-weight:600; margin-bottom:var(--space-18); }
        .u-flex-col-gap-8 { display:flex; flex-direction:column; gap:var(--space-8); }
        .u-fw-600 { font-weight:600; }
        .focus-post-dialog-close-btn { border:none; color:var(--text3); font-size:var(--font-size-12); padding:var(--space-8); }
        body.dark .btn-cancel.focus-post-dialog-close-btn { color:var(--text3); }
        .u-flex-wrap { display:flex; flex-wrap:wrap; }
        .fin-tab-pills-wrap { display:flex; background:rgba(var(--accent-rgb),0.08); border-radius:var(--radius-sm); padding:var(--space-3); margin-bottom:var(--space-12); gap:var(--space-2); }
        .fin-tab-pill { flex:1; padding:var(--space-6) 4px; border:none; border-radius:var(--radius-sm); background:none; color:var(--text2); font-family:inherit; font-size:var(--font-size-12); cursor:pointer; }
        .fin-tab-pill.active { background:var(--accent); color:var(--text-on-accent); }
        .cat-mgr-gear-btn { background:none; border:none; color:var(--accent); cursor:pointer; font-size:var(--font-size-12); padding:0 4px; vertical-align:middle; }
        .bill-add-date-btn { padding:var(--space-4) 8px; border:var(--border-hairline) solid var(--border); border-radius:var(--radius-xs); background:var(--bg3); cursor:pointer; }
        #billModalReminder { width:80px; text-align:center; }
        #billDurationCustom { width:100px; padding:var(--space-4) 8px; border-radius:var(--radius-sm); border:var(--border-hairline) solid rgba(var(--accent-rgb),0.2); background:var(--bg3); text-align:center; }
        .u-mb-2 { margin-bottom:var(--space-2); }
        .goal-progress-hint { font-size:var(--fs-body); color:var(--text2); margin-bottom:var(--space-8); }
        .btn-cancel-flex-label6 { flex:1; font-size:var(--fs-label); padding:var(--space-6); }
        .fin-json-btn { flex:1; font-size:var(--font-size-12); background:var(--color-json); border-color:var(--accent); }
        body.dark .btn-primary.fin-json-btn { background:var(--color-json); }
        .backup-section-title { font-size:var(--fs-label); font-weight:600; color:var(--accent-dark); margin-bottom:var(--space-6); }
        .fin-csv-export-btn { flex:1; font-size:var(--font-size-12); background:var(--color-csv-export); border-color:var(--color-csv-export); }
        body.dark .btn-primary.fin-csv-export-btn { background:var(--color-csv-export); }
        .fin-csv-import-btn { flex:1; font-size:var(--font-size-12); background:var(--color-csv-import); border-color:var(--color-csv-import-end); }
        body.dark .btn-primary.fin-csv-import-btn { background:var(--color-csv-import); }
        .fin-master-import-btn { flex:1; font-size:var(--font-size-12); background:linear-gradient(135deg,#0a5a3a,var(--color-master-structure)); border-color:var(--color-master-structure); }
        body.dark .btn-primary.fin-master-import-btn { background:linear-gradient(135deg,#0a5a3a,var(--color-master-structure)); }
        .print-month-picker-row { gap:var(--space-6); margin-bottom:var(--space-10); align-items:center; }
        #printMonthPickerInput { padding:var(--space-6) 8px; background:var(--bg3); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-sm); color:var(--text1); font-family:inherit; }
        .print-month-confirm-btn { font-size:var(--font-size-12); padding:var(--space-6) 10px; }
        .print-preview-actions-row { display:flex; gap:var(--space-8); margin-top:var(--space-12); flex-wrap:wrap; }
        .print-now-btn { flex:2; min-width:120px; }
        .save-pdf-btn { flex:1; min-width:110px; background:var(--color-pdf); border-color:var(--color-pdf); }
        body.dark .btn-primary.save-pdf-btn { background:var(--color-pdf); }
        .print-cancel-btn { flex:1; min-width:90px; }
        .modal-max-90vh-scroll { max-height:90vh; overflow-y:auto; }
        .u-flex-row-gap-8-mt16 { display:flex; gap:var(--space-8); margin-top:var(--space-16); }
        .excel-import-confirm-btn { flex:2; font-size:var(--fs-body); background:var(--color-master-structure); border-color:var(--color-master-structure); }
        body.dark .btn-primary.excel-import-confirm-btn { background:var(--color-master-structure); }
        .dp-nav-btn { border:none; background:none; cursor:pointer; font-size:var(--font-size-16); color:var(--accent); padding:var(--space-4) 8px; }
        .dp-title { font-size:var(--fs-body); font-weight:600; color:var(--text1); }
        .dp-grid { display:grid; grid-template-columns:repeat(7,1fr); gap:var(--space-2); }
        .yesterday-intention-card { background:rgba(var(--accent-rgb),0.06); border-radius:var(--radius); padding:var(--space-12) 14px; margin-bottom:var(--space-12); }
        .yesterday-intention-label { font-size:var(--fs-label); font-weight:600; color:var(--text3); margin-bottom:var(--space-6); }
        .yesterday-intention-text { font-size:var(--fs-body); color:var(--text1); line-height:1.6; }
        .eis-grid { display:grid; grid-template-columns:1fr 1fr; gap:var(--space-10); }
        .theme-palette-swatches-row { display:flex; flex-wrap:wrap; gap:var(--space-10); padding:var(--space-6) 2px 10px; }
        .add-deps-grid { max-height:120px; overflow-y:auto; margin-top:var(--space-4); margin-bottom:var(--space-10); }
        .task-modal-delete-btn { color:var(--danger); }
        body.dark .btn-cancel.task-modal-delete-btn { color:var(--danger); }
        .achievements-unlock-count { font-size:var(--fs-label); color:var(--text3); text-align:center; margin-top:var(--space-2); }
        .achievements-grid { display:grid; grid-template-columns:1fr 1fr; gap:var(--space-8); margin-top:var(--space-4); max-height:400px; overflow-y:auto; }
        .journey-current-stage { text-align:center; padding:var(--space-14) 8px; background:var(--bg2); border-radius:var(--radius-md); margin-top:var(--space-4); }
        .journey-timeline { display:flex; flex-direction:column; gap:var(--space-8); margin-top:var(--space-12); max-height:340px; overflow-y:auto; }
        .welcome-body-text { margin:var(--space-4) 0 var(--space-14); }
        .season-archive-list { display:flex; flex-direction:column; gap:var(--space-8); margin-top:var(--space-8); max-height:420px; overflow-y:auto; }
        .sc-voice-interim { font-size:var(--font-size-12); color:var(--text3); font-style:italic; margin:var(--space-2) var(--space-2) 0; padding:0; }
        /* ID selectors (1,0,0) — inputs inside .modal, same generic-rule
           trap as #addDurInput above; an ID beats the (0,1,1) generic rule
           without needing a .modal prefix. */
        #pmFormName { margin-bottom:var(--space-8); }
        #pmFormColor { height:36px; padding:var(--space-2); margin-bottom:var(--space-8); }
        .kpi-explain-body { padding:var(--space-4) 0; font-size:var(--fs-body); line-height:1.9; }
        .refl-day-summary { background:rgba(var(--accent-rgb),0.06); border-radius:var(--radius-sm); padding:var(--space-10) 12px; margin-bottom:var(--space-14); }
        .refl-tinted-box { background:var(--bg3); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-sm); padding:var(--space-10) 12px; margin-bottom:var(--space-14); }
        .modal-textarea-noresize { width:100%; resize:none; }
        .refl-tomorrow-section { margin-top:var(--space-16); padding-top:var(--space-14); border-top:var(--border-hairline) solid var(--border); }
        .section-label-lg { font-size:var(--fs-heading-sm); font-weight:700; color:var(--text1); }
        .tags-mgr-list { max-height:320px; overflow-y:auto; margin-bottom:var(--space-10); }
        .new-tag-box { background:var(--bg3); border:var(--border-hairline) solid var(--border); border-radius:var(--radius-sm); padding:var(--space-10); margin-bottom:var(--space-8); }
        .new-tag-box-title { font-size:var(--font-size-12); font-weight:600; margin-bottom:var(--space-6); color:var(--text2); }
        .tag-add-btn { padding:0 14px; }
        .reset-all-danger-btn { width:100%; margin-top:var(--space-8); color:var(--danger); border-color:var(--danger); }
        body.dark .btn-cancel.reset-all-danger-btn { color:var(--danger); }
        .pmgr-sort-row-wrap { display:flex; gap:var(--space-6); align-items:center; justify-content:space-between; margin-bottom:var(--space-6); flex-wrap:wrap; }
        .mgr-list-360 { max-height:360px; overflow-y:auto; margin-bottom:var(--space-10); }
        .project-preview-actions { display:flex; gap:var(--space-6); margin-top:var(--space-10); }
        .mgr-list-320 { margin-bottom:var(--space-10); max-height:320px; overflow-y:auto; }
        .new-stage-add-btn { width:100%; padding:var(--space-7); }

        /* [T-289] Task archive modal (Settings -> backup -> archive). Rows are RTL-safe flex; the restore button is the shared .btn-inline (Ghost) with a 44px target. */
        .arch-month { margin-top:var(--space-12); margin-bottom:var(--space-4); font-size:var(--fs-label); font-weight:700; color:var(--text2); }
        .arch-row { display:flex; align-items:center; gap:var(--space-8); min-height:44px; padding:var(--space-6) 0; border-bottom:var(--border-hairline) solid var(--border,rgba(var(--accent-rgb),0.12)); }
        .arch-row-text { flex:1; min-width:0; }
        .arch-row-title { font-size:var(--fs-body); color:var(--text1); overflow-wrap:anywhere; }
        .arch-row-meta { font-size:var(--fs-label); color:var(--text3); }
        .arch-restore-btn { min-width:44px; min-height:44px; flex-shrink:0; }
        .arch-live-note { font-size:var(--fs-label); color:var(--text3); flex-shrink:0; }
        .arch-empty, .arch-note { padding:var(--space-12) 0; font-size:var(--fs-label); color:var(--text3); text-align:center; }
        /* [T-358 P5] what 4 one-off style="" attributes in masari.html used to carry. */
        .task-icon-btn.sc-voice-btn { position:absolute; left:6px; bottom:8px; }
        .modal-label.pm-form-inherit-row { align-items:center; }
        textarea.ts-import-outline-textarea { resize:vertical; }
        .modal-label.confirm-modal-body { white-space:pre-line; }

        /* the two <style> blocks the insight charts carried inside their SVG (a <style> element is blocked by the CSP) */
        .svg-label { fill:var(--text2); }
        .svg-value { fill:var(--text2); }

        /* [T-358 P6] sx-*: what a few static style="" attributes of JS-built markup used to carry (one class per former attribute, the exact declarations).
           Only where no rule of this file that could match the element is more specific than a single class (tests/phase142 checks it with
           tests/lib/sxCascade.js, so a future rule cannot silently out-rank one); this block is the LAST of the file, so an equal rule loses to it.
           Every other static or run-time value is a data-css attribute (dataStyle in ui-safe-html.js), applied by CSSOM: exactly an inline style. */
        .sx-top-0 { top:0%; }
        .sx-justify-content-space-between { justify-content:space-between; }
        .sx-group-color-var-accent { --group-color:var(--accent); }
        .sx-align-items-flex-start { align-items:flex-start; }
        .sx-margin-bottom-var-space-10 { margin-bottom:var(--space-10); }
        .sx-margin-0 { margin:0; }
        .sx-opacity-65 { opacity:.65; }
        .sx-max-height-220px-overflow-y-auto { max-height:220px; overflow-y:auto; }
        .sx-text-align-center-flex-1 { text-align:center; flex:1; }
