/*
 * CommonLynk — Canonical Design Tokens
 * Always reference via var(--cl-*). Never hardcode hex values in new code.
 *
 * Token roles:
 *   --cl-ink      primary text, headings, navbar            (was old navy hex)
 *   --cl-paper    page and card background                  (was old cream hex)
 *   --cl-accent   CTAs, active states, highlights           (was old gold hex)
 *   --cl-teal     secondary actions, success states         (tokenised teal)
 *   --cl-danger   destructive actions, delete buttons, error states
 *                 (replaces the retired burgundy where it was used for danger)
 *   --cl-muted    muted body text, hints, secondary labels
 *   --cl-sidebar  sidebar background — defaults to --cl-ink; tenant base.html
 *                 may override per OrgProfile.nav_color
 *   --cl-border   subtle 1px border / divider — derived from --cl-ink
 *
 * Per-template :root blocks in templates/base.html and templates/landing/base.html
 * still declare local aliases (--navy, --teal, --gold, --burgundy etc.). The
 * legacy hex literals they used to hold have been swept to var(--cl-*) refs.
 */

/* Global scrollbar — gold thumb on neutral track. Overridden in
   templates/base.html for the .sidebar (translucent white on the navy
   sidebar background reads cleaner than gold). */
::-webkit-scrollbar{width:4px;height:4px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:var(--cl-accent);border-radius:999px}
::-webkit-scrollbar-thumb:hover{background:var(--cl-ink)}
*{scrollbar-width:thin;scrollbar-color:var(--cl-accent) transparent}

:root{
  /* Core palette */
  --cl-ink:    #0B1F3A;  /* Dark navy — primary text, headings, navbar */
  --cl-paper:  #F5F2EC;  /* Off-white — page & card backgrounds */
  --cl-accent: #C4A875;  /* Warm gold — CTAs, active states, highlights */
  --cl-teal:   #3FA68D;  /* Teal — secondary actions, success states */
  --cl-teal-dark: #0F6E56;  /* Dark teal — done/complete text on teal-tinted fills */
  --cl-danger: #C0392B;  /* Destructive actions, delete buttons, error states */
  --cl-muted:  #5F6672;  /* Muted body text, hints, secondary labels.
                            WCAG 1.4.3 / §4j rule 4: 5.25:1 on --cl-paper and
                            5.85:1 on white (D1, 2026-10-26; was #646B77 at
                            4.81 / 5.37, and #6B7280 before that, which failed).
                            core.tests_theme_tokens recomputes these from this file. */
  --cl-text-2: #5F6672;  /* D1: secondary HEADINGS (a card's or a page's sub line).
                            Light takes the colour those lines already used, which
                            is --cl-muted; dark lifts them a step above muted. */
  --cl-control-border: #8F897D; /* D1: the border of an INPUT or other control —
                            WCAG 1.4.11 wants 3:1 for the edge that tells you a field
                            is there (3.24 on paper, 3.57 on white). --cl-border stays
                            the decorative hairline. */

  /* Extended status palette */
  --cl-info:    #1565C0;             /* Informational accents, info banners, links */
  --cl-warning: #B45309;             /* Warning/attention text & badges (amber) */
  --cl-purple:  #7C3AED;             /* Category/tag accents */
  --cl-white:   #FFFFFF;             /* True white card surfaces & inverse text */
  --cl-page:    #FDFCF9;             /* Marketing ground — a lighter paper. The
                                        PRODUCT (tenant + Platform Admin) stays
                                        on --cl-paper; this is the landing site's
                                        airier surface, deliberately a separate
                                        token so restyling marketing can never
                                        move the workspace ground. */
  --cl-warm:    #F5F1E9;             /* Marketing rhythm band — a warm fill one
                                        step darker than --cl-page, used to
                                        separate marketing sections without
                                        introducing a second ground colour.
                                        The PRODUCT uses it once: the LynkView
                                        selection pill (owner, 2026-10-22). */
  --cl-accent-text: #7A6234;         /* Gold for TEXT on a light ground (REM-757,
                                        Build 5): 5.2:1 on paper, 5.8:1 on white.
                                        --cl-accent is 2.0:1 and --cl-accent-deep
                                        3.0:1 there — both fail WCAG 1.4.3 for
                                        text under 24px. */
  --cl-accent-deep: #A6884F;         /* Deep gold — accent hover/pressed and gold
                                        text that must clear contrast on a light
                                        ground (--cl-accent alone does not). */
  --cl-shadow:  rgba(11, 31, 58, 0.15); /* Ink-tinted drop shadow */

  /* Comma-separated RGB triplets of the core colors, for translucency.
     rgba() cannot take a hex custom property as its color argument, so
     rgba(var(--cl-accent), .1) silently fails — use rgba(var(--cl-accent-rgb), .1).
     Keep each triplet in sync with the hex above it. */
  --cl-ink-rgb:    11, 31, 58;
  --cl-paper-rgb:  245, 242, 236;
  --cl-accent-rgb: 196, 168, 117;
  --cl-danger-rgb: 192, 57, 43;
  --cl-white-rgb:  255, 255, 255;

  /* D1 — text and hairlines ON a dark slab (the Rail, --cl-surface, a navy band).
     A dark slab stays dark in both themes, so what sits on it is light in both:
     never write var(--cl-white) for that — in dark --cl-white is the CARD. */
  --cl-on-surface:     #FFFFFF;
  --cl-on-surface-rgb: 255, 255, 255;
  /* D1 — colour-mix() partners. A mix may only name tokens (owner ruling,
     guarded by core.tests_theme_tokens), so the darken/lighten partners are
     tokens too: --cl-shade darkens in both themes; --cl-tint lifts toward the
     raised surface, which is white by day and the warm slab by night. */
  --cl-shade: #000000;
  --cl-shade-rgb: 0, 0, 0;
  --cl-on-gold: #0B1F3A;   /* D1: text on the gold accent — navy in BOTH themes (ink turns light in dark) */   /* backdrops and shadows: rgba(var(--cl-shade-rgb), a) */
  --cl-tint:  #FFFFFF;

  /* Light tint backgrounds — paired with their status colors */
  --cl-teal-bg:    #EAF6F2;   /* success/teal state backgrounds */
  --cl-danger-bg:  #FDECEA;   /* error/danger state backgrounds */
  --cl-info-bg:    #EEF4FB;   /* info state backgrounds */
  --cl-warning-bg: #FEF3E2;   /* warning state backgrounds */

  /* ── Attention banners (the amber "act on your subscription" family) ──
     A SEPARATE ramp from --cl-warning / --cl-warning-bg above, which is the
     inline warning TEXT + badge pair. These three are the filled banner
     treatment: a tinted card with its own hairline and high-contrast body
     copy. Keeping them apart is deliberate — folding the banner into
     --cl-warning would restyle every warning badge on the platform.

     Two severities, because the tenant app shell renders two different
     messages: --cl-warn-* is the workspace-is-read-only grace banner (and the
     .cl-badge-gold pair, which was a verbatim second copy of it), while
     --cl-warn-soft-* is the dismissible "renews in N days" heads-up. */
  --cl-warn-bg:          #FEF3C7;   /* grace banner + gold badge fill */
  --cl-warn-text:        #92400E;   /* grace banner + gold badge copy */
  --cl-warn-border:      #FDE68A;   /* grace banner hairline */
  --cl-warn-soft-bg:     #FEF9C3;   /* expiry-soon banner fill */
  --cl-warn-soft-text:   #854D0E;   /* expiry-soon banner copy */
  --cl-warn-soft-border: #FEF08A;   /* expiry-soon banner hairline */

  /* Derived semantic tokens */
  --cl-text:        var(--cl-ink);
  --cl-bg:          var(--cl-paper);
  --cl-sidebar:     var(--cl-ink);   /* Sidebar background — overridden per-tenant in base.html */
  --cl-surface:     #0B1F3A;         /* Dark navy surface (buttons, badges, popovers) — pinned, never follows tenant text color */
  /* D1 (2026-08-27) — the PRIMARY button is NAVY, not gold.
     Gold is now the ACCENT role plus the on-navy inversion only. These two
     tokens had ZERO consumers when the decision landed (`.cl-btn--primary` in
     commonlynk.components.css already hardcoded var(--cl-ink)), so flipping
     them changed no pixel — it makes the token layer AGREE with the component
     layer, which is what stops the next author reading `--cl-btn-primary` and
     building a gold button that no longer matches anything. */
  --cl-btn-primary: var(--cl-ink);
  --cl-btn-text:    var(--cl-white);
  --cl-success:     var(--cl-teal);
  --cl-border:      #E8E8E5;   /* Subtle 1px border / divider */

  /* Focus / selection halo — the ring drawn behind a focused control, as
     `box-shadow: 0 0 0 var(--cl-focus-ring-width) var(--cl-focus-ring)`. A COLOUR rather than a whole
     shadow, because that is the shape every caller already uses.
     It was REFERENCED here and defined nowhere: an undefined custom property
     makes the whole declaration invalid, so any template that did not alias it
     locally rendered no focus ring at all. Keyboard operators have to be able to
     see which field they are in, and some of those fields hold credentials. */
  /* WCAG 2.2 §1.4.11 / §2.4.7 (§4j rule 2): a focus ring must reach 3:1 against
     EVERY ground it lands on. The old translucent gold was ~2:1 on paper and
     invisible on the navy sidebar. A solid #2563EB is >=3:1 on paper (4.63),
     white (5.17), --cl-page (5.04) AND navy (3.20), so one token serves the whole
     app. Do not revert to the accent — accent-on-paper is 2.04:1.
     Token v4 (owner 2026-10-18): FOCUS IS NEVER BLUE. The ring is INK, 2 px:
     16.6:1 on white, 15.2:1 on paper. Ink on the navy Rail would vanish, so
     every DARK surface redefines the token to white (12.6:1 on navy) below —
     one token, two grounds, never blue and never gold (gold is 2.2:1 on white). */
  --cl-focus-ring:  var(--cl-ink);
  --cl-focus-ring-width: 2px;

  /* Typography */
  --cl-font-sans:"Inter Tight","Helvetica Neue",Helvetica,Arial,sans-serif;
  --cl-font-mono:"JetBrains Mono",ui-monospace,Menlo,Monaco,Consolas,monospace;
  --cl-fs-display:56px;
  --cl-fs-h1:36px;
  --cl-fs-h2:22px;
  --cl-fs-h3:15px;
  --cl-fs-body:14px;
  --cl-fs-small:12px;
  --cl-fs-control:13px; /* §4.4: the compact control label (the top-bar Add, token v4) */
  --cl-fs-label:12px;   /* was 10px — REM-370: nothing a person reads is under 12px */
  /* Form FIELD label (above an input). NOT --cl-fs-label, which is the
     uppercase tracked eyebrow used over sections and stats. */
  --cl-fs-field-label:13px;
  --cl-report-head-row:37px;   /* the report table's first header row height: the second row sticks under it */
  --cl-fw-light:300;
  --cl-fw-regular:400;
  --cl-fw-medium:500;
  --cl-fw-semibold:600;
  --cl-fw-bold:700;
  /* Tracking — for Latin, Greek, Cyrillic, Armenian and Georgian only. The
     generated block below this :root sets all three to 0 for every other
     script (core/script_tracking.py, REM-643). */
  --cl-track-display:-0.03em;
  --cl-track-heading:-0.02em;
  --cl-track-label:0.18em;
  /* D1 — a FIGURE (a number shown at 20px or more: a stat, a KPI, a chart
     total) is Inter Tight in every language, tabular, semibold, tracked in. */
  --cl-font-figure:"Inter Tight","Helvetica Neue",Helvetica,Arial,sans-serif;
  --cl-fw-figure:600;
  --cl-track-figure:-0.02em;

  /* Map choropleth — a 5-step sequential ramp from paper to ink (indicators
     map + the donor report's map figure, 2026-10-09). Low → high. */
  --cl-map-1: #EDE6D6;
  --cl-map-2: #D7C49C;
  --cl-map-3: #A8956E;
  --cl-map-4: #4F6383;
  --cl-map-5: #0B1F3A;
  --cl-map-none: #F1EFEA;
  --cl-map-stroke: #5C6B80;
  /* D2: project markers are NEUTRAL (surface fill, ink outline); red is
     reserved for "off track". */
  --cl-map-marker: var(--cl-ink);

  /* D1 — chart series (categorical, in this order) and their tints. Marks
     reach 3:1 on paper and white; chart-none is "no data / no target". Read them
     through static/js/cl_charts.js, never as literals in a page. */
  --cl-chart-1: #2E8A73;  --cl-chart-1-bg: #E3F1EC;
  --cl-chart-2: #9A7C45;  --cl-chart-2-bg: #F4EEE2;
  --cl-chart-3: #3F78B8;  --cl-chart-3-bg: #E7EFF8;
  --cl-chart-4: #C2603F;  --cl-chart-4-bg: #F8E9E3;
  --cl-chart-5: #8C6BBF;  --cl-chart-5-bg: #EFEAF7;
  --cl-chart-none: #8F897D; --cl-chart-none-bg: #F2F1EF;

  /* D1 — status: a MARK (3:1 dot/bar/fill), its TEXT (4.5:1 on its bg) and its
     BG. On track / at risk / off track / no target. Status is never colour
     alone: every use carries the word (design system §D1). */
  --cl-status-ok: #2E8A73;    --cl-status-ok-text: #1F6E5A;    --cl-status-ok-bg: #E6F4EF;
  --cl-status-risk: #B45309;  --cl-status-risk-text: #92400E;  --cl-status-risk-bg: #FEF3E2;
  --cl-status-off: #C0392B;   --cl-status-off-text: #9B2C20;   --cl-status-off-bg: #FDECEA;
  --cl-status-none: #8F897D;  --cl-status-none-text: #5F6672;  --cl-status-none-bg: #F3F0EA;
  /* A count badge (utility bar) sits on --cl-status-risk: white by day (5.02:1),
     navy by night (white on the light amber is 2.20:1). */
  --cl-badge-text: #FFFFFF;

  /* D1 — the dark Rail. base.html overrides it per workspace with nav_color
     mixed 40% toward this value (computed in Python, core.theme). */
  --cl-rail-dark: #0A111B;
  /* D1 — the workspace accent in DARK. base.html writes the workspace's own
     brand_color here when it reaches 3:1 on the dark paper, else this default
     (core.theme.accent_on_dark). Light always uses the brand as given. */
  --cl-accent-on-dark: #C4A875;
  /* D1 — the plate a logo or picture without transparency sits on: light in
     both themes, so a white-boxed logo never floats as a white slab on dark. */
  --cl-plate: #FFFFFF;

  /* D1 — density. Comfortable here; [data-density="compact"] below. Row and
     control heights shrink only for a fine pointer, so a compact phone keeps
     44px taps (Rule 25). */
  --cl-space-card: 18px;
  --cl-gap: 16px;
  --cl-row-h: 44px;
  --cl-dash-row: 112px;
  --cl-control-h: 40px;
  /* D1: a chart frame's height (_partials/cl_chart.html sets it per chart). */
  --cl-chart-h: 260px;

  /* === Component Tokens === */

  /* Buttons */
  --cl-btn-padding-y: 0.5rem;
  --cl-btn-padding-x: 1.1rem;
  --cl-btn-padding-y-sm: 0.3rem;
  --cl-btn-padding-x-sm: 0.75rem;
  --cl-btn-padding-y-lg: 0.65rem;
  --cl-btn-padding-x-lg: 1.5rem;
  --cl-btn-font-size: 0.875rem;
  --cl-btn-font-size-sm: 0.8rem;
  --cl-btn-font-weight: 600;
  --cl-btn-radius: 6px;
  --cl-btn-transition: background 150ms ease, opacity 150ms ease, box-shadow 150ms ease;

  /* Surfaces */
  --cl-radius-sm: 4px;
  --cl-radius-md: 8px;
  --cl-radius-lg: 12px;
  --cl-radius-card: 12px;
  --cl-radius-modal: 14px;
  --cl-radius-badge: 999px;

  /* Elevation */
  --cl-shadow-sm: 0 1px 3px var(--cl-shadow);
  --cl-shadow-md: 0 4px 12px var(--cl-shadow);
  --cl-shadow-lg: 0 8px 24px var(--cl-shadow);
  /* Named ROLE, not a fourth size: the lift a Hub card takes on hover
     (design system 9.3). Aliased so the card never names a raw shadow. */
  --cl-shadow-lift: var(--cl-shadow-md);
  /* Named ROLE (Build 6, design system 5.11.8): the edge shadow a pinned table
     zone casts where the scrolling middle passes under it. Physical x for LTR;
     mirrored for RTL below. */
  --cl-shadow-pin-start: 6px 0 6px -4px var(--cl-shadow);
  --cl-shadow-pin-end: -6px 0 6px -4px var(--cl-shadow);

  /* Transitions */
  --cl-transition-fast: 120ms ease;
  --cl-transition: 200ms ease;
  --cl-transition-slow: 350ms ease;
}

/* ── D1 dark theme (2026-10-26) ───────────────────────────────────────────
   <html data-theme="light|dark|auto"> (UserProfile.theme; the apex auth pages
   are always "auto"). The SAME body twice — once for an explicit "dark", once
   for "auto" when the device prefers dark — and core.tests_theme_tokens holds
   the two copies byte-equal and fails on any colour token in :root that the
   dark body neither redefines nor lists as theme-invariant.
   Screens only: exports, emails and PRINTED pages are always light.
   Specificity (0,2,0) beats the workspace's own `:root{}` brand overrides in
   base.html, so a workspace text/background colour is a LIGHT-theme setting.
   The workspace accent (brand_color) is kept; the dark Rail is nav_color mixed
   40% toward --cl-rail-dark, written by base.html as --cl-rail-dark. */
/* BEGIN DARK */
@media screen {
:root[data-theme="dark"] {
  --cl-ink: #EEF1F5;
  --cl-paper: #0E1622;
  --cl-white: #152030;
  --cl-warm: #1B2A3E;
  --cl-page: #0E1622;
  --cl-text: var(--cl-ink);
  --cl-bg: var(--cl-paper);
  --cl-text-2: #C3CAD4;
  --cl-muted: #9AA4B2;
  --cl-border: #22324A;
  --cl-control-border: #6E7F9A;
  --cl-focus-ring: #EEF1F5;
  --cl-shadow: rgba(0, 0, 0, 0.35);
  --cl-ink-rgb: 238, 241, 245;
  --cl-paper-rgb: 14, 22, 34;
  --cl-white-rgb: 21, 32, 48;
  --cl-danger-rgb: 224, 112, 95;
  --cl-btn-primary: #C4A875;
  --cl-btn-text: #0B1F3A;
  --cl-sidebar: var(--cl-rail-dark);
  --cl-surface: #22324A;
  --cl-on-surface: #EEF1F5;
  --cl-on-surface-rgb: 238, 241, 245;
  --cl-tint: #22324A;
  --cl-teal: #4FC2A5;
  --cl-teal-dark: #7FD9C1;
  --cl-danger: #E0705F;
  --cl-info: #86B2E6;
  --cl-warning: #E8A048;
  --cl-purple: #B49BDC;
  --cl-accent-text: #D9BE88;
  --cl-accent-deep: #D9BE88;
  --cl-teal-bg: #16352F;
  --cl-danger-bg: #3B2228;
  --cl-info-bg: #1E2E45;
  --cl-warning-bg: #3A2E1B;
  --cl-warn-bg: #3A2E1B;
  --cl-warn-text: #F2BE7A;
  --cl-warn-border: #5A4526;
  --cl-warn-soft-bg: #33301B;
  --cl-warn-soft-text: #EBD58A;
  --cl-warn-soft-border: #4F4A26;
  --cl-map-1: #24324A;
  --cl-map-2: #3E5272;
  --cl-map-3: #6E7F9A;
  --cl-map-4: #B39A6B;
  --cl-map-5: #E9D7AE;
  --cl-map-none: #1B2A3E;
  --cl-map-stroke: #9AA4B2;
  --cl-map-marker: var(--cl-ink);
  --cl-chart-1: #4FC2A5;  --cl-chart-1-bg: #1E3A43;
  --cl-chart-2: #D9BE88;  --cl-chart-2-bg: #34393E;
  --cl-chart-3: #86B2E6;  --cl-chart-3-bg: #27374D;
  --cl-chart-4: #F0A085;  --cl-chart-4-bg: #38343E;
  --cl-chart-5: #B49BDC;  --cl-chart-5-bg: #2E344C;
  --cl-chart-none: #6E7F9A; --cl-chart-none-bg: #232F41;
  --cl-status-ok: #4FC2A5;    --cl-status-ok-text: #7FD9C1;    --cl-status-ok-bg: #16352F;
  --cl-status-risk: #E8A048;  --cl-status-risk-text: #F2BE7A;  --cl-status-risk-bg: #3A2E1B;
  --cl-status-off: #E0705F;   --cl-status-off-text: #F2A094;   --cl-status-off-bg: #3B2228;
  --cl-status-none: #6E7F9A;  --cl-status-none-text: #C3CAD4;  --cl-status-none-bg: #1B2A3E;
  --cl-badge-text: #0B1F3A;
  --cl-accent: var(--cl-accent-on-dark);
  color-scheme: dark;
}
}
@media screen and (prefers-color-scheme: dark) {
:root[data-theme="auto"] {
  --cl-ink: #EEF1F5;
  --cl-paper: #0E1622;
  --cl-white: #152030;
  --cl-warm: #1B2A3E;
  --cl-page: #0E1622;
  --cl-text: var(--cl-ink);
  --cl-bg: var(--cl-paper);
  --cl-text-2: #C3CAD4;
  --cl-muted: #9AA4B2;
  --cl-border: #22324A;
  --cl-control-border: #6E7F9A;
  --cl-focus-ring: #EEF1F5;
  --cl-shadow: rgba(0, 0, 0, 0.35);
  --cl-ink-rgb: 238, 241, 245;
  --cl-paper-rgb: 14, 22, 34;
  --cl-white-rgb: 21, 32, 48;
  --cl-danger-rgb: 224, 112, 95;
  --cl-btn-primary: #C4A875;
  --cl-btn-text: #0B1F3A;
  --cl-sidebar: var(--cl-rail-dark);
  --cl-surface: #22324A;
  --cl-on-surface: #EEF1F5;
  --cl-on-surface-rgb: 238, 241, 245;
  --cl-tint: #22324A;
  --cl-teal: #4FC2A5;
  --cl-teal-dark: #7FD9C1;
  --cl-danger: #E0705F;
  --cl-info: #86B2E6;
  --cl-warning: #E8A048;
  --cl-purple: #B49BDC;
  --cl-accent-text: #D9BE88;
  --cl-accent-deep: #D9BE88;
  --cl-teal-bg: #16352F;
  --cl-danger-bg: #3B2228;
  --cl-info-bg: #1E2E45;
  --cl-warning-bg: #3A2E1B;
  --cl-warn-bg: #3A2E1B;
  --cl-warn-text: #F2BE7A;
  --cl-warn-border: #5A4526;
  --cl-warn-soft-bg: #33301B;
  --cl-warn-soft-text: #EBD58A;
  --cl-warn-soft-border: #4F4A26;
  --cl-map-1: #24324A;
  --cl-map-2: #3E5272;
  --cl-map-3: #6E7F9A;
  --cl-map-4: #B39A6B;
  --cl-map-5: #E9D7AE;
  --cl-map-none: #1B2A3E;
  --cl-map-stroke: #9AA4B2;
  --cl-map-marker: var(--cl-ink);
  --cl-chart-1: #4FC2A5;  --cl-chart-1-bg: #1E3A43;
  --cl-chart-2: #D9BE88;  --cl-chart-2-bg: #34393E;
  --cl-chart-3: #86B2E6;  --cl-chart-3-bg: #27374D;
  --cl-chart-4: #F0A085;  --cl-chart-4-bg: #38343E;
  --cl-chart-5: #B49BDC;  --cl-chart-5-bg: #2E344C;
  --cl-chart-none: #6E7F9A; --cl-chart-none-bg: #232F41;
  --cl-status-ok: #4FC2A5;    --cl-status-ok-text: #7FD9C1;    --cl-status-ok-bg: #16352F;
  --cl-status-risk: #E8A048;  --cl-status-risk-text: #F2BE7A;  --cl-status-risk-bg: #3A2E1B;
  --cl-status-off: #E0705F;   --cl-status-off-text: #F2A094;   --cl-status-off-bg: #3B2228;
  --cl-status-none: #6E7F9A;  --cl-status-none-text: #C3CAD4;  --cl-status-none-bg: #1B2A3E;
  --cl-badge-text: #0B1F3A;
  --cl-accent: var(--cl-accent-on-dark);
  color-scheme: dark;
}
}
/* END DARK */

/* ── D1 density ───────────────────────────────────────────────────────────
   <html data-density="comfortable|compact"> (UserProfile.density). Spacing
   tightens everywhere; row and control heights only under a fine pointer. */
:root[data-density="compact"] {
  --cl-space-card: 12px;
  --cl-gap: 10px;
  --cl-dash-row: 96px;
}
@media (pointer: fine) {
  :root[data-density="compact"] {
    --cl-row-h: 36px;
    --cl-control-h: 34px;
  }
}

/* A FIGURE (D1): any number shown at 20px or more. */
.cl-figure {
  font-family: var(--cl-font-figure);
  font-weight: var(--cl-fw-figure);
  letter-spacing: var(--cl-track-figure);
  font-variant-numeric: tabular-nums;
}

/* BEGIN GENERATED: script tracking (manage.py build_script_tracking_css) */
/* Do not edit by hand: core/script_tracking.py renders this from
   settings.LANGUAGES and CLDR, and core.tests_script_tracking fails on drift.
   Letter-spacing stays ON only for a language written in: Latn Grek Cyrl Armn Geor.
   Every other script gets 0 - tracking pulls joined and shaped letters
   apart (REM-643). Form fields and code boxes keep theirs. */
:root:not(:lang(af)):not(:lang(ast)):not(:lang(az)):not(:lang(be)):not(:lang(bg)):not(:lang(br)):not(:lang(bs)):not(:lang(ca)):not(:lang(cs)):not(:lang(cy)):not(:lang(da)):not(:lang(de)):not(:lang(dsb)):not(:lang(el)):not(:lang(en)):not(:lang(eo)):not(:lang(es)):not(:lang(et)):not(:lang(eu)):not(:lang(fi)):not(:lang(fr)):not(:lang(fy)):not(:lang(ga)):not(:lang(gd)):not(:lang(gl)):not(:lang(ha)):not(:lang(hr)):not(:lang(hsb)):not(:lang(hu)):not(:lang(hy)):not(:lang(ia)):not(:lang(id)):not(:lang(ig)):not(:lang(io)):not(:lang(is)):not(:lang(it)):not(:lang(ka)):not(:lang(kab)):not(:lang(kk)):not(:lang(ky)):not(:lang(lb)):not(:lang(lt)):not(:lang(lv)):not(:lang(mk)):not(:lang(mn)):not(:lang(ms)):not(:lang(nb)):not(:lang(nl)):not(:lang(nn)):not(:lang(os)):not(:lang(pl)):not(:lang(pt)):not(:lang(ro)):not(:lang(ru)):not(:lang(sk)):not(:lang(sl)):not(:lang(so)):not(:lang(sq)):not(:lang(sr)):not(:lang(sv)):not(:lang(sw)):not(:lang(tg)):not(:lang(tk)):not(:lang(tr)):not(:lang(tt)):not(:lang(udm)):not(:lang(uk)):not(:lang(uz)):not(:lang(vi)):not(:lang(yo)){--cl-track-display:0; --cl-track-heading:0; --cl-track-label:0;}
:not(:lang(af)):not(:lang(ast)):not(:lang(az)):not(:lang(be)):not(:lang(bg)):not(:lang(br)):not(:lang(bs)):not(:lang(ca)):not(:lang(cs)):not(:lang(cy)):not(:lang(da)):not(:lang(de)):not(:lang(dsb)):not(:lang(el)):not(:lang(en)):not(:lang(eo)):not(:lang(es)):not(:lang(et)):not(:lang(eu)):not(:lang(fi)):not(:lang(fr)):not(:lang(fy)):not(:lang(ga)):not(:lang(gd)):not(:lang(gl)):not(:lang(ha)):not(:lang(hr)):not(:lang(hsb)):not(:lang(hu)):not(:lang(hy)):not(:lang(ia)):not(:lang(id)):not(:lang(ig)):not(:lang(io)):not(:lang(is)):not(:lang(it)):not(:lang(ka)):not(:lang(kab)):not(:lang(kk)):not(:lang(ky)):not(:lang(lb)):not(:lang(lt)):not(:lang(lv)):not(:lang(mk)):not(:lang(mn)):not(:lang(ms)):not(:lang(nb)):not(:lang(nl)):not(:lang(nn)):not(:lang(os)):not(:lang(pl)):not(:lang(pt)):not(:lang(ro)):not(:lang(ru)):not(:lang(sk)):not(:lang(sl)):not(:lang(so)):not(:lang(sq)):not(:lang(sr)):not(:lang(sv)):not(:lang(sw)):not(:lang(tg)):not(:lang(tk)):not(:lang(tr)):not(:lang(tt)):not(:lang(udm)):not(:lang(uk)):not(:lang(uz)):not(:lang(vi)):not(:lang(yo)):not(input):not(textarea):not(code):not(kbd):not(samp):not(pre):not([data-cl-tracking-keep]),
:not(:lang(af)):not(:lang(ast)):not(:lang(az)):not(:lang(be)):not(:lang(bg)):not(:lang(br)):not(:lang(bs)):not(:lang(ca)):not(:lang(cs)):not(:lang(cy)):not(:lang(da)):not(:lang(de)):not(:lang(dsb)):not(:lang(el)):not(:lang(en)):not(:lang(eo)):not(:lang(es)):not(:lang(et)):not(:lang(eu)):not(:lang(fi)):not(:lang(fr)):not(:lang(fy)):not(:lang(ga)):not(:lang(gd)):not(:lang(gl)):not(:lang(ha)):not(:lang(hr)):not(:lang(hsb)):not(:lang(hu)):not(:lang(hy)):not(:lang(ia)):not(:lang(id)):not(:lang(ig)):not(:lang(io)):not(:lang(is)):not(:lang(it)):not(:lang(ka)):not(:lang(kab)):not(:lang(kk)):not(:lang(ky)):not(:lang(lb)):not(:lang(lt)):not(:lang(lv)):not(:lang(mk)):not(:lang(mn)):not(:lang(ms)):not(:lang(nb)):not(:lang(nl)):not(:lang(nn)):not(:lang(os)):not(:lang(pl)):not(:lang(pt)):not(:lang(ro)):not(:lang(ru)):not(:lang(sk)):not(:lang(sl)):not(:lang(so)):not(:lang(sq)):not(:lang(sr)):not(:lang(sv)):not(:lang(sw)):not(:lang(tg)):not(:lang(tk)):not(:lang(tr)):not(:lang(tt)):not(:lang(udm)):not(:lang(uk)):not(:lang(uz)):not(:lang(vi)):not(:lang(yo))::before,
:not(:lang(af)):not(:lang(ast)):not(:lang(az)):not(:lang(be)):not(:lang(bg)):not(:lang(br)):not(:lang(bs)):not(:lang(ca)):not(:lang(cs)):not(:lang(cy)):not(:lang(da)):not(:lang(de)):not(:lang(dsb)):not(:lang(el)):not(:lang(en)):not(:lang(eo)):not(:lang(es)):not(:lang(et)):not(:lang(eu)):not(:lang(fi)):not(:lang(fr)):not(:lang(fy)):not(:lang(ga)):not(:lang(gd)):not(:lang(gl)):not(:lang(ha)):not(:lang(hr)):not(:lang(hsb)):not(:lang(hu)):not(:lang(hy)):not(:lang(ia)):not(:lang(id)):not(:lang(ig)):not(:lang(io)):not(:lang(is)):not(:lang(it)):not(:lang(ka)):not(:lang(kab)):not(:lang(kk)):not(:lang(ky)):not(:lang(lb)):not(:lang(lt)):not(:lang(lv)):not(:lang(mk)):not(:lang(mn)):not(:lang(ms)):not(:lang(nb)):not(:lang(nl)):not(:lang(nn)):not(:lang(os)):not(:lang(pl)):not(:lang(pt)):not(:lang(ro)):not(:lang(ru)):not(:lang(sk)):not(:lang(sl)):not(:lang(so)):not(:lang(sq)):not(:lang(sr)):not(:lang(sv)):not(:lang(sw)):not(:lang(tg)):not(:lang(tk)):not(:lang(tr)):not(:lang(tt)):not(:lang(udm)):not(:lang(uk)):not(:lang(uz)):not(:lang(vi)):not(:lang(yo))::after{letter-spacing:0 !important;}
/* END GENERATED: script tracking */

/* ── Phone input widget (templates/components/phone_input.html) ───────────
   The tenant portal does not load Bootstrap, so the widget can't rely on
   .input-group / .form-select. These rules render the country-code select
   and the number field as one cohesive input group: [🇪🇬 +20][ number … ]. */
/* NB: `overflow: hidden` here used to clip the country-code dropdown. The
   dropdown is position:absolute inside .phone-picker (position:relative), and
   that containing block is a DESCENDANT of this box, so the clip applied
   (CSS 2.1 §11.1.1). Worse, this box then became a scroll container, so the
   picker's search.focus() scrolled the clipped dropdown into view — dragging a
   search box into the pill where the number input had been. The rounded corners
   it was there for are now done with logical radii on the end children. */
.phone-input-group {
  display: flex;
  border: 1px solid var(--cl-control-border);
  border-radius: 6px;
  overflow: visible;
  background: var(--cl-white);
}
/* Logical, so the pill stays correct when the row flips under [dir=rtl].
   `.phone-picker` covers the current core/_phone_field.html markup (which does
   not use the --embedded modifier); only the left-corner radii are ported —
   not min-width — so the +20 button stays content-width. */
.phone-input-group > .phone-picker--embedded,
.phone-input-group > .phone-picker {
  border-start-start-radius: 6px;
  border-end-start-radius: 6px;
}
.phone-input-group > .phone-status {
  border-start-end-radius: 6px;
  border-end-end-radius: 6px;
}
.phone-input-group:focus-within {
  border-color: var(--cl-accent);
  box-shadow: 0 0 0 3px rgba(var(--cl-accent-rgb), 0.15);
}
.phone-number-input {
  border: none;
  flex: 1;
  padding: 0.5rem 0.75rem;
  font-size: 0.875rem;
  outline: none;
  background: transparent;
  color: var(--cl-ink);
  min-width: 0;              /* let the field shrink inside the flex group */
}
.phone-number-input::placeholder { color: var(--cl-muted); }
/* Live E.164 validation badge appended by static/js/localization.js. It
   toggles the d-none / text-* classes the script already emits. */
.phone-status {
  display: flex;
  align-items: center;
  padding: 0 0.625rem;
  font-size: 0.85rem;
  background: var(--cl-paper);
  border-inline-start: 1px solid var(--cl-border);
}
.phone-status.d-none      { display: none; }
.phone-status.text-success { color: var(--cl-teal); }
.phone-status.text-danger  { color: var(--cl-danger); }
.phone-status.text-muted   { color: var(--cl-muted); }

/* ── Flag-button country-code picker (P04, 2026-05-26) ─────────────────────
   Used standalone (templates/core/_phone_picker.html) and as the country-code
   half of templates/components/phone_input.html. Drop-in replacement for the
   prior native <select>; same data attributes so localization.js wires up. */
.phone-picker { position: relative; display: inline-block; min-width: 0; }
.phone-picker--embedded {
  /* When embedded inside .phone-input-group flex row */
  border-inline-end: 1px solid var(--cl-border);
  background: var(--cl-paper);
}
.phone-picker-btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 0.5rem 0.625rem;
  background: transparent;
  border: 1px solid var(--cl-border);
  border-radius: 6px;
  font-size: 0.875rem; color: var(--cl-ink);
  cursor: pointer; white-space: nowrap;
}
.phone-picker--embedded .phone-picker-btn {
  border: none; border-radius: 0;
  min-width: 84px;
}
.phone-picker-btn:hover { background: var(--cl-paper); }
.phone-picker--embedded .phone-picker-btn:hover { background: color-mix(in srgb, var(--cl-paper) 60%, var(--cl-tint)); }
.phone-picker-flag { font-size: 1.05rem; line-height: 1; }
.phone-picker-code { font-variant-numeric: tabular-nums; }
.phone-picker-caret { font-size: 0.75rem; opacity: 0.55; margin-inline-start: 2px; }
.phone-picker-dropdown {
  position: absolute; top: calc(100% + 4px); inset-inline-start: 0; z-index: 200;
  background: var(--cl-white);
  border: 1px solid var(--cl-border); border-radius: 8px;
  min-width: 280px; max-width: 380px;
  padding: 8px;
  box-shadow: 0 8px 28px var(--cl-shadow);
}
.phone-picker-search {
  width: 100%; box-sizing: border-box;
  padding: 7px 10px; font-size: 13px;
  border: 1px solid var(--cl-border); border-radius: 6px;
  color: var(--cl-ink); background: var(--cl-white); margin-bottom: 6px;
}
.phone-picker-search:focus { outline: none; border-color: var(--cl-accent); box-shadow: 0 0 0 var(--cl-focus-ring-width) var(--cl-focus-ring); }
.phone-picker-list { max-height: 280px; overflow-y: auto; }
.phone-picker-option {
  display: grid; grid-template-columns: 22px 1fr auto;
  align-items: center; gap: 8px;
  width: 100%;
  padding: 7px 10px;
  background: transparent; border: none; border-radius: 5px;
  text-align: start; font-size: 13px; color: var(--cl-ink);
  cursor: pointer;
}
.phone-picker-option:hover,
.phone-picker-option.is-active { background: var(--cl-paper); }
.phone-picker-option.is-selected { background: color-mix(in srgb, var(--cl-accent) 14%, transparent); }
.phone-picker-option-flag { font-size: 1.05rem; line-height: 1; }
.phone-picker-option-name { color: var(--cl-ink); }
.phone-picker-option-dial { color: var(--cl-muted); font-variant-numeric: tabular-nums; }
.phone-picker-option.is-hidden { display: none; }

/* ── Indeterminate "preparing" progress overlay (2026-06-10) ──────────────
   A fixed bottom-centre card with a spinner + animated bar, for multi-second
   operations that have NO measurable byte/percentage progress — e.g. a
   server-side file build (the Translation Manager all-languages .xlsx export
   is the first user). The bar animates on its own; show/hide by toggling the
   .is-visible class. Self-contained (own spinner + keyframes) so it can be
   dropped into any page that loads this file.
   Markup:
     <div class="cl-prep-overlay" role="status" aria-live="polite">
       <div class="cl-prep-overlay__row">
         <span class="cl-prep-overlay__spinner"></span>
         <span class="js-label">Preparing…</span>
       </div>
       <div class="cl-prep-bar"><span></span></div>
     </div>
   JS: el.classList.add('is-visible') / .remove('is-visible'). */
@keyframes cl-prep-indeterminate { 0% { left: -45%; } 100% { left: 100%; } }
@keyframes cl-prep-spin { to { transform: rotate(360deg); } }
.cl-prep-overlay {
  position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%);
  z-index: 10000; min-width: 300px; max-width: 90vw;
  background: var(--cl-surface); color: var(--cl-on-surface);
  padding: 0.85rem 1.25rem; border-radius: var(--cl-radius-card);
  box-shadow: var(--cl-shadow-lg); display: none;
}
.cl-prep-overlay.is-visible { display: block; }
.cl-prep-overlay__row {
  display: flex; align-items: center; gap: 0.6rem;
  font-size: 0.875rem; margin-bottom: 0.6rem;
}
.cl-prep-overlay__spinner {
  display: inline-block; width: 12px; height: 12px; flex: none;
  border: 2px solid rgba(var(--cl-on-surface-rgb), 0.25); border-top-color: var(--cl-accent);
  border-radius: 50%; animation: cl-prep-spin 0.8s linear infinite;
}
.cl-prep-bar {
  position: relative; height: 4px; border-radius: 2px; overflow: hidden;
  background: rgba(var(--cl-on-surface-rgb), 0.18);
}
.cl-prep-bar > span {
  position: absolute; top: 0; height: 100%; width: 45%; border-radius: 2px;
  background: var(--cl-accent); animation: cl-prep-indeterminate 1.1s ease-in-out infinite;
}

/* ── Row actions dropdown (registration lists) ─────────────────── */
/* The cell the row menu sits in. It was a class SIX templates asked for and no
   stylesheet defined, so each one hand-added `style="text-align:center"` — or
   forgot to, which is why the beneficiaries lists sat left of the programme and
   activity lists. Defining it is what makes the menu column line up across the
   platform without every list restating how. */
.cl-row-actions-cell{width:1%;white-space:nowrap;text-align:center;}
.cl-row-actions{position:relative;display:inline-block;}
.cl-actions-btn{background:none;border:none;cursor:pointer;font-size:var(--cl-fs-h2);color:var(--cl-ink);padding:4px 8px;border-radius:4px;line-height:1;}
.cl-actions-btn:hover{background:var(--cl-paper);}
/* Positioned FIXED, not absolute, and placed by cl_menu.js against the
   trigger's viewport rect. Every kebab in the platform renders inside a
   `.table-wrap` (overflow-x:auto), and an absolutely-positioned menu is
   CLIPPED by that scroller — it appeared as a tiny scrollable box pinned to
   the table's edge instead of a menu under the button. `fixed` escapes the
   scroller; no ancestor of a kebab declares transform/filter/contain, which
   are the only things that would re-trap it. top/left are placeholders: the
   menu is `hidden` until the script unhides it, and the script always sets
   both first, so there is no state in which these values are shown.
   z-index clears the two shells' sticky headers and mobile drawer (1000/1001);
   a drawer click is an outside click, so a menu can never be open beneath it. */
.cl-actions-dropdown{width:max-content;max-width:min(20rem,calc(100vw - 1rem));min-width:140px;padding:4px 0;}
.cl-actions-dropdown a,.cl-actions-dropdown button{display:block;width:100%;padding:8px 16px;text-align:start;background:none;border:none;color:var(--cl-ink);text-decoration:none;cursor:pointer;font-size:.875rem;box-sizing:border-box;}
.cl-actions-dropdown a:hover,.cl-actions-dropdown button:hover,.cl-actions-dropdown a:focus-visible,.cl-actions-dropdown button:focus-visible{background:var(--cl-paper);}
.cl-actions-delete{color:var(--cl-danger);}

/* ── The ONE pop-up menu (static/js/cl_menu.js, docs/LYNKVIEW.md §F) ─────
   Every panel is FIXED and placed by the script against the viewport; where
   the browser has the popover API it is also shown in the TOP LAYER, which no
   ancestor's overflow, transform, table or card can clip. `inset:auto` and
   `margin:0` undo the UA's centred-popover defaults (`inset:0; margin:auto`);
   top/left are placeholders the script always writes before revealing it.
   The look (`.cl-menu__panel`) is shared so a kebab, the ⚙ menu, the column
   picker and the search panel read as one component. z-index clears the two
   shells' sticky headers and drawer (1000/1001) for the no-popover fallback. */
[data-cl-menu-panel]{overflow:auto;box-sizing:border-box;max-width:calc(100vw - 16px);color:var(--cl-ink);}
.cl-menu-js [data-cl-menu-panel],.cl-actions-dropdown{position:fixed;inset:auto;top:0;left:0;margin:0;z-index:1200;}
[data-cl-menu-panel][hidden]{display:none;}
/* Build 6: an ITEM marked hidden inside any menu panel is never drawn — an
   item rule's own display (.cl-actions-dropdown button{display:block}, the
   user menu's display:flex) beat the attribute, so the web user menu showed
   the app-only "Switch workspace". One rule for every panel. */
[data-cl-menu-panel] [hidden]{display:none !important;}
details.cl-menu>summary{list-style:none;cursor:pointer;}
details.cl-menu>summary::-webkit-details-marker{display:none;}
html:not(.cl-menu-js) details.cl-menu[open]>[data-cl-menu-panel]{margin-block-start:4px;}
.cl-actions-dropdown,.cl-menu__panel{background:var(--cl-white);border:1px solid var(--cl-border);border-radius:var(--cl-radius-md);box-shadow:var(--cl-shadow-md);}
.cl-menu__panel{min-width:200px;padding:6px;}
.cl-menu__item{display:flex;align-items:center;gap:8px;width:100%;min-height:40px;padding:0 12px;border:0;background:none;border-radius:var(--cl-radius-sm);color:var(--cl-ink);text-decoration:none;text-align:start;font:inherit;font-size:var(--cl-fs-body);cursor:pointer;box-sizing:border-box;}
.cl-menu__item:hover,.cl-menu__item:focus-visible{background:var(--cl-paper);}
.cl-menu__item[aria-current=page],.cl-menu__item.is-active{font-weight:var(--cl-fw-semibold);}
.cl-menu__item--danger{color:var(--cl-danger);}
.cl-menu__divider{height:0;margin:6px 4px;border:0;border-block-start:1px solid var(--cl-border);}
.cl-menu__heading{margin:8px 12px 4px;font-size:var(--cl-fs-small);font-weight:var(--cl-fw-semibold);color:var(--cl-muted);}
[data-cl-menu-panel] :focus-visible{outline:var(--cl-focus-ring-width) solid var(--cl-focus-ring);outline-offset:-2px;}
.cl-menu-js [data-cl-menu-panel].is-sheet{inset:0;width:auto;height:auto;max-width:none;max-height:none;border-radius:0;border:0;}
@media (pointer:coarse){.cl-menu__item,[data-cl-menu-panel] [role^=menuitem]{min-height:44px;}}
tr[data-href]{cursor:pointer;}

/* ── Directional glyphs ───────────────────────────────────────────────────
   `←` `→` `↩` in a back link, a pagination control, a wizard nav or a
   forward CTA carry DIRECTION, not decoration. Flex rows and logical
   properties already swap sides under `dir=rtl`, but the arrowhead keeps
   pointing the way it was drawn — so on an Arabic tenant "next" reads as
   pointing backwards. Mirroring the glyph is the whole fix.

   This lives HERE rather than in commonlynk.components.css because it has to
   reach every shell: `external_base.html` — the anonymous public form-fill
   page, and so the single most likely place for an Arabic reader to meet a
   wizard arrow — loads the tokens sheet and NOT the components sheet.

   `.arrow` is a marker class carried only by these glyph spans; it is
   deliberately unscoped so one rule serves every surface. An arrow that is
   genuinely NOT directional (a `from → to` transition, a breadcrumb
   separator, an arrow baked into a msgid) must not carry it. */
[dir="rtl"] .arrow { display: inline-block; transform: scaleX(-1); }
[dir="rtl"] { --cl-shadow-pin-start: -6px 0 6px -4px var(--cl-shadow); --cl-shadow-pin-end: 6px 0 6px -4px var(--cl-shadow); }

/* ── Visible focus, everywhere (REM-696, §4j rule 2, WCAG 2.4.7 / 2.4.11) ──
   The fallback ring for every focusable control that does not draw its own:
   `:where()` keeps it at zero specificity, so a component's own ring (a
   box-shadow on .cl-btn, .cl-input…) still wins, and only a control that drew
   NOTHING gets this one. The ink ring is ≥3:1 on white and on paper.
   `scroll-margin` keeps a focused control clear of the sticky top bar when
   the browser scrolls it into view, so focus is never hidden under it. */
:where(a[href], button, input:not([type=hidden]), select, textarea, summary, [tabindex]:not([tabindex="-1"])):focus-visible {
  outline: var(--cl-focus-ring-width) solid var(--cl-focus-ring);
  outline-offset: 2px;
}
/* Dark surfaces (the Rail, a navy band): the same token, in white. */
.sidebar, [data-cl-dark], .cl-on-navy { --cl-focus-ring: var(--cl-on-surface); }
:where(a[href], button, input, select, textarea, summary, [tabindex]) { scroll-margin-block: 88px 24px; }
/* …and the SCROLLERS keep a focused control clear of what sticks to them: the
   shell's top bar, and a sticky footer such as the form designer's "Add
   question" button, which covered the focused question near the bottom of the
   viewport (measured by the ui_conformance Tab walk, 2026-10-16). Focus
   scrolling honours scroll-padding; `.content` is the tenant shell's scroller. */
html, .content { scroll-padding-block: 72px 96px; }
.phone-input-group:focus-within { box-shadow: 0 0 0 var(--cl-focus-ring-width) var(--cl-focus-ring); }

/* An EMPTY value (REM-713, core/display.py): the word "N/A" (Arabic «غير محدد»),
   muted so it never reads as data. Never the "—" em dash. */
.cl-na { color: var(--cl-muted); }
